blob: 784283ef9762e467ae53c92fac4fe2e3842fd847 [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{
Bram Moolenaareb6880b2020-07-12 17:07:05 +020025 // Do not go up the stack, a ":function" inside vim9script uses legacy
26 // syntax. "sc_version" is also set when compiling a ":def" function in
27 // legacy script.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010028 return current_sctx.sc_version == SCRIPT_VERSION_VIM9;
29}
30
31/*
32 * ":vim9script".
33 */
34 void
35ex_vim9script(exarg_T *eap)
36{
Bram Moolenaar101f4812020-06-16 23:18:51 +020037 scriptitem_T *si;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010038
39 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
40 {
41 emsg(_("E1038: vim9script can only be used in a script"));
42 return;
43 }
Bram Moolenaar101f4812020-06-16 23:18:51 +020044 si = SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010045 if (si->sn_had_command)
46 {
47 emsg(_("E1039: vim9script must be the first command in a script"));
48 return;
49 }
50 current_sctx.sc_version = SCRIPT_VERSION_VIM9;
51 si->sn_version = SCRIPT_VERSION_VIM9;
52 si->sn_had_command = TRUE;
53
54 if (STRCMP(p_cpo, CPO_VIM) != 0)
55 {
56 si->sn_save_cpo = p_cpo;
57 p_cpo = vim_strsave((char_u *)CPO_VIM);
58 }
59}
60
61/*
62 * ":export let Name: type"
63 * ":export const Name: type"
64 * ":export def Name(..."
65 * ":export class Name ..."
66 *
67 * ":export {Name, ...}"
68 */
69 void
Bram Moolenaar09689a02020-05-09 22:50:08 +020070ex_export(exarg_T *eap)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010071{
Bram Moolenaareb6880b2020-07-12 17:07:05 +020072 if (!in_vim9script())
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010073 {
74 emsg(_(e_needs_vim9));
75 return;
76 }
77
78 eap->cmd = eap->arg;
79 (void)find_ex_command(eap, NULL, lookup_scriptvar, NULL);
80 switch (eap->cmdidx)
81 {
82 case CMD_let:
83 case CMD_const:
84 case CMD_def:
85 // case CMD_class:
86 is_export = TRUE;
87 do_cmdline(eap->cmd, eap->getline, eap->cookie,
88 DOCMD_VERBOSE + DOCMD_NOWAIT);
89
90 // The command will reset "is_export" when exporting an item.
91 if (is_export)
92 {
93 emsg(_("E1044: export with invalid argument"));
94 is_export = FALSE;
95 }
96 break;
97 default:
98 emsg(_("E1043: Invalid command after :export"));
99 break;
100 }
101}
102
103/*
104 * Add a new imported item entry to the current script.
105 */
106 static imported_T *
107new_imported(garray_T *gap)
108{
109 if (ga_grow(gap, 1) == OK)
110 return ((imported_T *)gap->ga_data + gap->ga_len++);
111 return NULL;
112}
113
114/*
115 * Free all imported items in script "sid".
116 */
117 void
118free_imports(int sid)
119{
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100120 scriptitem_T *si = SCRIPT_ITEM(sid);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100121 int idx;
122
123 for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
124 {
Bram Moolenaar20431c92020-03-20 18:39:46 +0100125 imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100126
127 vim_free(imp->imp_name);
128 }
129 ga_clear(&si->sn_imports);
Bram Moolenaar20431c92020-03-20 18:39:46 +0100130 ga_clear(&si->sn_var_vals);
Bram Moolenaar6110e792020-07-08 19:35:21 +0200131 clear_type_list(&si->sn_type_list);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100132}
133
134/*
135 * ":import Item from 'filename'"
136 * ":import Item as Alias from 'filename'"
137 * ":import {Item} from 'filename'".
138 * ":import {Item as Alias} from 'filename'"
139 * ":import {Item, Item} from 'filename'"
140 * ":import {Item, Item as Alias} from 'filename'"
141 *
142 * ":import * as Name from 'filename'"
143 */
144 void
145ex_import(exarg_T *eap)
146{
Bram Moolenaar1c991142020-07-04 13:15:31 +0200147 char_u *cmd_end;
148 evalarg_T evalarg;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100149
Bram Moolenaar101f4812020-06-16 23:18:51 +0200150 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
151 {
152 emsg(_("E1094: import can only be used in a script"));
153 return;
154 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200155 fill_evalarg_from_eap(&evalarg, eap, eap->skip);
Bram Moolenaar101f4812020-06-16 23:18:51 +0200156
Bram Moolenaar1c991142020-07-04 13:15:31 +0200157 cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid,
158 &evalarg, NULL);
Bram Moolenaar9721fb42020-06-11 23:10:46 +0200159 if (cmd_end != NULL)
160 eap->nextcmd = check_nextcmd(cmd_end);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200161 clear_evalarg(&evalarg, eap);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100162}
163
164/*
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100165 * Find an exported item in "sid" matching the name at "*argp".
166 * When it is a variable return the index.
167 * When it is a user function return "*ufunc".
168 * When not found returns -1 and "*ufunc" is NULL.
169 */
170 int
171find_exported(
172 int sid,
Bram Moolenaar1c991142020-07-04 13:15:31 +0200173 char_u *name,
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100174 ufunc_T **ufunc,
175 type_T **type)
176{
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100177 int idx = -1;
178 svar_T *sv;
179 scriptitem_T *script = SCRIPT_ITEM(sid);
180
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100181 // find name in "script"
182 // TODO: also find script-local user function
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100183 idx = get_script_item_idx(sid, name, FALSE);
184 if (idx >= 0)
185 {
186 sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
187 if (!sv->sv_export)
188 {
189 semsg(_("E1049: Item not exported in script: %s"), name);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100190 return -1;
191 }
192 *type = sv->sv_type;
193 *ufunc = NULL;
194 }
195 else
196 {
197 char_u buffer[200];
198 char_u *funcname;
199
200 // it could be a user function.
Bram Moolenaar5a67c372020-07-23 14:39:47 +0200201 if (STRLEN(name) < sizeof(buffer) - 15)
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100202 funcname = buffer;
203 else
204 {
Bram Moolenaar5a67c372020-07-23 14:39:47 +0200205 funcname = alloc(STRLEN(name) + 15);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100206 if (funcname == NULL)
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100207 return -1;
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100208 }
209 funcname[0] = K_SPECIAL;
210 funcname[1] = KS_EXTRA;
211 funcname[2] = (int)KE_SNR;
212 sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name);
Bram Moolenaar4c17ad92020-04-27 22:47:51 +0200213 *ufunc = find_func(funcname, FALSE, NULL);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100214 if (funcname != buffer)
215 vim_free(funcname);
216
217 if (*ufunc == NULL)
218 {
219 semsg(_("E1048: Item not found in script: %s"), name);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100220 return -1;
221 }
222 }
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100223
224 return idx;
225}
226
227/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100228 * Handle an ":import" command and add the resulting imported_T to "gap", when
229 * not NULL, or script "import_sid" sn_imports.
230 * Returns a pointer to after the command or NULL in case of failure
231 */
232 char_u *
Bram Moolenaar1c991142020-07-04 13:15:31 +0200233handle_import(
234 char_u *arg_start,
235 garray_T *gap,
236 int import_sid,
237 evalarg_T *evalarg,
238 void *cctx)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100239{
240 char_u *arg = arg_start;
Bram Moolenaar1c991142020-07-04 13:15:31 +0200241 char_u *cmd_end = NULL;
242 char_u *as_name = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100243 int ret = FAIL;
244 typval_T tv;
245 int sid = -1;
246 int res;
Bram Moolenaar1c991142020-07-04 13:15:31 +0200247 garray_T names;
248 static char e_import_syntax[] = N_("E1047: syntax error in import");
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100249
Bram Moolenaar1c991142020-07-04 13:15:31 +0200250 ga_init2(&names, sizeof(char_u *), 10);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100251 if (*arg == '{')
252 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200253 // "import {item, item} from ..."
254 arg = skipwhite_and_linebreak(arg + 1, evalarg);
255 for (;;)
256 {
257 char_u *p = arg;
258 int had_comma = FALSE;
259
260 while (eval_isnamec(*arg))
261 ++arg;
262 if (p == arg)
263 break;
264 if (ga_grow(&names, 1) == FAIL)
265 goto erret;
266 ((char_u **)names.ga_data)[names.ga_len] =
267 vim_strnsave(p, arg - p);
268 ++names.ga_len;
269 if (*arg == ',')
270 {
271 had_comma = TRUE;
272 ++arg;
273 }
274 arg = skipwhite_and_linebreak(arg, evalarg);
275 if (*arg == '}')
276 {
277 arg = skipwhite_and_linebreak(arg + 1, evalarg);
278 break;
279 }
280 if (!had_comma)
281 {
282 emsg(_("E1046: Missing comma in import"));
283 goto erret;
284 }
285 }
286 if (names.ga_len == 0)
287 {
288 emsg(_(e_import_syntax));
289 goto erret;
290 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100291 }
292 else
293 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200294 // "import Name from ..."
295 // "import * as Name from ..."
296 // "import item [as Name] from ..."
297 arg = skipwhite_and_linebreak(arg, evalarg);
298 if (arg[0] == '*' && IS_WHITE_OR_NUL(arg[1]))
299 arg = skipwhite_and_linebreak(arg + 1, evalarg);
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100300 else if (eval_isnamec1(*arg))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100301 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200302 char_u *p = arg;
303
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100304 while (eval_isnamec(*arg))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100305 ++arg;
Bram Moolenaar1c991142020-07-04 13:15:31 +0200306 if (ga_grow(&names, 1) == FAIL)
307 goto erret;
308 ((char_u **)names.ga_data)[names.ga_len] =
309 vim_strnsave(p, arg - p);
310 ++names.ga_len;
311 arg = skipwhite_and_linebreak(arg, evalarg);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100312 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200313 else
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100314 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200315 emsg(_(e_import_syntax));
316 goto erret;
317 }
318
319 if (STRNCMP("as", arg, 2) == 0 && IS_WHITE_OR_NUL(arg[2]))
320 {
321 char_u *p;
322
323 // skip over "as Name "; no line break allowed after "as"
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100324 arg = skipwhite(arg + 2);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200325 p = arg;
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100326 if (eval_isnamec1(*arg))
327 while (eval_isnamec(*arg))
328 ++arg;
Bram Moolenaarcbb6bdc2020-07-06 21:53:17 +0200329 if (check_defined(p, arg - p, cctx) == FAIL)
Bram Moolenaar1c991142020-07-04 13:15:31 +0200330 goto erret;
331 as_name = vim_strnsave(p, arg - p);
332 arg = skipwhite_and_linebreak(arg, evalarg);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100333 }
334 else if (*arg_start == '*')
335 {
336 emsg(_("E1045: Missing \"as\" after *"));
Bram Moolenaar1c991142020-07-04 13:15:31 +0200337 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100338 }
339 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200340
341 if (STRNCMP("from", arg, 4) != 0 || !IS_WHITE_OR_NUL(arg[4]))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100342 {
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100343 emsg(_("E1070: Missing \"from\""));
Bram Moolenaar1c991142020-07-04 13:15:31 +0200344 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100345 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200346
Bram Moolenaar962d7212020-07-04 14:15:00 +0200347 arg = skipwhite_and_linebreak(arg + 4, evalarg);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100348 tv.v_type = VAR_UNKNOWN;
349 // TODO: should we accept any expression?
350 if (*arg == '\'')
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +0200351 ret = eval_lit_string(&arg, &tv, TRUE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100352 else if (*arg == '"')
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +0200353 ret = eval_string(&arg, &tv, TRUE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100354 if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
355 {
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100356 emsg(_("E1071: Invalid string after \"from\""));
Bram Moolenaar1c991142020-07-04 13:15:31 +0200357 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100358 }
359 cmd_end = arg;
360
Bram Moolenaar1c991142020-07-04 13:15:31 +0200361 /*
362 * find script file
363 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100364 if (*tv.vval.v_string == '.')
365 {
366 size_t len;
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100367 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100368 char_u *tail = gettail(si->sn_name);
369 char_u *from_name;
370
371 // Relative to current script: "./name.vim", "../../name.vim".
372 len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2;
373 from_name = alloc((int)len);
374 if (from_name == NULL)
375 {
376 clear_tv(&tv);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200377 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100378 }
379 vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
380 add_pathsep(from_name);
381 STRCAT(from_name, tv.vval.v_string);
382 simplify_filename(from_name);
383
384 res = do_source(from_name, FALSE, DOSO_NONE, &sid);
385 vim_free(from_name);
386 }
387 else if (mch_isFullName(tv.vval.v_string))
388 {
389 // Absolute path: "/tmp/name.vim"
390 res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid);
391 }
392 else
393 {
394 size_t len = 7 + STRLEN(tv.vval.v_string) + 1;
395 char_u *from_name;
396
397 // Find file in "import" subdirs in 'runtimepath'.
398 from_name = alloc((int)len);
399 if (from_name == NULL)
400 {
401 clear_tv(&tv);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200402 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100403 }
404 vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
405 res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
406 vim_free(from_name);
407 }
408
409 if (res == FAIL || sid <= 0)
410 {
411 semsg(_("E1053: Could not import \"%s\""), tv.vval.v_string);
412 clear_tv(&tv);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200413 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100414 }
415 clear_tv(&tv);
416
417 if (*arg_start == '*')
418 {
419 imported_T *imported = new_imported(gap != NULL ? gap
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100420 : &SCRIPT_ITEM(import_sid)->sn_imports);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100421
422 if (imported == NULL)
Bram Moolenaar1c991142020-07-04 13:15:31 +0200423 goto erret;
424 imported->imp_name = as_name;
425 as_name = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100426 imported->imp_sid = sid;
427 imported->imp_all = TRUE;
428 }
429 else
430 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200431 int i;
432
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100433 arg = arg_start;
434 if (*arg == '{')
435 arg = skipwhite(arg + 1);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200436 for (i = 0; i < names.ga_len; ++i)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100437 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200438 char_u *name = ((char_u **)names.ga_data)[i];
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100439 int idx;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100440 imported_T *imported;
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100441 ufunc_T *ufunc = NULL;
442 type_T *type;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100443
Bram Moolenaar1c991142020-07-04 13:15:31 +0200444 idx = find_exported(sid, name, &ufunc, &type);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100445
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100446 if (idx < 0 && ufunc == NULL)
Bram Moolenaar1c991142020-07-04 13:15:31 +0200447 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100448
Bram Moolenaar1c991142020-07-04 13:15:31 +0200449 if (check_defined(name, STRLEN(name), cctx) == FAIL)
450 goto erret;
Bram Moolenaar5269bd22020-03-09 19:25:27 +0100451
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100452 imported = new_imported(gap != NULL ? gap
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100453 : &SCRIPT_ITEM(import_sid)->sn_imports);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100454 if (imported == NULL)
Bram Moolenaar1c991142020-07-04 13:15:31 +0200455 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100456
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100457 // TODO: check for "as" following
Bram Moolenaar1c991142020-07-04 13:15:31 +0200458 // imported->imp_name = vim_strsave(as_name);
459 imported->imp_name = name;
460 ((char_u **)names.ga_data)[i] = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100461 imported->imp_sid = sid;
462 if (idx >= 0)
463 {
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100464 imported->imp_type = type;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100465 imported->imp_var_vals_idx = idx;
466 }
467 else
Bram Moolenaar40f4f7a2020-07-23 22:41:43 +0200468 {
469 imported->imp_type = ufunc->uf_func_type;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100470 imported->imp_funcname = ufunc->uf_name;
Bram Moolenaar40f4f7a2020-07-23 22:41:43 +0200471 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100472 }
473 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200474erret:
475 ga_clear_strings(&names);
476 vim_free(as_name);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100477 return cmd_end;
478}
479
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200480/*
481 * Declare a script-local variable without init: "let var: type".
482 * "const" is an error since the value is missing.
483 * Returns a pointer to after the type.
484 */
485 char_u *
486vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
487{
488 char_u *p;
489 char_u *name;
490 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
491 type_T *type;
492 int called_emsg_before = called_emsg;
493 typval_T init_tv;
494
495 if (eap->cmdidx == CMD_const)
496 {
497 emsg(_(e_const_req_value));
498 return arg + STRLEN(arg);
499 }
500
501 // Check for valid starting character.
502 if (!eval_isnamec1(*arg))
503 {
504 semsg(_(e_invarg2), arg);
505 return arg + STRLEN(arg);
506 }
507
Bram Moolenaar984dddb2020-06-14 12:50:24 +0200508 for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p))
Bram Moolenaar3b74b6b2020-06-19 19:01:43 +0200509 if (*p == ':' && (VIM_ISWHITE(p[1]) || p != arg + 1))
Bram Moolenaar984dddb2020-06-14 12:50:24 +0200510 break;
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200511
512 if (*p != ':')
513 {
514 emsg(_(e_type_req));
515 return arg + STRLEN(arg);
516 }
Bram Moolenaar984dddb2020-06-14 12:50:24 +0200517 if (!VIM_ISWHITE(p[1]))
518 {
519 semsg(_(e_white_after), ":");
520 return arg + STRLEN(arg);
521 }
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200522 name = vim_strnsave(arg, p - arg);
523
524 // parse type
525 p = skipwhite(p + 1);
526 type = parse_type(&p, &si->sn_type_list);
527 if (called_emsg != called_emsg_before)
Bram Moolenaarf3decc52020-06-13 19:56:38 +0200528 {
529 vim_free(name);
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200530 return p;
Bram Moolenaarf3decc52020-06-13 19:56:38 +0200531 }
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200532
533 // Create the variable with 0/NULL value.
534 CLEAR_FIELD(init_tv);
535 init_tv.v_type = type->tt_type;
536 set_var_const(name, type, &init_tv, FALSE, 0);
537
538 vim_free(name);
539 return p;
540}
541
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200542/*
543 * Check if the type of script variable "dest" allows assigning "value".
544 */
Bram Moolenaarc785b9a2020-06-19 18:34:15 +0200545 int
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200546check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
547{
548 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
549 int idx;
550
551 // Find the svar_T in sn_var_vals.
552 for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
553 {
554 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
555
556 if (sv->sv_tv == dest)
557 {
558 if (sv->sv_const)
Bram Moolenaarc785b9a2020-06-19 18:34:15 +0200559 {
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200560 semsg(_(e_readonlyvar), name);
Bram Moolenaarc785b9a2020-06-19 18:34:15 +0200561 return FAIL;
562 }
Bram Moolenaar4cdb13c2020-07-22 21:45:14 +0200563 return check_typval_type(sv->sv_type, value);
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200564 }
565 }
566 iemsg("check_script_var_type(): not found");
Bram Moolenaarc785b9a2020-06-19 18:34:15 +0200567 return OK; // not really
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200568}
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200569
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100570#endif // FEAT_EVAL