1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2071d4279SBram Moolenaar *
3071d4279SBram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
4071d4279SBram Moolenaar *
5071d4279SBram Moolenaar * Do ":help uganda" in Vim to read copying and usage conditions.
6071d4279SBram Moolenaar * Do ":help credits" in Vim to see a list of people who contributed.
7071d4279SBram Moolenaar * See README.txt for an overview of the Vim source code.
8071d4279SBram Moolenaar */
9071d4279SBram Moolenaar
10071d4279SBram Moolenaar /*
11071d4279SBram Moolenaar * eval.c: Expression evaluation.
12071d4279SBram Moolenaar */
13fefecb0fSBram Moolenaar #define USING_FLOAT_STUFF
14071d4279SBram Moolenaar
15071d4279SBram Moolenaar #include "vim.h"
16071d4279SBram Moolenaar
178c8de839SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
188c8de839SBram Moolenaar
19314f11d4SBram Moolenaar #ifdef VMS
20314f11d4SBram Moolenaar # include <float.h>
21314f11d4SBram Moolenaar #endif
22314f11d4SBram Moolenaar
239bbf63dbSBram Moolenaar #define NAMESPACE_CHAR (char_u *)"abglstvw"
249bbf63dbSBram Moolenaar
25532c780eSBram Moolenaar /*
26d9fba318SBram Moolenaar * When recursively copying lists and dicts we need to remember which ones we
27d9fba318SBram Moolenaar * have done to avoid endless recursiveness. This unique ID is used for that.
28c0a6fac5SBram Moolenaar * The last bit is used for previous_funccal, ignored when comparing.
29d9fba318SBram Moolenaar */
30d9fba318SBram Moolenaar static int current_copyID = 0;
318502c704SBram Moolenaar
32071d4279SBram Moolenaar /*
333d60ec2aSBram Moolenaar * Info used by a ":for" loop.
343d60ec2aSBram Moolenaar */
3533570924SBram Moolenaar typedef struct
363d60ec2aSBram Moolenaar {
375d18efecSBram Moolenaar int fi_semicolon; // TRUE if ending in '; var]'
385d18efecSBram Moolenaar int fi_varcount; // nr of variables in the list
39b7a78f7aSBram Moolenaar int fi_break_count; // nr of line breaks encountered
405d18efecSBram Moolenaar listwatch_T fi_lw; // keep an eye on the item used.
415d18efecSBram Moolenaar list_T *fi_list; // list being used
425d18efecSBram Moolenaar int fi_bi; // index of blob
435d18efecSBram Moolenaar blob_T *fi_blob; // blob being used
4474e54fcbSBram Moolenaar char_u *fi_string; // copy of string being used
4574e54fcbSBram Moolenaar int fi_byte_idx; // byte index in fi_string
4633570924SBram Moolenaar } forinfo_T;
473d60ec2aSBram Moolenaar
485409f5d8SBram Moolenaar static int eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
495409f5d8SBram Moolenaar static int eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
505409f5d8SBram Moolenaar static int eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
515409f5d8SBram Moolenaar static int eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
525409f5d8SBram Moolenaar static int eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
53459fbdbfSBram Moolenaar static int eval7t(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
545409f5d8SBram Moolenaar static int eval7(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
550b1cd52fSBram Moolenaar static int eval7_leader(typval_T *rettv, int numeric_only, char_u *start_leader, char_u **end_leaderp);
56a40058acSBram Moolenaar
5748e697e4SBram Moolenaar static int free_unref_items(int copyID);
5848e697e4SBram Moolenaar static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
59a2438132SYegappan Lakshmanan static char_u *eval_next_line(evalarg_T *evalarg);
602c704a77SBram Moolenaar
61e21c1580SBram Moolenaar /*
62e21c1580SBram Moolenaar * Return "n1" divided by "n2", taking care of dividing by zero.
63c5f59fabSBram Moolenaar * If "failed" is not NULL set it to TRUE when dividing by zero fails.
64e21c1580SBram Moolenaar */
650522ba03SBram Moolenaar varnumber_T
num_divide(varnumber_T n1,varnumber_T n2,int * failed)66c5f59fabSBram Moolenaar num_divide(varnumber_T n1, varnumber_T n2, int *failed)
67e21c1580SBram Moolenaar {
68e21c1580SBram Moolenaar varnumber_T result;
69e21c1580SBram Moolenaar
7099880f96SBram Moolenaar if (n2 == 0)
71e21c1580SBram Moolenaar {
7299880f96SBram Moolenaar if (in_vim9script())
73c5f59fabSBram Moolenaar {
7499880f96SBram Moolenaar emsg(_(e_divide_by_zero));
75c5f59fabSBram Moolenaar if (failed != NULL)
76c5f59fabSBram Moolenaar *failed = TRUE;
77c5f59fabSBram Moolenaar }
78e21c1580SBram Moolenaar if (n1 == 0)
79e21c1580SBram Moolenaar result = VARNUM_MIN; // similar to NaN
80e21c1580SBram Moolenaar else if (n1 < 0)
81e21c1580SBram Moolenaar result = -VARNUM_MAX;
82e21c1580SBram Moolenaar else
83e21c1580SBram Moolenaar result = VARNUM_MAX;
84e21c1580SBram Moolenaar }
85e21c1580SBram Moolenaar else
86e21c1580SBram Moolenaar result = n1 / n2;
87e21c1580SBram Moolenaar
88e21c1580SBram Moolenaar return result;
89e21c1580SBram Moolenaar }
90e21c1580SBram Moolenaar
91e21c1580SBram Moolenaar /*
92e21c1580SBram Moolenaar * Return "n1" modulus "n2", taking care of dividing by zero.
93c5f59fabSBram Moolenaar * If "failed" is not NULL set it to TRUE when dividing by zero fails.
94e21c1580SBram Moolenaar */
950522ba03SBram Moolenaar varnumber_T
num_modulus(varnumber_T n1,varnumber_T n2,int * failed)96c5f59fabSBram Moolenaar num_modulus(varnumber_T n1, varnumber_T n2, int *failed)
97e21c1580SBram Moolenaar {
9899880f96SBram Moolenaar if (n2 == 0 && in_vim9script())
99c5f59fabSBram Moolenaar {
10099880f96SBram Moolenaar emsg(_(e_divide_by_zero));
101c5f59fabSBram Moolenaar if (failed != NULL)
102c5f59fabSBram Moolenaar *failed = TRUE;
103c5f59fabSBram Moolenaar }
104e21c1580SBram Moolenaar return (n2 == 0) ? 0 : (n1 % n2);
105e21c1580SBram Moolenaar }
106e21c1580SBram Moolenaar
10733570924SBram Moolenaar /*
10833570924SBram Moolenaar * Initialize the global and v: variables.
109a7043832SBram Moolenaar */
110a7043832SBram Moolenaar void
eval_init(void)1117454a06eSBram Moolenaar eval_init(void)
112a7043832SBram Moolenaar {
113e5cdf153SBram Moolenaar evalvars_init();
114a9b579f3SBram Moolenaar func_init();
11533570924SBram Moolenaar
1162c704a77SBram Moolenaar #ifdef EBCDIC
1172c704a77SBram Moolenaar /*
118195ea0ffSBram Moolenaar * Sort the function table, to enable binary search.
1192c704a77SBram Moolenaar */
1202c704a77SBram Moolenaar sortFunctions();
1212c704a77SBram Moolenaar #endif
122a7043832SBram Moolenaar }
123a7043832SBram Moolenaar
12429a1c1d3SBram Moolenaar #if defined(EXITFREE) || defined(PROTO)
12529a1c1d3SBram Moolenaar void
eval_clear(void)1267454a06eSBram Moolenaar eval_clear(void)
12729a1c1d3SBram Moolenaar {
128e5cdf153SBram Moolenaar evalvars_clear();
1297ebcba61SBram Moolenaar free_scriptnames(); // must come after evalvars_clear().
1309b486ca3SBram Moolenaar free_locales();
13129a1c1d3SBram Moolenaar
132da6c0334SBram Moolenaar // autoloaded script names
133da6c0334SBram Moolenaar free_autoload_scriptnames();
134aa35dd16SBram Moolenaar
13575ee544fSBram Moolenaar // unreferenced lists and dicts
13675ee544fSBram Moolenaar (void)garbage_collect(FALSE);
137c07f67adSBram Moolenaar
138c07f67adSBram Moolenaar // functions not garbage collected
139c07f67adSBram Moolenaar free_all_functions();
14029a1c1d3SBram Moolenaar }
14129a1c1d3SBram Moolenaar #endif
14229a1c1d3SBram Moolenaar
143e6b5324eSBram Moolenaar void
fill_evalarg_from_eap(evalarg_T * evalarg,exarg_T * eap,int skip)14437c83711SBram Moolenaar fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip)
14537c83711SBram Moolenaar {
146*844fb64aSBram Moolenaar init_evalarg(evalarg);
14737c83711SBram Moolenaar evalarg->eval_flags = skip ? 0 : EVAL_EVALUATE;
1482eb6fc3bSBram Moolenaar if (eap != NULL)
1492eb6fc3bSBram Moolenaar {
1502eb6fc3bSBram Moolenaar evalarg->eval_cstack = eap->cstack;
1512eb6fc3bSBram Moolenaar if (getline_equal(eap->getline, eap->cookie, getsourceline))
15237c83711SBram Moolenaar {
15337c83711SBram Moolenaar evalarg->eval_getline = eap->getline;
15437c83711SBram Moolenaar evalarg->eval_cookie = eap->cookie;
15537c83711SBram Moolenaar }
15637c83711SBram Moolenaar }
1572eb6fc3bSBram Moolenaar }
15837c83711SBram Moolenaar
159071d4279SBram Moolenaar /*
160071d4279SBram Moolenaar * Top level evaluation function, returning a boolean.
161071d4279SBram Moolenaar * Sets "error" to TRUE if there was an error.
162071d4279SBram Moolenaar * Return TRUE or FALSE.
163071d4279SBram Moolenaar */
164071d4279SBram Moolenaar int
eval_to_bool(char_u * arg,int * error,exarg_T * eap,int skip)1657454a06eSBram Moolenaar eval_to_bool(
1667454a06eSBram Moolenaar char_u *arg,
1677454a06eSBram Moolenaar int *error,
168b171fb17SBram Moolenaar exarg_T *eap,
1695d18efecSBram Moolenaar int skip) // only parse, don't execute
170071d4279SBram Moolenaar {
17133570924SBram Moolenaar typval_T tv;
17222fcfad2SBram Moolenaar varnumber_T retval = FALSE;
173faf8626bSBram Moolenaar evalarg_T evalarg;
174faf8626bSBram Moolenaar
17537c83711SBram Moolenaar fill_evalarg_from_eap(&evalarg, eap, skip);
176071d4279SBram Moolenaar
177071d4279SBram Moolenaar if (skip)
178071d4279SBram Moolenaar ++emsg_skip;
179faf8626bSBram Moolenaar if (eval0(arg, &tv, eap, &evalarg) == FAIL)
180071d4279SBram Moolenaar *error = TRUE;
181071d4279SBram Moolenaar else
182071d4279SBram Moolenaar {
183071d4279SBram Moolenaar *error = FALSE;
184071d4279SBram Moolenaar if (!skip)
185071d4279SBram Moolenaar {
1863e06a1e2SBram Moolenaar if (in_vim9script())
18713106605SBram Moolenaar retval = tv_get_bool_chk(&tv, error);
1883e06a1e2SBram Moolenaar else
189d155d7a8SBram Moolenaar retval = (tv_get_number_chk(&tv, error) != 0);
190c70646c6SBram Moolenaar clear_tv(&tv);
191071d4279SBram Moolenaar }
192071d4279SBram Moolenaar }
193071d4279SBram Moolenaar if (skip)
194071d4279SBram Moolenaar --emsg_skip;
195faf8626bSBram Moolenaar clear_evalarg(&evalarg, eap);
196071d4279SBram Moolenaar
19722fcfad2SBram Moolenaar return (int)retval;
198071d4279SBram Moolenaar }
199071d4279SBram Moolenaar
200ce9d50dfSBram Moolenaar /*
201ce9d50dfSBram Moolenaar * Call eval1() and give an error message if not done at a lower level.
202ce9d50dfSBram Moolenaar */
203ce9d50dfSBram Moolenaar static int
eval1_emsg(char_u ** arg,typval_T * rettv,exarg_T * eap)20447e880d6SBram Moolenaar eval1_emsg(char_u **arg, typval_T *rettv, exarg_T *eap)
205ce9d50dfSBram Moolenaar {
2066acc79f5SBram Moolenaar char_u *start = *arg;
207ce9d50dfSBram Moolenaar int ret;
208ce9d50dfSBram Moolenaar int did_emsg_before = did_emsg;
209ce9d50dfSBram Moolenaar int called_emsg_before = called_emsg;
21047e880d6SBram Moolenaar evalarg_T evalarg;
211ce9d50dfSBram Moolenaar
21247e880d6SBram Moolenaar fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip);
21347e880d6SBram Moolenaar
21447e880d6SBram Moolenaar ret = eval1(arg, rettv, &evalarg);
215ce9d50dfSBram Moolenaar if (ret == FAIL)
216ce9d50dfSBram Moolenaar {
217ce9d50dfSBram Moolenaar // Report the invalid expression unless the expression evaluation has
218ce9d50dfSBram Moolenaar // been cancelled due to an aborting error, an interrupt, or an
219ce9d50dfSBram Moolenaar // exception, or we already gave a more specific error.
220ce9d50dfSBram Moolenaar // Also check called_emsg for when using assert_fails().
221ce9d50dfSBram Moolenaar if (!aborting() && did_emsg == did_emsg_before
222ce9d50dfSBram Moolenaar && called_emsg == called_emsg_before)
223108010aaSBram Moolenaar semsg(_(e_invalid_expression_str), start);
224ce9d50dfSBram Moolenaar }
22547e880d6SBram Moolenaar clear_evalarg(&evalarg, eap);
226ce9d50dfSBram Moolenaar return ret;
227ce9d50dfSBram Moolenaar }
228ce9d50dfSBram Moolenaar
2298a7d6542SBram Moolenaar /*
230a9c01049SBram Moolenaar * Return whether a typval is a valid expression to pass to eval_expr_typval()
231a9c01049SBram Moolenaar * or eval_expr_to_bool(). An empty string returns FALSE;
232a9c01049SBram Moolenaar */
233a9c01049SBram Moolenaar int
eval_expr_valid_arg(typval_T * tv)234a9c01049SBram Moolenaar eval_expr_valid_arg(typval_T *tv)
235a9c01049SBram Moolenaar {
236a9c01049SBram Moolenaar return tv->v_type != VAR_UNKNOWN
237a9c01049SBram Moolenaar && (tv->v_type != VAR_STRING
238a9c01049SBram Moolenaar || (tv->vval.v_string != NULL && *tv->vval.v_string != NUL));
239a9c01049SBram Moolenaar }
240a9c01049SBram Moolenaar
241a9c01049SBram Moolenaar /*
2428a7d6542SBram Moolenaar * Evaluate an expression, which can be a function, partial or string.
2438a7d6542SBram Moolenaar * Pass arguments "argv[argc]".
2448a7d6542SBram Moolenaar * Return the result in "rettv" and OK or FAIL.
2458a7d6542SBram Moolenaar */
246543c9b19SBram Moolenaar int
eval_expr_typval(typval_T * expr,typval_T * argv,int argc,typval_T * rettv)24748570488SBram Moolenaar eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
24848570488SBram Moolenaar {
24948570488SBram Moolenaar char_u *s;
25048570488SBram Moolenaar char_u buf[NUMBUFLEN];
251c6538bccSBram Moolenaar funcexe_T funcexe;
25248570488SBram Moolenaar
25348570488SBram Moolenaar if (expr->v_type == VAR_FUNC)
25448570488SBram Moolenaar {
25548570488SBram Moolenaar s = expr->vval.v_string;
25648570488SBram Moolenaar if (s == NULL || *s == NUL)
25748570488SBram Moolenaar return FAIL;
258a80faa89SBram Moolenaar CLEAR_FIELD(funcexe);
259c6538bccSBram Moolenaar funcexe.evaluate = TRUE;
260c6538bccSBram Moolenaar if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL)
26148570488SBram Moolenaar return FAIL;
26248570488SBram Moolenaar }
26348570488SBram Moolenaar else if (expr->v_type == VAR_PARTIAL)
26448570488SBram Moolenaar {
26548570488SBram Moolenaar partial_T *partial = expr->vval.v_partial;
26648570488SBram Moolenaar
2679d8d0b5cSBram Moolenaar if (partial == NULL)
2689d8d0b5cSBram Moolenaar return FAIL;
2699d8d0b5cSBram Moolenaar
270822ba247SBram Moolenaar if (partial->pt_func != NULL
2710cb5bcf5SBram Moolenaar && partial->pt_func->uf_def_status != UF_NOT_COMPILED)
2728a7d6542SBram Moolenaar {
2736f5b6dfbSBram Moolenaar if (call_def_function(partial->pt_func, argc, argv,
2746f5b6dfbSBram Moolenaar partial, rettv) == FAIL)
2758a7d6542SBram Moolenaar return FAIL;
2768a7d6542SBram Moolenaar }
2778a7d6542SBram Moolenaar else
2788a7d6542SBram Moolenaar {
27948570488SBram Moolenaar s = partial_name(partial);
28048570488SBram Moolenaar if (s == NULL || *s == NUL)
28148570488SBram Moolenaar return FAIL;
282a80faa89SBram Moolenaar CLEAR_FIELD(funcexe);
283c6538bccSBram Moolenaar funcexe.evaluate = TRUE;
284c6538bccSBram Moolenaar funcexe.partial = partial;
285c6538bccSBram Moolenaar if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL)
28648570488SBram Moolenaar return FAIL;
28748570488SBram Moolenaar }
2888a7d6542SBram Moolenaar }
289f18332fbSBram Moolenaar else if (expr->v_type == VAR_INSTR)
290f18332fbSBram Moolenaar {
291f18332fbSBram Moolenaar return exe_typval_instr(expr, rettv);
292f18332fbSBram Moolenaar }
29348570488SBram Moolenaar else
29448570488SBram Moolenaar {
295d155d7a8SBram Moolenaar s = tv_get_string_buf_chk(expr, buf);
29648570488SBram Moolenaar if (s == NULL)
29748570488SBram Moolenaar return FAIL;
29848570488SBram Moolenaar s = skipwhite(s);
29947e880d6SBram Moolenaar if (eval1_emsg(&s, rettv, NULL) == FAIL)
30048570488SBram Moolenaar return FAIL;
301f96e9decSBram Moolenaar if (*skipwhite(s) != NUL) // check for trailing chars after expr
30248570488SBram Moolenaar {
303a43ebe94SBram Moolenaar clear_tv(rettv);
304108010aaSBram Moolenaar semsg(_(e_invalid_expression_str), s);
30548570488SBram Moolenaar return FAIL;
30648570488SBram Moolenaar }
30748570488SBram Moolenaar }
30848570488SBram Moolenaar return OK;
30948570488SBram Moolenaar }
31048570488SBram Moolenaar
31148570488SBram Moolenaar /*
31248570488SBram Moolenaar * Like eval_to_bool() but using a typval_T instead of a string.
31348570488SBram Moolenaar * Works for string, funcref and partial.
31448570488SBram Moolenaar */
31548570488SBram Moolenaar int
eval_expr_to_bool(typval_T * expr,int * error)31648570488SBram Moolenaar eval_expr_to_bool(typval_T *expr, int *error)
31748570488SBram Moolenaar {
31848570488SBram Moolenaar typval_T rettv;
31948570488SBram Moolenaar int res;
32048570488SBram Moolenaar
32148570488SBram Moolenaar if (eval_expr_typval(expr, NULL, 0, &rettv) == FAIL)
32248570488SBram Moolenaar {
32348570488SBram Moolenaar *error = TRUE;
32448570488SBram Moolenaar return FALSE;
32548570488SBram Moolenaar }
326e15eebd2SBram Moolenaar res = (tv_get_bool_chk(&rettv, error) != 0);
32748570488SBram Moolenaar clear_tv(&rettv);
32848570488SBram Moolenaar return res;
32948570488SBram Moolenaar }
33048570488SBram Moolenaar
331071d4279SBram Moolenaar /*
332071d4279SBram Moolenaar * Top level evaluation function, returning a string. If "skip" is TRUE,
333071d4279SBram Moolenaar * only parsing to "nextcmd" is done, without reporting errors. Return
334071d4279SBram Moolenaar * pointer to allocated memory, or NULL for failure or when "skip" is TRUE.
335071d4279SBram Moolenaar */
336071d4279SBram Moolenaar char_u *
eval_to_string_skip(char_u * arg,exarg_T * eap,int skip)3377454a06eSBram Moolenaar eval_to_string_skip(
3387454a06eSBram Moolenaar char_u *arg,
339b171fb17SBram Moolenaar exarg_T *eap,
3405d18efecSBram Moolenaar int skip) // only parse, don't execute
341071d4279SBram Moolenaar {
34233570924SBram Moolenaar typval_T tv;
343071d4279SBram Moolenaar char_u *retval;
344006ad48bSBram Moolenaar evalarg_T evalarg;
345071d4279SBram Moolenaar
34637c83711SBram Moolenaar fill_evalarg_from_eap(&evalarg, eap, skip);
347071d4279SBram Moolenaar if (skip)
348071d4279SBram Moolenaar ++emsg_skip;
349006ad48bSBram Moolenaar if (eval0(arg, &tv, eap, &evalarg) == FAIL || skip)
350071d4279SBram Moolenaar retval = NULL;
351071d4279SBram Moolenaar else
352071d4279SBram Moolenaar {
353d155d7a8SBram Moolenaar retval = vim_strsave(tv_get_string(&tv));
354c70646c6SBram Moolenaar clear_tv(&tv);
355071d4279SBram Moolenaar }
356071d4279SBram Moolenaar if (skip)
357071d4279SBram Moolenaar --emsg_skip;
358006ad48bSBram Moolenaar clear_evalarg(&evalarg, eap);
359071d4279SBram Moolenaar
360071d4279SBram Moolenaar return retval;
361071d4279SBram Moolenaar }
362071d4279SBram Moolenaar
363071d4279SBram Moolenaar /*
36469a7cb47SBram Moolenaar * Skip over an expression at "*pp".
36569a7cb47SBram Moolenaar * Return FAIL for an error, OK otherwise.
36669a7cb47SBram Moolenaar */
36769a7cb47SBram Moolenaar int
skip_expr(char_u ** pp,evalarg_T * evalarg)368683581ebSBram Moolenaar skip_expr(char_u **pp, evalarg_T *evalarg)
36969a7cb47SBram Moolenaar {
37033570924SBram Moolenaar typval_T rettv;
37169a7cb47SBram Moolenaar
37269a7cb47SBram Moolenaar *pp = skipwhite(*pp);
373683581ebSBram Moolenaar return eval1(pp, &rettv, evalarg);
37469a7cb47SBram Moolenaar }
37569a7cb47SBram Moolenaar
37669a7cb47SBram Moolenaar /*
37703717bf6SBram Moolenaar * Skip over an expression at "*arg".
378e40fbc2cSBram Moolenaar * If in Vim9 script and line breaks are encountered, the lines are
379e40fbc2cSBram Moolenaar * concatenated. "evalarg->eval_tofree" will be set accordingly.
3808e2730a3SBram Moolenaar * "arg" is advanced to just after the expression.
3818e2730a3SBram Moolenaar * "start" is set to the start of the expression, "end" to just after the end.
3828e2730a3SBram Moolenaar * Also when the expression is copied to allocated memory.
383e40fbc2cSBram Moolenaar * Return FAIL for an error, OK otherwise.
384e40fbc2cSBram Moolenaar */
385e40fbc2cSBram Moolenaar int
skip_expr_concatenate(char_u ** arg,char_u ** start,char_u ** end,evalarg_T * evalarg)3868e2730a3SBram Moolenaar skip_expr_concatenate(
3878e2730a3SBram Moolenaar char_u **arg,
3888e2730a3SBram Moolenaar char_u **start,
3898e2730a3SBram Moolenaar char_u **end,
3908e2730a3SBram Moolenaar evalarg_T *evalarg)
391e40fbc2cSBram Moolenaar {
392e40fbc2cSBram Moolenaar typval_T rettv;
393e40fbc2cSBram Moolenaar int res;
394eb6880b6SBram Moolenaar int vim9script = in_vim9script();
3959c2b0663SBram Moolenaar garray_T *gap = evalarg == NULL ? NULL : &evalarg->eval_ga;
396ecb66450SBram Moolenaar garray_T *freegap = evalarg == NULL ? NULL : &evalarg->eval_freega;
397e40fbc2cSBram Moolenaar int save_flags = evalarg == NULL ? 0 : evalarg->eval_flags;
398aeb2bdd0SBram Moolenaar int evaluate = evalarg == NULL
399aeb2bdd0SBram Moolenaar ? FALSE : (evalarg->eval_flags & EVAL_EVALUATE);
400e40fbc2cSBram Moolenaar
401aeb2bdd0SBram Moolenaar if (vim9script && evaluate
4027a4b8980SBram Moolenaar && (evalarg->eval_cookie != NULL || evalarg->eval_cctx != NULL))
403e40fbc2cSBram Moolenaar {
404e40fbc2cSBram Moolenaar ga_init2(gap, sizeof(char_u *), 10);
405e40fbc2cSBram Moolenaar // leave room for "start"
4067a4b8980SBram Moolenaar if (ga_grow(gap, 1) == OK)
407e40fbc2cSBram Moolenaar ++gap->ga_len;
408ecb66450SBram Moolenaar ga_init2(freegap, sizeof(char_u *), 10);
409e40fbc2cSBram Moolenaar }
4108e2730a3SBram Moolenaar *start = *arg;
411e40fbc2cSBram Moolenaar
412e40fbc2cSBram Moolenaar // Don't evaluate the expression.
413e40fbc2cSBram Moolenaar if (evalarg != NULL)
414e40fbc2cSBram Moolenaar evalarg->eval_flags &= ~EVAL_EVALUATE;
4158e2730a3SBram Moolenaar *arg = skipwhite(*arg);
4168e2730a3SBram Moolenaar res = eval1(arg, &rettv, evalarg);
4178e2730a3SBram Moolenaar *end = *arg;
418e40fbc2cSBram Moolenaar if (evalarg != NULL)
419e40fbc2cSBram Moolenaar evalarg->eval_flags = save_flags;
420e40fbc2cSBram Moolenaar
421aeb2bdd0SBram Moolenaar if (vim9script && evaluate
4227a4b8980SBram Moolenaar && (evalarg->eval_cookie != NULL || evalarg->eval_cctx != NULL))
4237a4b8980SBram Moolenaar {
4247a4b8980SBram Moolenaar if (evalarg->eval_ga.ga_len == 1)
4257a4b8980SBram Moolenaar {
426ecb66450SBram Moolenaar // just the one line, no need to concatenate
4277a4b8980SBram Moolenaar ga_clear(gap);
4287a4b8980SBram Moolenaar gap->ga_itemsize = 0;
4297a4b8980SBram Moolenaar }
4307a4b8980SBram Moolenaar else
431e40fbc2cSBram Moolenaar {
432e40fbc2cSBram Moolenaar char_u *p;
4338e2730a3SBram Moolenaar size_t endoff = STRLEN(*arg);
434e40fbc2cSBram Moolenaar
435e40fbc2cSBram Moolenaar // Line breaks encountered, concatenate all the lines.
436e40fbc2cSBram Moolenaar *((char_u **)gap->ga_data) = *start;
437e40fbc2cSBram Moolenaar p = ga_concat_strings(gap, " ");
4387a4b8980SBram Moolenaar
4397a4b8980SBram Moolenaar // free the lines only when using getsourceline()
4407a4b8980SBram Moolenaar if (evalarg->eval_cookie != NULL)
4417a4b8980SBram Moolenaar {
4428e2730a3SBram Moolenaar // Do not free the first line, the caller can still use it.
443e40fbc2cSBram Moolenaar *((char_u **)gap->ga_data) = NULL;
4448e2730a3SBram Moolenaar // Do not free the last line, "arg" points into it, free it
4458e2730a3SBram Moolenaar // later.
4468e2730a3SBram Moolenaar vim_free(evalarg->eval_tofree);
4478e2730a3SBram Moolenaar evalarg->eval_tofree =
4488e2730a3SBram Moolenaar ((char_u **)gap->ga_data)[gap->ga_len - 1];
4498e2730a3SBram Moolenaar ((char_u **)gap->ga_data)[gap->ga_len - 1] = NULL;
450e40fbc2cSBram Moolenaar ga_clear_strings(gap);
4517a4b8980SBram Moolenaar }
4527a4b8980SBram Moolenaar else
453ecb66450SBram Moolenaar {
4547a4b8980SBram Moolenaar ga_clear(gap);
455ecb66450SBram Moolenaar
456ecb66450SBram Moolenaar // free lines that were explicitly marked for freeing
457ecb66450SBram Moolenaar ga_clear_strings(freegap);
458ecb66450SBram Moolenaar }
459ecb66450SBram Moolenaar
460e40fbc2cSBram Moolenaar gap->ga_itemsize = 0;
461e40fbc2cSBram Moolenaar if (p == NULL)
462e40fbc2cSBram Moolenaar return FAIL;
463e40fbc2cSBram Moolenaar *start = p;
4648e2730a3SBram Moolenaar vim_free(evalarg->eval_tofree_lambda);
4658e2730a3SBram Moolenaar evalarg->eval_tofree_lambda = p;
466e40fbc2cSBram Moolenaar // Compute "end" relative to the end.
467e40fbc2cSBram Moolenaar *end = *start + STRLEN(*start) - endoff;
468e40fbc2cSBram Moolenaar }
4697a4b8980SBram Moolenaar }
470e40fbc2cSBram Moolenaar
471e40fbc2cSBram Moolenaar return res;
472e40fbc2cSBram Moolenaar }
473e40fbc2cSBram Moolenaar
474e40fbc2cSBram Moolenaar /*
475883cf97fSBram Moolenaar * Convert "tv" to a string.
476883cf97fSBram Moolenaar * When "convert" is TRUE convert a List into a sequence of lines and convert
477883cf97fSBram Moolenaar * a Float to a String.
478883cf97fSBram Moolenaar * Returns an allocated string (NULL when out of memory).
479883cf97fSBram Moolenaar */
480883cf97fSBram Moolenaar char_u *
typval2string(typval_T * tv,int convert)481883cf97fSBram Moolenaar typval2string(typval_T *tv, int convert)
482883cf97fSBram Moolenaar {
483883cf97fSBram Moolenaar garray_T ga;
484883cf97fSBram Moolenaar char_u *retval;
485883cf97fSBram Moolenaar #ifdef FEAT_FLOAT
486883cf97fSBram Moolenaar char_u numbuf[NUMBUFLEN];
487883cf97fSBram Moolenaar #endif
488883cf97fSBram Moolenaar
489883cf97fSBram Moolenaar if (convert && tv->v_type == VAR_LIST)
490883cf97fSBram Moolenaar {
491883cf97fSBram Moolenaar ga_init2(&ga, (int)sizeof(char), 80);
492883cf97fSBram Moolenaar if (tv->vval.v_list != NULL)
493883cf97fSBram Moolenaar {
494883cf97fSBram Moolenaar list_join(&ga, tv->vval.v_list, (char_u *)"\n", TRUE, FALSE, 0);
495883cf97fSBram Moolenaar if (tv->vval.v_list->lv_len > 0)
496883cf97fSBram Moolenaar ga_append(&ga, NL);
497883cf97fSBram Moolenaar }
498883cf97fSBram Moolenaar ga_append(&ga, NUL);
499883cf97fSBram Moolenaar retval = (char_u *)ga.ga_data;
500883cf97fSBram Moolenaar }
501883cf97fSBram Moolenaar #ifdef FEAT_FLOAT
502883cf97fSBram Moolenaar else if (convert && tv->v_type == VAR_FLOAT)
503883cf97fSBram Moolenaar {
504883cf97fSBram Moolenaar vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", tv->vval.v_float);
505883cf97fSBram Moolenaar retval = vim_strsave(numbuf);
506883cf97fSBram Moolenaar }
507883cf97fSBram Moolenaar #endif
508883cf97fSBram Moolenaar else
509883cf97fSBram Moolenaar retval = vim_strsave(tv_get_string(tv));
510883cf97fSBram Moolenaar return retval;
511883cf97fSBram Moolenaar }
512883cf97fSBram Moolenaar
513883cf97fSBram Moolenaar /*
5147a4b8980SBram Moolenaar * Top level evaluation function, returning a string. Does not handle line
5157a4b8980SBram Moolenaar * breaks.
516a85fb757SBram Moolenaar * When "convert" is TRUE convert a List into a sequence of lines and convert
517a85fb757SBram Moolenaar * a Float to a String.
518071d4279SBram Moolenaar * Return pointer to allocated memory, or NULL for failure.
519071d4279SBram Moolenaar */
520071d4279SBram Moolenaar char_u *
eval_to_string_eap(char_u * arg,int convert,exarg_T * eap)521b4bcea47SBram Moolenaar eval_to_string_eap(
5227454a06eSBram Moolenaar char_u *arg,
523b4bcea47SBram Moolenaar int convert,
524b4bcea47SBram Moolenaar exarg_T *eap)
525071d4279SBram Moolenaar {
52633570924SBram Moolenaar typval_T tv;
527071d4279SBram Moolenaar char_u *retval;
528b4bcea47SBram Moolenaar evalarg_T evalarg;
529071d4279SBram Moolenaar
530b4bcea47SBram Moolenaar fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip);
531b4bcea47SBram Moolenaar if (eval0(arg, &tv, NULL, &evalarg) == FAIL)
532071d4279SBram Moolenaar retval = NULL;
533071d4279SBram Moolenaar else
534071d4279SBram Moolenaar {
535883cf97fSBram Moolenaar retval = typval2string(&tv, convert);
536c70646c6SBram Moolenaar clear_tv(&tv);
537071d4279SBram Moolenaar }
538b4bcea47SBram Moolenaar clear_evalarg(&evalarg, NULL);
539071d4279SBram Moolenaar
540071d4279SBram Moolenaar return retval;
541071d4279SBram Moolenaar }
542071d4279SBram Moolenaar
543b4bcea47SBram Moolenaar char_u *
eval_to_string(char_u * arg,int convert)544b4bcea47SBram Moolenaar eval_to_string(
545b4bcea47SBram Moolenaar char_u *arg,
546b4bcea47SBram Moolenaar int convert)
547b4bcea47SBram Moolenaar {
548b4bcea47SBram Moolenaar return eval_to_string_eap(arg, convert, NULL);
549b4bcea47SBram Moolenaar }
550b4bcea47SBram Moolenaar
551071d4279SBram Moolenaar /*
552b71eaaeaSBram Moolenaar * Call eval_to_string() without using current local variables and using
5536adb9ea0SBram Moolenaar * textwinlock. When "use_sandbox" is TRUE use the sandbox.
554c9edd6b5SBram Moolenaar * Use legacy Vim script syntax.
555071d4279SBram Moolenaar */
556071d4279SBram Moolenaar char_u *
eval_to_string_safe(char_u * arg,int use_sandbox)5577454a06eSBram Moolenaar eval_to_string_safe(
5587454a06eSBram Moolenaar char_u *arg,
5597454a06eSBram Moolenaar int use_sandbox)
560071d4279SBram Moolenaar {
561071d4279SBram Moolenaar char_u *retval;
56227e80c88SBram Moolenaar funccal_entry_T funccal_entry;
563c9edd6b5SBram Moolenaar int save_sc_version = current_sctx.sc_version;
564070ac343SChristian Brabandt int save_garbage = may_garbage_collect;
565071d4279SBram Moolenaar
566c9edd6b5SBram Moolenaar current_sctx.sc_version = 1;
56727e80c88SBram Moolenaar save_funccal(&funccal_entry);
568b71eaaeaSBram Moolenaar if (use_sandbox)
569071d4279SBram Moolenaar ++sandbox;
5706adb9ea0SBram Moolenaar ++textwinlock;
571070ac343SChristian Brabandt may_garbage_collect = FALSE;
572b171fb17SBram Moolenaar retval = eval_to_string(arg, FALSE);
573b71eaaeaSBram Moolenaar if (use_sandbox)
574071d4279SBram Moolenaar --sandbox;
5756adb9ea0SBram Moolenaar --textwinlock;
576070ac343SChristian Brabandt may_garbage_collect = save_garbage;
57727e80c88SBram Moolenaar restore_funccal();
578c9edd6b5SBram Moolenaar current_sctx.sc_version = save_sc_version;
579071d4279SBram Moolenaar return retval;
580071d4279SBram Moolenaar }
581071d4279SBram Moolenaar
582071d4279SBram Moolenaar /*
583071d4279SBram Moolenaar * Top level evaluation function, returning a number.
584071d4279SBram Moolenaar * Evaluates "expr" silently.
585071d4279SBram Moolenaar * Returns -1 for an error.
586071d4279SBram Moolenaar */
58722fcfad2SBram Moolenaar varnumber_T
eval_to_number(char_u * expr)5887454a06eSBram Moolenaar eval_to_number(char_u *expr)
589071d4279SBram Moolenaar {
59033570924SBram Moolenaar typval_T rettv;
59122fcfad2SBram Moolenaar varnumber_T retval;
59231c67ef8SBram Moolenaar char_u *p = skipwhite(expr);
593071d4279SBram Moolenaar
594071d4279SBram Moolenaar ++emsg_off;
595071d4279SBram Moolenaar
5965409f5d8SBram Moolenaar if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL)
597071d4279SBram Moolenaar retval = -1;
598071d4279SBram Moolenaar else
599071d4279SBram Moolenaar {
600d155d7a8SBram Moolenaar retval = tv_get_number_chk(&rettv, NULL);
601c70646c6SBram Moolenaar clear_tv(&rettv);
602071d4279SBram Moolenaar }
603071d4279SBram Moolenaar --emsg_off;
604071d4279SBram Moolenaar
605071d4279SBram Moolenaar return retval;
606071d4279SBram Moolenaar }
607071d4279SBram Moolenaar
60887e25fdfSBram Moolenaar /*
6094770d09aSBram Moolenaar * Top level evaluation function.
6104770d09aSBram Moolenaar * Returns an allocated typval_T with the result.
6114770d09aSBram Moolenaar * Returns NULL when there is an error.
61287e25fdfSBram Moolenaar */
61387e25fdfSBram Moolenaar typval_T *
eval_expr(char_u * arg,exarg_T * eap)614b171fb17SBram Moolenaar eval_expr(char_u *arg, exarg_T *eap)
61587e25fdfSBram Moolenaar {
61687e25fdfSBram Moolenaar typval_T *tv;
61737c83711SBram Moolenaar evalarg_T evalarg;
61837c83711SBram Moolenaar
61937c83711SBram Moolenaar fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip);
62087e25fdfSBram Moolenaar
621c799fe20SBram Moolenaar tv = ALLOC_ONE(typval_T);
62237c83711SBram Moolenaar if (tv != NULL && eval0(arg, tv, eap, &evalarg) == FAIL)
623d23a8236SBram Moolenaar VIM_CLEAR(tv);
62487e25fdfSBram Moolenaar
62537c83711SBram Moolenaar clear_evalarg(&evalarg, eap);
62687e25fdfSBram Moolenaar return tv;
62787e25fdfSBram Moolenaar }
62887e25fdfSBram Moolenaar
629071d4279SBram Moolenaar /*
630b544f3c8SBram Moolenaar * Call some Vim script function and return the result in "*rettv".
631ffa96841SBram Moolenaar * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc]
632ffa96841SBram Moolenaar * should have type VAR_UNKNOWN.
633d8e9bb20SBram Moolenaar * Returns OK or FAIL.
634071d4279SBram Moolenaar */
63582139084SBram Moolenaar int
call_vim_function(char_u * func,int argc,typval_T * argv,typval_T * rettv)6367454a06eSBram Moolenaar call_vim_function(
6377454a06eSBram Moolenaar char_u *func,
6387454a06eSBram Moolenaar int argc,
639ffa96841SBram Moolenaar typval_T *argv,
640ded27a1fSBram Moolenaar typval_T *rettv)
641071d4279SBram Moolenaar {
642d8e9bb20SBram Moolenaar int ret;
643c6538bccSBram Moolenaar funcexe_T funcexe;
644071d4279SBram Moolenaar
6455d18efecSBram Moolenaar rettv->v_type = VAR_UNKNOWN; // clear_tv() uses this
646a80faa89SBram Moolenaar CLEAR_FIELD(funcexe);
647c6538bccSBram Moolenaar funcexe.firstline = curwin->w_cursor.lnum;
648c6538bccSBram Moolenaar funcexe.lastline = curwin->w_cursor.lnum;
649c6538bccSBram Moolenaar funcexe.evaluate = TRUE;
650c6538bccSBram Moolenaar ret = call_func(func, -1, rettv, argc, argv, &funcexe);
651d8e9bb20SBram Moolenaar if (ret == FAIL)
652d8e9bb20SBram Moolenaar clear_tv(rettv);
653d8e9bb20SBram Moolenaar
654d8e9bb20SBram Moolenaar return ret;
655d8e9bb20SBram Moolenaar }
656d8e9bb20SBram Moolenaar
657b2c5a5acSBram Moolenaar /*
658b544f3c8SBram Moolenaar * Call Vim script function "func" and return the result as a number.
659b2c5a5acSBram Moolenaar * Returns -1 when calling the function fails.
660ffa96841SBram Moolenaar * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should
661ffa96841SBram Moolenaar * have type VAR_UNKNOWN.
662b2c5a5acSBram Moolenaar */
66322fcfad2SBram Moolenaar varnumber_T
call_func_retnr(char_u * func,int argc,typval_T * argv)6647454a06eSBram Moolenaar call_func_retnr(
6657454a06eSBram Moolenaar char_u *func,
6667454a06eSBram Moolenaar int argc,
667ded27a1fSBram Moolenaar typval_T *argv)
668b2c5a5acSBram Moolenaar {
669b2c5a5acSBram Moolenaar typval_T rettv;
67022fcfad2SBram Moolenaar varnumber_T retval;
671b2c5a5acSBram Moolenaar
672ded27a1fSBram Moolenaar if (call_vim_function(func, argc, argv, &rettv) == FAIL)
673b2c5a5acSBram Moolenaar return -1;
674b2c5a5acSBram Moolenaar
675d155d7a8SBram Moolenaar retval = tv_get_number_chk(&rettv, NULL);
676b2c5a5acSBram Moolenaar clear_tv(&rettv);
677b2c5a5acSBram Moolenaar return retval;
678b2c5a5acSBram Moolenaar }
679b2c5a5acSBram Moolenaar
680d8e9bb20SBram Moolenaar /*
6815b3d1bb0SBram Moolenaar * Call Vim script function like call_func_retnr() and drop the result.
6825b3d1bb0SBram Moolenaar * Returns FAIL when calling the function fails.
6835b3d1bb0SBram Moolenaar */
6845b3d1bb0SBram Moolenaar int
call_func_noret(char_u * func,int argc,typval_T * argv)6855b3d1bb0SBram Moolenaar call_func_noret(
6865b3d1bb0SBram Moolenaar char_u *func,
6875b3d1bb0SBram Moolenaar int argc,
6885b3d1bb0SBram Moolenaar typval_T *argv)
6895b3d1bb0SBram Moolenaar {
6905b3d1bb0SBram Moolenaar typval_T rettv;
6915b3d1bb0SBram Moolenaar
6925b3d1bb0SBram Moolenaar if (call_vim_function(func, argc, argv, &rettv) == FAIL)
6935b3d1bb0SBram Moolenaar return FAIL;
6945b3d1bb0SBram Moolenaar clear_tv(&rettv);
6955b3d1bb0SBram Moolenaar return OK;
6965b3d1bb0SBram Moolenaar }
6975b3d1bb0SBram Moolenaar
6985b3d1bb0SBram Moolenaar /*
699b544f3c8SBram Moolenaar * Call Vim script function "func" and return the result as a string.
7005b3d1bb0SBram Moolenaar * Uses "argv" and "argc" as call_func_retnr().
70125ceb227SBram Moolenaar * Returns NULL when calling the function fails.
702d8e9bb20SBram Moolenaar */
703d8e9bb20SBram Moolenaar void *
call_func_retstr(char_u * func,int argc,typval_T * argv)7047454a06eSBram Moolenaar call_func_retstr(
7057454a06eSBram Moolenaar char_u *func,
7067454a06eSBram Moolenaar int argc,
707ded27a1fSBram Moolenaar typval_T *argv)
708d8e9bb20SBram Moolenaar {
709d8e9bb20SBram Moolenaar typval_T rettv;
71025ceb227SBram Moolenaar char_u *retval;
711d8e9bb20SBram Moolenaar
712ded27a1fSBram Moolenaar if (call_vim_function(func, argc, argv, &rettv) == FAIL)
713d8e9bb20SBram Moolenaar return NULL;
714d8e9bb20SBram Moolenaar
715d155d7a8SBram Moolenaar retval = vim_strsave(tv_get_string(&rettv));
716d8e9bb20SBram Moolenaar clear_tv(&rettv);
717071d4279SBram Moolenaar return retval;
718071d4279SBram Moolenaar }
719d8e9bb20SBram Moolenaar
72025ceb227SBram Moolenaar /*
721b544f3c8SBram Moolenaar * Call Vim script function "func" and return the result as a List.
7225b3d1bb0SBram Moolenaar * Uses "argv" and "argc" as call_func_retnr().
7239bf749bcSBram Moolenaar * Returns NULL when there is something wrong.
724d8e9bb20SBram Moolenaar */
725d8e9bb20SBram Moolenaar void *
call_func_retlist(char_u * func,int argc,typval_T * argv)7267454a06eSBram Moolenaar call_func_retlist(
7277454a06eSBram Moolenaar char_u *func,
7287454a06eSBram Moolenaar int argc,
729ded27a1fSBram Moolenaar typval_T *argv)
730d8e9bb20SBram Moolenaar {
731d8e9bb20SBram Moolenaar typval_T rettv;
732d8e9bb20SBram Moolenaar
733ded27a1fSBram Moolenaar if (call_vim_function(func, argc, argv, &rettv) == FAIL)
734d8e9bb20SBram Moolenaar return NULL;
735d8e9bb20SBram Moolenaar
736d8e9bb20SBram Moolenaar if (rettv.v_type != VAR_LIST)
737d8e9bb20SBram Moolenaar {
738d8e9bb20SBram Moolenaar clear_tv(&rettv);
739d8e9bb20SBram Moolenaar return NULL;
740d8e9bb20SBram Moolenaar }
741d8e9bb20SBram Moolenaar
742d8e9bb20SBram Moolenaar return rettv.vval.v_list;
743d8e9bb20SBram Moolenaar }
744071d4279SBram Moolenaar
745071d4279SBram Moolenaar #ifdef FEAT_FOLDING
746071d4279SBram Moolenaar /*
74732b3f820SBram Moolenaar * Evaluate "arg", which is 'foldexpr'.
74832b3f820SBram Moolenaar * Note: caller must set "curwin" to match "arg".
74932b3f820SBram Moolenaar * Returns the foldlevel, and any character preceding it in "*cp". Doesn't
75032b3f820SBram Moolenaar * give error messages.
751071d4279SBram Moolenaar */
752071d4279SBram Moolenaar int
eval_foldexpr(char_u * arg,int * cp)7537454a06eSBram Moolenaar eval_foldexpr(char_u *arg, int *cp)
754071d4279SBram Moolenaar {
75533570924SBram Moolenaar typval_T tv;
75622fcfad2SBram Moolenaar varnumber_T retval;
757071d4279SBram Moolenaar char_u *s;
758d1f56e68SBram Moolenaar int use_sandbox = was_set_insecurely((char_u *)"foldexpr",
759d1f56e68SBram Moolenaar OPT_LOCAL);
760071d4279SBram Moolenaar
761071d4279SBram Moolenaar ++emsg_off;
762b71eaaeaSBram Moolenaar if (use_sandbox)
763071d4279SBram Moolenaar ++sandbox;
7646adb9ea0SBram Moolenaar ++textwinlock;
765071d4279SBram Moolenaar *cp = NUL;
7665409f5d8SBram Moolenaar if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL)
767071d4279SBram Moolenaar retval = 0;
768071d4279SBram Moolenaar else
769071d4279SBram Moolenaar {
7705d18efecSBram Moolenaar // If the result is a number, just return the number.
771c70646c6SBram Moolenaar if (tv.v_type == VAR_NUMBER)
772c70646c6SBram Moolenaar retval = tv.vval.v_number;
773758711c5SBram Moolenaar else if (tv.v_type != VAR_STRING || tv.vval.v_string == NULL)
774071d4279SBram Moolenaar retval = 0;
775071d4279SBram Moolenaar else
776071d4279SBram Moolenaar {
7775d18efecSBram Moolenaar // If the result is a string, check if there is a non-digit before
7785d18efecSBram Moolenaar // the number.
779c70646c6SBram Moolenaar s = tv.vval.v_string;
780071d4279SBram Moolenaar if (!VIM_ISDIGIT(*s) && *s != '-')
781071d4279SBram Moolenaar *cp = *s++;
782071d4279SBram Moolenaar retval = atol((char *)s);
783071d4279SBram Moolenaar }
784c70646c6SBram Moolenaar clear_tv(&tv);
785071d4279SBram Moolenaar }
786071d4279SBram Moolenaar --emsg_off;
787b71eaaeaSBram Moolenaar if (use_sandbox)
788071d4279SBram Moolenaar --sandbox;
7896adb9ea0SBram Moolenaar --textwinlock;
790b7a78f7aSBram Moolenaar clear_evalarg(&EVALARG_EVALUATE, NULL);
791071d4279SBram Moolenaar
79222fcfad2SBram Moolenaar return (int)retval;
793071d4279SBram Moolenaar }
794071d4279SBram Moolenaar #endif
795071d4279SBram Moolenaar
796071d4279SBram Moolenaar /*
7977480b5ceSBram Moolenaar * Get an lval: variable, Dict item or List item that can be assigned a value
7987480b5ceSBram Moolenaar * to: "name", "na{me}", "name[expr]", "name[expr:expr]", "name[expr][expr]",
7997480b5ceSBram Moolenaar * "name.key", "name.key[expr]" etc.
8007480b5ceSBram Moolenaar * Indexing only works if "name" is an existing List or Dictionary.
8017480b5ceSBram Moolenaar * "name" points to the start of the name.
8027480b5ceSBram Moolenaar * If "rettv" is not NULL it points to the value to be assigned.
8037480b5ceSBram Moolenaar * "unlet" is TRUE for ":unlet": slightly different behavior when something is
8047480b5ceSBram Moolenaar * wrong; must end in space or cmd separator.
8057480b5ceSBram Moolenaar *
8066d977d6cSBram Moolenaar * flags:
8076d977d6cSBram Moolenaar * GLV_QUIET: do not give error messages
8083a257737SBram Moolenaar * GLV_READ_ONLY: will not change the variable
8096d977d6cSBram Moolenaar * GLV_NO_AUTOLOAD: do not use script autoloading
8106d977d6cSBram Moolenaar *
8117480b5ceSBram Moolenaar * Returns a pointer to just after the name, including indexes.
812a7043832SBram Moolenaar * When an evaluation error occurs "lp->ll_name" is NULL;
8137480b5ceSBram Moolenaar * Returns NULL for a parsing error. Still need to free items in "lp"!
814c70646c6SBram Moolenaar */
815a9b579f3SBram Moolenaar char_u *
get_lval(char_u * name,typval_T * rettv,lval_T * lp,int unlet,int skip,int flags,int fne_flags)8167454a06eSBram Moolenaar get_lval(
8177454a06eSBram Moolenaar char_u *name,
8187454a06eSBram Moolenaar typval_T *rettv,
8197454a06eSBram Moolenaar lval_T *lp,
8207454a06eSBram Moolenaar int unlet,
8217454a06eSBram Moolenaar int skip,
8225d18efecSBram Moolenaar int flags, // GLV_ values
8235d18efecSBram Moolenaar int fne_flags) // flags for find_name_end()
824c70646c6SBram Moolenaar {
825c70646c6SBram Moolenaar char_u *p;
8267480b5ceSBram Moolenaar char_u *expr_start, *expr_end;
8277480b5ceSBram Moolenaar int cc;
82833570924SBram Moolenaar dictitem_T *v;
82933570924SBram Moolenaar typval_T var1;
83033570924SBram Moolenaar typval_T var2;
8317480b5ceSBram Moolenaar int empty1 = FALSE;
8328c711458SBram Moolenaar char_u *key = NULL;
8338c711458SBram Moolenaar int len;
834896ad2c3SBram Moolenaar hashtab_T *ht = NULL;
8356d977d6cSBram Moolenaar int quiet = flags & GLV_QUIET;
83632b3f820SBram Moolenaar int writing;
837c70646c6SBram Moolenaar
8385d18efecSBram Moolenaar // Clear everything in "lp".
839a80faa89SBram Moolenaar CLEAR_POINTER(lp);
8407480b5ceSBram Moolenaar
8412ef951ddSBram Moolenaar if (skip || (flags & GLV_COMPILING))
8427480b5ceSBram Moolenaar {
8432ef951ddSBram Moolenaar // When skipping or compiling just find the end of the name.
8447480b5ceSBram Moolenaar lp->ll_name = name;
8459b5384b9SBram Moolenaar lp->ll_name_end = find_name_end(name, NULL, NULL,
8469b5384b9SBram Moolenaar FNE_INCL_BR | fne_flags);
8479b5384b9SBram Moolenaar return lp->ll_name_end;
8487480b5ceSBram Moolenaar }
8497480b5ceSBram Moolenaar
8505d18efecSBram Moolenaar // Find the end of the name.
85134cdc3e3SBram Moolenaar p = find_name_end(name, &expr_start, &expr_end, fne_flags);
8528a7d6542SBram Moolenaar lp->ll_name_end = p;
8537480b5ceSBram Moolenaar if (expr_start != NULL)
8547480b5ceSBram Moolenaar {
8555d18efecSBram Moolenaar // Don't expand the name when we already know there is an error.
8561c465444SBram Moolenaar if (unlet && !VIM_ISWHITE(*p) && !ends_excmd(*p)
8577480b5ceSBram Moolenaar && *p != '[' && *p != '.')
8587480b5ceSBram Moolenaar {
8592d06bfdeSBram Moolenaar semsg(_(e_trailing_arg), p);
8607480b5ceSBram Moolenaar return NULL;
8617480b5ceSBram Moolenaar }
8627480b5ceSBram Moolenaar
8637480b5ceSBram Moolenaar lp->ll_exp_name = make_expanded_name(name, expr_start, expr_end, p);
8647480b5ceSBram Moolenaar if (lp->ll_exp_name == NULL)
8657480b5ceSBram Moolenaar {
8665d18efecSBram Moolenaar // Report an invalid expression in braces, unless the
8675d18efecSBram Moolenaar // expression evaluation has been cancelled due to an
8685d18efecSBram Moolenaar // aborting error, an interrupt, or an exception.
8697480b5ceSBram Moolenaar if (!aborting() && !quiet)
8707480b5ceSBram Moolenaar {
8717480b5ceSBram Moolenaar emsg_severe = TRUE;
872f9e3e09fSBram Moolenaar semsg(_(e_invarg2), name);
8737480b5ceSBram Moolenaar return NULL;
8747480b5ceSBram Moolenaar }
8757480b5ceSBram Moolenaar }
8767480b5ceSBram Moolenaar lp->ll_name = lp->ll_exp_name;
8777480b5ceSBram Moolenaar }
8787480b5ceSBram Moolenaar else
8798a7d6542SBram Moolenaar {
8807480b5ceSBram Moolenaar lp->ll_name = name;
8817480b5ceSBram Moolenaar
88295dd9f25SBram Moolenaar if (in_vim9script())
88395dd9f25SBram Moolenaar {
88495dd9f25SBram Moolenaar // "a: type" is declaring variable "a" with a type, not "a:".
88595dd9f25SBram Moolenaar if (p == name + 2 && p[-1] == ':')
88695dd9f25SBram Moolenaar {
88795dd9f25SBram Moolenaar --p;
88895dd9f25SBram Moolenaar lp->ll_name_end = p;
88995dd9f25SBram Moolenaar }
89095dd9f25SBram Moolenaar if (*p == ':')
8918a7d6542SBram Moolenaar {
89221b9e977SBram Moolenaar scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
8938a7d6542SBram Moolenaar char_u *tp = skipwhite(p + 1);
89460faf865SBram Moolenaar
89560faf865SBram Moolenaar if (tp == p + 1 && !quiet)
89660faf865SBram Moolenaar {
89760faf865SBram Moolenaar semsg(_(e_white_space_required_after_str_str), ":", p);
89860faf865SBram Moolenaar return NULL;
89960faf865SBram Moolenaar }
9008a7d6542SBram Moolenaar
9018a7d6542SBram Moolenaar // parse the type after the name
9029e68c325SBram Moolenaar lp->ll_type = parse_type(&tp, &si->sn_type_list, !quiet);
9039e68c325SBram Moolenaar if (lp->ll_type == NULL && !quiet)
9049e68c325SBram Moolenaar return NULL;
9058a7d6542SBram Moolenaar lp->ll_name_end = tp;
9068a7d6542SBram Moolenaar }
9078a7d6542SBram Moolenaar }
90895dd9f25SBram Moolenaar }
9098a7d6542SBram Moolenaar
9105d18efecSBram Moolenaar // Without [idx] or .key we are done.
9117480b5ceSBram Moolenaar if ((*p != '[' && *p != '.') || lp->ll_name == NULL)
9127480b5ceSBram Moolenaar return p;
9137480b5ceSBram Moolenaar
914aacc966cSBram Moolenaar if (in_vim9script() && lval_root != NULL)
915aacc966cSBram Moolenaar {
916aacc966cSBram Moolenaar // using local variable
917aacc966cSBram Moolenaar lp->ll_tv = lval_root;
91878a9c2e6SBram Moolenaar v = NULL;
919aacc966cSBram Moolenaar }
920aacc966cSBram Moolenaar else
921aacc966cSBram Moolenaar {
9227480b5ceSBram Moolenaar cc = *p;
9237480b5ceSBram Moolenaar *p = NUL;
92432b3f820SBram Moolenaar // When we would write to the variable pass &ht and prevent autoload.
92532b3f820SBram Moolenaar writing = !(flags & GLV_READ_ONLY);
92632b3f820SBram Moolenaar v = find_var(lp->ll_name, writing ? &ht : NULL,
92732b3f820SBram Moolenaar (flags & GLV_NO_AUTOLOAD) || writing);
9287480b5ceSBram Moolenaar if (v == NULL && !quiet)
929451c2e35SBram Moolenaar semsg(_(e_undefined_variable_str), lp->ll_name);
9307480b5ceSBram Moolenaar *p = cc;
931c70646c6SBram Moolenaar if (v == NULL)
932c70646c6SBram Moolenaar return NULL;
933aacc966cSBram Moolenaar lp->ll_tv = &v->di_tv;
934aacc966cSBram Moolenaar }
935c70646c6SBram Moolenaar
9368f22f5c3SBram Moolenaar if (in_vim9script() && (flags & GLV_NO_DECL) == 0)
9378f22f5c3SBram Moolenaar {
9388f22f5c3SBram Moolenaar if (!quiet)
9398f22f5c3SBram Moolenaar semsg(_(e_variable_already_declared), lp->ll_name);
9408f22f5c3SBram Moolenaar return NULL;
9418f22f5c3SBram Moolenaar }
9428f22f5c3SBram Moolenaar
9437480b5ceSBram Moolenaar /*
9447480b5ceSBram Moolenaar * Loop until no more [idx] or .key is following.
9457480b5ceSBram Moolenaar */
946f06e5a54SBram Moolenaar var1.v_type = VAR_UNKNOWN;
947f06e5a54SBram Moolenaar var2.v_type = VAR_UNKNOWN;
9483a3b10e8SBram Moolenaar while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
949c70646c6SBram Moolenaar {
9503a3b10e8SBram Moolenaar if (*p == '.' && lp->ll_tv->v_type != VAR_DICT)
9513a3b10e8SBram Moolenaar {
9523a3b10e8SBram Moolenaar if (!quiet)
9533a3b10e8SBram Moolenaar semsg(_(e_dot_can_only_be_used_on_dictionary_str), name);
9543a3b10e8SBram Moolenaar return NULL;
9553a3b10e8SBram Moolenaar }
956e65081d1SBram Moolenaar if (lp->ll_tv->v_type != VAR_LIST
957e65081d1SBram Moolenaar && lp->ll_tv->v_type != VAR_DICT
958e65081d1SBram Moolenaar && lp->ll_tv->v_type != VAR_BLOB)
959c70646c6SBram Moolenaar {
9607480b5ceSBram Moolenaar if (!quiet)
961f9e3e09fSBram Moolenaar emsg(_("E689: Can only index a List, Dictionary or Blob"));
9627480b5ceSBram Moolenaar return NULL;
963c70646c6SBram Moolenaar }
964e65081d1SBram Moolenaar
965e65081d1SBram Moolenaar // a NULL list/blob works like an empty list/blob, allocate one now.
966e65081d1SBram Moolenaar if (lp->ll_tv->v_type == VAR_LIST && lp->ll_tv->vval.v_list == NULL)
967e65081d1SBram Moolenaar rettv_list_alloc(lp->ll_tv);
968e65081d1SBram Moolenaar else if (lp->ll_tv->v_type == VAR_BLOB
969e65081d1SBram Moolenaar && lp->ll_tv->vval.v_blob == NULL)
970e65081d1SBram Moolenaar rettv_blob_alloc(lp->ll_tv);
971e65081d1SBram Moolenaar
9727480b5ceSBram Moolenaar if (lp->ll_range)
9736cc16197SBram Moolenaar {
9747480b5ceSBram Moolenaar if (!quiet)
975f9e3e09fSBram Moolenaar emsg(_("E708: [:] must come last"));
9767480b5ceSBram Moolenaar return NULL;
9776cc16197SBram Moolenaar }
9786cc16197SBram Moolenaar
97910c65860SBram Moolenaar if (in_vim9script() && lp->ll_valtype == NULL
98078a9c2e6SBram Moolenaar && v != NULL
98110c65860SBram Moolenaar && lp->ll_tv == &v->di_tv
98210c65860SBram Moolenaar && ht != NULL && ht == get_script_local_ht())
98310c65860SBram Moolenaar {
984c967d57aSBram Moolenaar svar_T *sv = find_typval_in_script(lp->ll_tv);
98510c65860SBram Moolenaar
98610c65860SBram Moolenaar // Vim9 script local variable: get the type
98710c65860SBram Moolenaar if (sv != NULL)
98810c65860SBram Moolenaar lp->ll_valtype = sv->sv_type;
98910c65860SBram Moolenaar }
99010c65860SBram Moolenaar
9918c711458SBram Moolenaar len = -1;
9928c711458SBram Moolenaar if (*p == '.')
9938c711458SBram Moolenaar {
9948c711458SBram Moolenaar key = p + 1;
9958c711458SBram Moolenaar for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
9968c711458SBram Moolenaar ;
9978c711458SBram Moolenaar if (len == 0)
9988c711458SBram Moolenaar {
9997480b5ceSBram Moolenaar if (!quiet)
1000f9e3e09fSBram Moolenaar emsg(_(e_emptykey));
10017480b5ceSBram Moolenaar return NULL;
10028c711458SBram Moolenaar }
10038c711458SBram Moolenaar p = key + len;
10048c711458SBram Moolenaar }
10058c711458SBram Moolenaar else
10068c711458SBram Moolenaar {
10075d18efecSBram Moolenaar // Get the index [expr] or the first index [expr: ].
1008c70646c6SBram Moolenaar p = skipwhite(p + 1);
10096cc16197SBram Moolenaar if (*p == ':')
10106cc16197SBram Moolenaar empty1 = TRUE;
10116cc16197SBram Moolenaar else
10126cc16197SBram Moolenaar {
10136cc16197SBram Moolenaar empty1 = FALSE;
10145409f5d8SBram Moolenaar if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL) // recursive!
10157480b5ceSBram Moolenaar return NULL;
1016d155d7a8SBram Moolenaar if (tv_get_string_chk(&var1) == NULL)
10179ba0eb85SBram Moolenaar {
10185d18efecSBram Moolenaar // not a number or string
10199ba0eb85SBram Moolenaar clear_tv(&var1);
10209ba0eb85SBram Moolenaar return NULL;
10219ba0eb85SBram Moolenaar }
10226a250262SBram Moolenaar p = skipwhite(p);
10236cc16197SBram Moolenaar }
10246cc16197SBram Moolenaar
10255d18efecSBram Moolenaar // Optionally get the second index [ :expr].
10266cc16197SBram Moolenaar if (*p == ':')
10276cc16197SBram Moolenaar {
10287480b5ceSBram Moolenaar if (lp->ll_tv->v_type == VAR_DICT)
10298c711458SBram Moolenaar {
10307480b5ceSBram Moolenaar if (!quiet)
1031cc673e74SBram Moolenaar emsg(_(e_cannot_slice_dictionary));
10328c711458SBram Moolenaar clear_tv(&var1);
10337480b5ceSBram Moolenaar return NULL;
10348c711458SBram Moolenaar }
10356e5ea8d2SBram Moolenaar if (rettv != NULL
10366e5ea8d2SBram Moolenaar && !(rettv->v_type == VAR_LIST
1037c0f5a78cSBram Moolenaar && rettv->vval.v_list != NULL)
10386e5ea8d2SBram Moolenaar && !(rettv->v_type == VAR_BLOB
1039c0f5a78cSBram Moolenaar && rettv->vval.v_blob != NULL))
10406cc16197SBram Moolenaar {
10417480b5ceSBram Moolenaar if (!quiet)
1042f9e3e09fSBram Moolenaar emsg(_("E709: [:] requires a List or Blob value"));
10436cc16197SBram Moolenaar clear_tv(&var1);
10447480b5ceSBram Moolenaar return NULL;
10456cc16197SBram Moolenaar }
10466cc16197SBram Moolenaar p = skipwhite(p + 1);
10476cc16197SBram Moolenaar if (*p == ']')
10487480b5ceSBram Moolenaar lp->ll_empty2 = TRUE;
10496cc16197SBram Moolenaar else
10506cc16197SBram Moolenaar {
10517480b5ceSBram Moolenaar lp->ll_empty2 = FALSE;
105232e35117SBram Moolenaar // recursive!
10535409f5d8SBram Moolenaar if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL)
10546cc16197SBram Moolenaar {
10556cc16197SBram Moolenaar clear_tv(&var1);
10567480b5ceSBram Moolenaar return NULL;
10576cc16197SBram Moolenaar }
1058d155d7a8SBram Moolenaar if (tv_get_string_chk(&var2) == NULL)
10599ba0eb85SBram Moolenaar {
10605d18efecSBram Moolenaar // not a number or string
10619ba0eb85SBram Moolenaar clear_tv(&var1);
10629ba0eb85SBram Moolenaar clear_tv(&var2);
10639ba0eb85SBram Moolenaar return NULL;
10649ba0eb85SBram Moolenaar }
10656cc16197SBram Moolenaar }
10667480b5ceSBram Moolenaar lp->ll_range = TRUE;
10676cc16197SBram Moolenaar }
10686cc16197SBram Moolenaar else
10697480b5ceSBram Moolenaar lp->ll_range = FALSE;
10706cc16197SBram Moolenaar
1071c70646c6SBram Moolenaar if (*p != ']')
1072c70646c6SBram Moolenaar {
10737480b5ceSBram Moolenaar if (!quiet)
1074f9e3e09fSBram Moolenaar emsg(_(e_missbrac));
1075c70646c6SBram Moolenaar clear_tv(&var1);
10766cc16197SBram Moolenaar clear_tv(&var2);
10777480b5ceSBram Moolenaar return NULL;
1078c70646c6SBram Moolenaar }
10796cc16197SBram Moolenaar
10805d18efecSBram Moolenaar // Skip to past ']'.
10818c711458SBram Moolenaar ++p;
10828c711458SBram Moolenaar }
10838c711458SBram Moolenaar
10847480b5ceSBram Moolenaar if (lp->ll_tv->v_type == VAR_DICT)
10858c711458SBram Moolenaar {
10868c711458SBram Moolenaar if (len == -1)
10878c711458SBram Moolenaar {
10885d18efecSBram Moolenaar // "[key]": get key from "var1"
10895d18efecSBram Moolenaar key = tv_get_string_chk(&var1); // is number or string
10900921ecffSBram Moolenaar if (key == NULL)
10918c711458SBram Moolenaar {
10928c711458SBram Moolenaar clear_tv(&var1);
10937480b5ceSBram Moolenaar return NULL;
10948c711458SBram Moolenaar }
10958c711458SBram Moolenaar }
10969ef486dbSBram Moolenaar lp->ll_list = NULL;
109781ed4960SBram Moolenaar
109881ed4960SBram Moolenaar // a NULL dict is equivalent with an empty dict
109981ed4960SBram Moolenaar if (lp->ll_tv->vval.v_dict == NULL)
110081ed4960SBram Moolenaar {
110181ed4960SBram Moolenaar lp->ll_tv->vval.v_dict = dict_alloc();
110281ed4960SBram Moolenaar if (lp->ll_tv->vval.v_dict == NULL)
110381ed4960SBram Moolenaar {
110481ed4960SBram Moolenaar clear_tv(&var1);
110581ed4960SBram Moolenaar return NULL;
110681ed4960SBram Moolenaar }
110781ed4960SBram Moolenaar ++lp->ll_tv->vval.v_dict->dv_refcount;
110881ed4960SBram Moolenaar }
11099ef486dbSBram Moolenaar lp->ll_dict = lp->ll_tv->vval.v_dict;
111081ed4960SBram Moolenaar
1111ce5e58e6SBram Moolenaar lp->ll_di = dict_find(lp->ll_dict, key, len);
11124228bec0SBram Moolenaar
11135d18efecSBram Moolenaar // When assigning to a scope dictionary check that a function and
11145d18efecSBram Moolenaar // variable name is valid (only variable name unless it is l: or
11155d18efecSBram Moolenaar // g: dictionary). Disallow overwriting a builtin function.
1116bdb62056SBram Moolenaar if (rettv != NULL && lp->ll_dict->dv_scope != 0)
11174228bec0SBram Moolenaar {
1118bdb62056SBram Moolenaar int prevval;
1119bdb62056SBram Moolenaar int wrong;
1120bdb62056SBram Moolenaar
1121bdb62056SBram Moolenaar if (len != -1)
1122bdb62056SBram Moolenaar {
1123bdb62056SBram Moolenaar prevval = key[len];
1124bdb62056SBram Moolenaar key[len] = NUL;
1125bdb62056SBram Moolenaar }
11264380d1eaSBram Moolenaar else
11275d18efecSBram Moolenaar prevval = 0; // avoid compiler warning
1128bdb62056SBram Moolenaar wrong = (lp->ll_dict->dv_scope == VAR_DEF_SCOPE
1129bdb62056SBram Moolenaar && rettv->v_type == VAR_FUNC
113098b4f145SBram Moolenaar && var_wrong_func_name(key, lp->ll_di == NULL))
113103290b84SBram Moolenaar || !valid_varname(key, TRUE);
1132bdb62056SBram Moolenaar if (len != -1)
1133bdb62056SBram Moolenaar key[len] = prevval;
1134bdb62056SBram Moolenaar if (wrong)
1135ea04a6e8SBram Moolenaar {
1136ea04a6e8SBram Moolenaar clear_tv(&var1);
11374228bec0SBram Moolenaar return NULL;
11384228bec0SBram Moolenaar }
1139ea04a6e8SBram Moolenaar }
11404228bec0SBram Moolenaar
114110c65860SBram Moolenaar if (lp->ll_valtype != NULL)
114210c65860SBram Moolenaar // use the type of the member
114310c65860SBram Moolenaar lp->ll_valtype = lp->ll_valtype->tt_member;
114410c65860SBram Moolenaar
11457480b5ceSBram Moolenaar if (lp->ll_di == NULL)
11468c711458SBram Moolenaar {
114731b81604SBram Moolenaar // Can't add "v:" or "a:" variable.
1148da6c0334SBram Moolenaar if (lp->ll_dict == get_vimvar_dict()
114931b81604SBram Moolenaar || &lp->ll_dict->dv_hashtab == get_funccal_args_ht())
11504228bec0SBram Moolenaar {
1151f9e3e09fSBram Moolenaar semsg(_(e_illvar), name);
1152ab89d7abSBram Moolenaar clear_tv(&var1);
11534228bec0SBram Moolenaar return NULL;
11544228bec0SBram Moolenaar }
11554228bec0SBram Moolenaar
115631b81604SBram Moolenaar // Key does not exist in dict: may need to add it.
11577480b5ceSBram Moolenaar if (*p == '[' || *p == '.' || unlet)
11588c711458SBram Moolenaar {
11597480b5ceSBram Moolenaar if (!quiet)
1160f9e3e09fSBram Moolenaar semsg(_(e_dictkey), key);
11618c711458SBram Moolenaar clear_tv(&var1);
11627480b5ceSBram Moolenaar return NULL;
11638c711458SBram Moolenaar }
11648c711458SBram Moolenaar if (len == -1)
11657480b5ceSBram Moolenaar lp->ll_newkey = vim_strsave(key);
11668c711458SBram Moolenaar else
11677480b5ceSBram Moolenaar lp->ll_newkey = vim_strnsave(key, len);
11688c711458SBram Moolenaar clear_tv(&var1);
11697480b5ceSBram Moolenaar if (lp->ll_newkey == NULL)
11708c711458SBram Moolenaar p = NULL;
11718c711458SBram Moolenaar break;
11728c711458SBram Moolenaar }
11735d18efecSBram Moolenaar // existing variable, need to check if it can be changed
11743a257737SBram Moolenaar else if ((flags & GLV_READ_ONLY) == 0
1175a187c43cSBram Moolenaar && (var_check_ro(lp->ll_di->di_flags, name, FALSE)
1176a187c43cSBram Moolenaar || var_check_lock(lp->ll_di->di_flags, name, FALSE)))
117749439c4cSBram Moolenaar {
117849439c4cSBram Moolenaar clear_tv(&var1);
11794228bec0SBram Moolenaar return NULL;
118049439c4cSBram Moolenaar }
11814228bec0SBram Moolenaar
11828c711458SBram Moolenaar clear_tv(&var1);
11837480b5ceSBram Moolenaar lp->ll_tv = &lp->ll_di->di_tv;
11848c711458SBram Moolenaar }
11856e5ea8d2SBram Moolenaar else if (lp->ll_tv->v_type == VAR_BLOB)
11866e5ea8d2SBram Moolenaar {
1187c0f5a78cSBram Moolenaar long bloblen = blob_len(lp->ll_tv->vval.v_blob);
1188c0f5a78cSBram Moolenaar
11896e5ea8d2SBram Moolenaar /*
11906e5ea8d2SBram Moolenaar * Get the number and item for the only or first index of the List.
11916e5ea8d2SBram Moolenaar */
11926e5ea8d2SBram Moolenaar if (empty1)
11936e5ea8d2SBram Moolenaar lp->ll_n1 = 0;
11946e5ea8d2SBram Moolenaar else
11956e5ea8d2SBram Moolenaar // is number or string
11966e5ea8d2SBram Moolenaar lp->ll_n1 = (long)tv_get_number(&var1);
11976e5ea8d2SBram Moolenaar clear_tv(&var1);
11986e5ea8d2SBram Moolenaar
1199bd6406f1SBram Moolenaar if (check_blob_index(bloblen, lp->ll_n1, quiet) == FAIL)
12006e5ea8d2SBram Moolenaar {
1201c0f5a78cSBram Moolenaar clear_tv(&var2);
12026e5ea8d2SBram Moolenaar return NULL;
12036e5ea8d2SBram Moolenaar }
12046e5ea8d2SBram Moolenaar if (lp->ll_range && !lp->ll_empty2)
12056e5ea8d2SBram Moolenaar {
12066e5ea8d2SBram Moolenaar lp->ll_n2 = (long)tv_get_number(&var2);
12076e5ea8d2SBram Moolenaar clear_tv(&var2);
12080e3ff191SBram Moolenaar if (check_blob_range(bloblen, lp->ll_n1, lp->ll_n2, quiet)
12090e3ff191SBram Moolenaar == FAIL)
1210c0f5a78cSBram Moolenaar return NULL;
1211c0f5a78cSBram Moolenaar }
12126e5ea8d2SBram Moolenaar lp->ll_blob = lp->ll_tv->vval.v_blob;
12136e5ea8d2SBram Moolenaar lp->ll_tv = NULL;
121461be3763SBram Moolenaar break;
12156e5ea8d2SBram Moolenaar }
12168c711458SBram Moolenaar else
12178c711458SBram Moolenaar {
12186cc16197SBram Moolenaar /*
12198c711458SBram Moolenaar * Get the number and item for the only or first index of the List.
12206cc16197SBram Moolenaar */
12216cc16197SBram Moolenaar if (empty1)
12227480b5ceSBram Moolenaar lp->ll_n1 = 0;
12236cc16197SBram Moolenaar else
12245d18efecSBram Moolenaar // is number or string
1225d155d7a8SBram Moolenaar lp->ll_n1 = (long)tv_get_number(&var1);
1226c70646c6SBram Moolenaar clear_tv(&var1);
1227f06e5a54SBram Moolenaar
12289ef486dbSBram Moolenaar lp->ll_dict = NULL;
12297480b5ceSBram Moolenaar lp->ll_list = lp->ll_tv->vval.v_list;
12304f0884d6SBram Moolenaar lp->ll_li = check_range_index_one(lp->ll_list, &lp->ll_n1, quiet);
1231e65081d1SBram Moolenaar if (lp->ll_li == NULL)
1232e65081d1SBram Moolenaar {
12336cc16197SBram Moolenaar clear_tv(&var2);
12347480b5ceSBram Moolenaar return NULL;
12356cc16197SBram Moolenaar }
12366cc16197SBram Moolenaar
123710c65860SBram Moolenaar if (lp->ll_valtype != NULL)
123810c65860SBram Moolenaar // use the type of the member
123910c65860SBram Moolenaar lp->ll_valtype = lp->ll_valtype->tt_member;
124010c65860SBram Moolenaar
12416cc16197SBram Moolenaar /*
12428c711458SBram Moolenaar * May need to find the item or absolute index for the second
12438c711458SBram Moolenaar * index of a range.
12447480b5ceSBram Moolenaar * When no index given: "lp->ll_empty2" is TRUE.
12457480b5ceSBram Moolenaar * Otherwise "lp->ll_n2" is set to the second index.
12466cc16197SBram Moolenaar */
12477480b5ceSBram Moolenaar if (lp->ll_range && !lp->ll_empty2)
12486cc16197SBram Moolenaar {
1249d155d7a8SBram Moolenaar lp->ll_n2 = (long)tv_get_number(&var2);
12505d18efecSBram Moolenaar // is number or string
12516cc16197SBram Moolenaar clear_tv(&var2);
12524f0884d6SBram Moolenaar if (check_range_index_two(lp->ll_list,
12534f0884d6SBram Moolenaar &lp->ll_n1, lp->ll_li,
12544f0884d6SBram Moolenaar &lp->ll_n2, quiet) == FAIL)
12557480b5ceSBram Moolenaar return NULL;
1256e962388eSBram Moolenaar }
12576cc16197SBram Moolenaar
12587480b5ceSBram Moolenaar lp->ll_tv = &lp->ll_li->li_tv;
12598c711458SBram Moolenaar }
1260c70646c6SBram Moolenaar }
1261c70646c6SBram Moolenaar
1262f06e5a54SBram Moolenaar clear_tv(&var1);
12638a7d6542SBram Moolenaar lp->ll_name_end = p;
12647480b5ceSBram Moolenaar return p;
1265c70646c6SBram Moolenaar }
12667480b5ceSBram Moolenaar
12677480b5ceSBram Moolenaar /*
126833570924SBram Moolenaar * Clear lval "lp" that was filled by get_lval().
12697480b5ceSBram Moolenaar */
1270a9b579f3SBram Moolenaar void
clear_lval(lval_T * lp)12717454a06eSBram Moolenaar clear_lval(lval_T *lp)
12727480b5ceSBram Moolenaar {
12737480b5ceSBram Moolenaar vim_free(lp->ll_exp_name);
12747480b5ceSBram Moolenaar vim_free(lp->ll_newkey);
12757480b5ceSBram Moolenaar }
12767480b5ceSBram Moolenaar
12777480b5ceSBram Moolenaar /*
12782e6aff38SBram Moolenaar * Set a variable that was parsed by get_lval() to "rettv".
12797480b5ceSBram Moolenaar * "endp" points to just after the parsed name.
1280ff697e6cSBram Moolenaar * "op" is NULL, "+" for "+=", "-" for "-=", "*" for "*=", "/" for "/=",
1281ff697e6cSBram Moolenaar * "%" for "%=", "." for ".=" or "=" for "=".
12827480b5ceSBram Moolenaar */
12830522ba03SBram Moolenaar void
set_var_lval(lval_T * lp,char_u * endp,typval_T * rettv,int copy,int flags,char_u * op,int var_idx)12847454a06eSBram Moolenaar set_var_lval(
12857454a06eSBram Moolenaar lval_T *lp,
12867454a06eSBram Moolenaar char_u *endp,
12877454a06eSBram Moolenaar typval_T *rettv,
12887454a06eSBram Moolenaar int copy,
128930fd8204SBram Moolenaar int flags, // ASSIGN_CONST, ASSIGN_NO_DECL
1290f785aa13SBram Moolenaar char_u *op,
1291f785aa13SBram Moolenaar int var_idx) // index for "let [a, b] = list"
12927480b5ceSBram Moolenaar {
12937480b5ceSBram Moolenaar int cc;
129433570924SBram Moolenaar dictitem_T *di;
12957480b5ceSBram Moolenaar
12967480b5ceSBram Moolenaar if (lp->ll_tv == NULL)
12977480b5ceSBram Moolenaar {
12987480b5ceSBram Moolenaar cc = *endp;
12997480b5ceSBram Moolenaar *endp = NUL;
1300d0edaf9dSBram Moolenaar if (in_vim9script() && check_reserved_name(lp->ll_name) == FAIL)
1301d0edaf9dSBram Moolenaar return;
1302d0edaf9dSBram Moolenaar
13036e5ea8d2SBram Moolenaar if (lp->ll_blob != NULL)
13046e5ea8d2SBram Moolenaar {
13056e5ea8d2SBram Moolenaar int error = FALSE, val;
1306c0f5a78cSBram Moolenaar
13079ef486dbSBram Moolenaar if (op != NULL && *op != '=')
13089ef486dbSBram Moolenaar {
1309f9e3e09fSBram Moolenaar semsg(_(e_letwrong), op);
13106e5ea8d2SBram Moolenaar return;
13116e5ea8d2SBram Moolenaar }
1312a187c43cSBram Moolenaar if (value_check_lock(lp->ll_blob->bv_lock, lp->ll_name, FALSE))
1313021bda56SBram Moolenaar return;
13146e5ea8d2SBram Moolenaar
13156e5ea8d2SBram Moolenaar if (lp->ll_range && rettv->v_type == VAR_BLOB)
13166e5ea8d2SBram Moolenaar {
1317c0f5a78cSBram Moolenaar if (lp->ll_empty2)
1318c0f5a78cSBram Moolenaar lp->ll_n2 = blob_len(lp->ll_blob) - 1;
1319c0f5a78cSBram Moolenaar
132068452177SBram Moolenaar if (blob_set_range(lp->ll_blob, lp->ll_n1, lp->ll_n2,
132168452177SBram Moolenaar rettv) == FAIL)
13226e5ea8d2SBram Moolenaar return;
13236e5ea8d2SBram Moolenaar }
13246e5ea8d2SBram Moolenaar else
13256e5ea8d2SBram Moolenaar {
13266e5ea8d2SBram Moolenaar val = (int)tv_get_number_chk(rettv, &error);
13276e5ea8d2SBram Moolenaar if (!error)
1328e8209b91SBram Moolenaar blob_set_append(lp->ll_blob, lp->ll_n1, val);
13296e5ea8d2SBram Moolenaar }
13306e5ea8d2SBram Moolenaar }
13316e5ea8d2SBram Moolenaar else if (op != NULL && *op != '=')
13326e5ea8d2SBram Moolenaar {
133333570924SBram Moolenaar typval_T tv;
13349ef486dbSBram Moolenaar
1335f6a8d420SBram Moolenaar if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1336f6a8d420SBram Moolenaar && (flags & ASSIGN_FOR_LOOP) == 0)
13379937a055SBram Moolenaar {
13389937a055SBram Moolenaar emsg(_(e_cannot_mod));
13399937a055SBram Moolenaar *endp = cc;
13409937a055SBram Moolenaar return;
13419937a055SBram Moolenaar }
13429937a055SBram Moolenaar
1343ff697e6cSBram Moolenaar // handle +=, -=, *=, /=, %= and .=
13441cd5e613SBram Moolenaar di = NULL;
13459a78e6dfSBram Moolenaar if (eval_variable(lp->ll_name, (int)STRLEN(lp->ll_name),
1346cb4e80faSBram Moolenaar &tv, &di, EVAL_VAR_VERBOSE) == OK)
13479ef486dbSBram Moolenaar {
13481cd5e613SBram Moolenaar if ((di == NULL
13491cd5e613SBram Moolenaar || (!var_check_ro(di->di_flags, lp->ll_name, FALSE)
135005c00c03SBram Moolenaar && !tv_check_lock(&di->di_tv, lp->ll_name, FALSE)))
13511cd5e613SBram Moolenaar && tv_op(&tv, rettv, op) == OK)
135224e93165SBram Moolenaar set_var_const(lp->ll_name, NULL, &tv, FALSE,
135324e93165SBram Moolenaar ASSIGN_NO_DECL, 0);
13549ef486dbSBram Moolenaar clear_tv(&tv);
13559ef486dbSBram Moolenaar }
13569ef486dbSBram Moolenaar }
13579ef486dbSBram Moolenaar else
13584cdb13ceSBram Moolenaar {
13597a3fe3e1SBram Moolenaar if (lp->ll_type != NULL && check_typval_arg_type(lp->ll_type, rettv,
13607a3fe3e1SBram Moolenaar NULL, 0) == FAIL)
13614cdb13ceSBram Moolenaar return;
1362f785aa13SBram Moolenaar set_var_const(lp->ll_name, lp->ll_type, rettv, copy,
1363f785aa13SBram Moolenaar flags, var_idx);
13644cdb13ceSBram Moolenaar }
13657480b5ceSBram Moolenaar *endp = cc;
13667480b5ceSBram Moolenaar }
1367a187c43cSBram Moolenaar else if (value_check_lock(lp->ll_newkey == NULL
13682e6aff38SBram Moolenaar ? lp->ll_tv->v_lock
136977354e78SBram Moolenaar : lp->ll_tv->vval.v_dict->dv_lock, lp->ll_name, FALSE))
13702e6aff38SBram Moolenaar ;
13717480b5ceSBram Moolenaar else if (lp->ll_range)
13726cc16197SBram Moolenaar {
1373f6a8d420SBram Moolenaar if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1374f6a8d420SBram Moolenaar && (flags & ASSIGN_FOR_LOOP) == 0)
13759937a055SBram Moolenaar {
13769937a055SBram Moolenaar emsg(_("E996: Cannot lock a range"));
13779937a055SBram Moolenaar return;
13789937a055SBram Moolenaar }
13799937a055SBram Moolenaar
13804f0884d6SBram Moolenaar (void)list_assign_range(lp->ll_list, rettv->vval.v_list,
13814f0884d6SBram Moolenaar lp->ll_n1, lp->ll_n2, lp->ll_empty2, op, lp->ll_name);
13826cc16197SBram Moolenaar }
1383c70646c6SBram Moolenaar else
1384c70646c6SBram Moolenaar {
13857480b5ceSBram Moolenaar /*
13867480b5ceSBram Moolenaar * Assign to a List or Dictionary item.
13877480b5ceSBram Moolenaar */
1388f6a8d420SBram Moolenaar if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1389f6a8d420SBram Moolenaar && (flags & ASSIGN_FOR_LOOP) == 0)
13909937a055SBram Moolenaar {
13919937a055SBram Moolenaar emsg(_("E996: Cannot lock a list or dict"));
13929937a055SBram Moolenaar return;
13939937a055SBram Moolenaar }
139410c65860SBram Moolenaar
139510c65860SBram Moolenaar if (lp->ll_valtype != NULL
13967a3fe3e1SBram Moolenaar && check_typval_arg_type(lp->ll_valtype, rettv,
13977a3fe3e1SBram Moolenaar NULL, 0) == FAIL)
139810c65860SBram Moolenaar return;
139910c65860SBram Moolenaar
14007480b5ceSBram Moolenaar if (lp->ll_newkey != NULL)
14018c711458SBram Moolenaar {
14029ef486dbSBram Moolenaar if (op != NULL && *op != '=')
14039ef486dbSBram Moolenaar {
1404b9c0cd89SBram Moolenaar semsg(_(e_dictkey), lp->ll_newkey);
14059ef486dbSBram Moolenaar return;
14069ef486dbSBram Moolenaar }
14076f1d2aa4SBram Moolenaar if (dict_wrong_func_name(lp->ll_tv->vval.v_dict, rettv,
14086f1d2aa4SBram Moolenaar lp->ll_newkey))
14093d9c4eefSBram Moolenaar return;
14109ef486dbSBram Moolenaar
14115d18efecSBram Moolenaar // Need to add an item to the Dictionary.
1412ce5e58e6SBram Moolenaar di = dictitem_alloc(lp->ll_newkey);
14138c711458SBram Moolenaar if (di == NULL)
14147480b5ceSBram Moolenaar return;
1415ce5e58e6SBram Moolenaar if (dict_add(lp->ll_tv->vval.v_dict, di) == FAIL)
1416ce5e58e6SBram Moolenaar {
1417ce5e58e6SBram Moolenaar vim_free(di);
1418ce5e58e6SBram Moolenaar return;
1419ce5e58e6SBram Moolenaar }
14207480b5ceSBram Moolenaar lp->ll_tv = &di->di_tv;
14218c711458SBram Moolenaar }
14229ef486dbSBram Moolenaar else if (op != NULL && *op != '=')
14239ef486dbSBram Moolenaar {
14249ef486dbSBram Moolenaar tv_op(lp->ll_tv, rettv, op);
14259ef486dbSBram Moolenaar return;
14269ef486dbSBram Moolenaar }
14278c711458SBram Moolenaar else
14287480b5ceSBram Moolenaar clear_tv(lp->ll_tv);
14298c711458SBram Moolenaar
14306cc16197SBram Moolenaar /*
14316cc16197SBram Moolenaar * Assign the value to the variable or list item.
14326cc16197SBram Moolenaar */
1433c70646c6SBram Moolenaar if (copy)
14347480b5ceSBram Moolenaar copy_tv(rettv, lp->ll_tv);
1435c70646c6SBram Moolenaar else
1436c70646c6SBram Moolenaar {
14377480b5ceSBram Moolenaar *lp->ll_tv = *rettv;
1438758711c5SBram Moolenaar lp->ll_tv->v_lock = 0;
1439c70646c6SBram Moolenaar init_tv(rettv);
1440071d4279SBram Moolenaar }
1441071d4279SBram Moolenaar }
1442071d4279SBram Moolenaar }
1443071d4279SBram Moolenaar
14443d60ec2aSBram Moolenaar /*
1445ff697e6cSBram Moolenaar * Handle "tv1 += tv2", "tv1 -= tv2", "tv1 *= tv2", "tv1 /= tv2", "tv1 %= tv2"
1446ff697e6cSBram Moolenaar * and "tv1 .= tv2"
14479ef486dbSBram Moolenaar * Returns OK or FAIL.
14489ef486dbSBram Moolenaar */
14494f0884d6SBram Moolenaar int
tv_op(typval_T * tv1,typval_T * tv2,char_u * op)14507454a06eSBram Moolenaar tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
14519ef486dbSBram Moolenaar {
145222fcfad2SBram Moolenaar varnumber_T n;
14539ef486dbSBram Moolenaar char_u numbuf[NUMBUFLEN];
14549ef486dbSBram Moolenaar char_u *s;
1455c5f59fabSBram Moolenaar int failed = FALSE;
14569ef486dbSBram Moolenaar
1457f24f51d0SBram Moolenaar // Can't do anything with a Funcref or Dict on the right.
1458f24f51d0SBram Moolenaar // v:true and friends only work with "..=".
1459520e1e41SBram Moolenaar if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT
1460f24f51d0SBram Moolenaar && ((tv2->v_type != VAR_BOOL && tv2->v_type != VAR_SPECIAL)
1461f24f51d0SBram Moolenaar || *op == '.'))
14629ef486dbSBram Moolenaar {
14639ef486dbSBram Moolenaar switch (tv1->v_type)
14649ef486dbSBram Moolenaar {
1465835dc636SBram Moolenaar case VAR_UNKNOWN:
14664c683750SBram Moolenaar case VAR_ANY:
14678a7d6542SBram Moolenaar case VAR_VOID:
14689ef486dbSBram Moolenaar case VAR_DICT:
14699ef486dbSBram Moolenaar case VAR_FUNC:
14701735bc98SBram Moolenaar case VAR_PARTIAL:
14719b4a15d5SBram Moolenaar case VAR_BOOL:
1472520e1e41SBram Moolenaar case VAR_SPECIAL:
1473835dc636SBram Moolenaar case VAR_JOB:
14747707344dSBram Moolenaar case VAR_CHANNEL:
1475f18332fbSBram Moolenaar case VAR_INSTR:
14769ef486dbSBram Moolenaar break;
14779ef486dbSBram Moolenaar
14786e5ea8d2SBram Moolenaar case VAR_BLOB:
14796e5ea8d2SBram Moolenaar if (*op != '+' || tv2->v_type != VAR_BLOB)
14806e5ea8d2SBram Moolenaar break;
14816e5ea8d2SBram Moolenaar // BLOB += BLOB
14826e5ea8d2SBram Moolenaar if (tv1->vval.v_blob != NULL && tv2->vval.v_blob != NULL)
14836e5ea8d2SBram Moolenaar {
14846e5ea8d2SBram Moolenaar blob_T *b1 = tv1->vval.v_blob;
14856e5ea8d2SBram Moolenaar blob_T *b2 = tv2->vval.v_blob;
14866e5ea8d2SBram Moolenaar int i, len = blob_len(b2);
14876e5ea8d2SBram Moolenaar for (i = 0; i < len; i++)
14886e5ea8d2SBram Moolenaar ga_append(&b1->bv_ga, blob_get(b2, i));
14896e5ea8d2SBram Moolenaar }
14906e5ea8d2SBram Moolenaar return OK;
14916e5ea8d2SBram Moolenaar
14929ef486dbSBram Moolenaar case VAR_LIST:
14939ef486dbSBram Moolenaar if (*op != '+' || tv2->v_type != VAR_LIST)
14949ef486dbSBram Moolenaar break;
1495ff697e6cSBram Moolenaar // List += List
149681ed4960SBram Moolenaar if (tv2->vval.v_list != NULL)
149781ed4960SBram Moolenaar {
149881ed4960SBram Moolenaar if (tv1->vval.v_list == NULL)
149981ed4960SBram Moolenaar {
150081ed4960SBram Moolenaar tv1->vval.v_list = tv2->vval.v_list;
150181ed4960SBram Moolenaar ++tv1->vval.v_list->lv_refcount;
150281ed4960SBram Moolenaar }
150381ed4960SBram Moolenaar else
15049ef486dbSBram Moolenaar list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
150581ed4960SBram Moolenaar }
15069ef486dbSBram Moolenaar return OK;
15079ef486dbSBram Moolenaar
15089ef486dbSBram Moolenaar case VAR_NUMBER:
15099ef486dbSBram Moolenaar case VAR_STRING:
15109ef486dbSBram Moolenaar if (tv2->v_type == VAR_LIST)
15119ef486dbSBram Moolenaar break;
1512ff697e6cSBram Moolenaar if (vim_strchr((char_u *)"+-*/%", *op) != NULL)
15139ef486dbSBram Moolenaar {
1514ff697e6cSBram Moolenaar // nr += nr , nr -= nr , nr *=nr , nr /= nr , nr %= nr
1515d155d7a8SBram Moolenaar n = tv_get_number(tv1);
15168c8de839SBram Moolenaar #ifdef FEAT_FLOAT
15178c8de839SBram Moolenaar if (tv2->v_type == VAR_FLOAT)
15188c8de839SBram Moolenaar {
15198c8de839SBram Moolenaar float_T f = n;
15208c8de839SBram Moolenaar
1521ff697e6cSBram Moolenaar if (*op == '%')
1522ff697e6cSBram Moolenaar break;
1523ff697e6cSBram Moolenaar switch (*op)
1524ff697e6cSBram Moolenaar {
1525ff697e6cSBram Moolenaar case '+': f += tv2->vval.v_float; break;
1526ff697e6cSBram Moolenaar case '-': f -= tv2->vval.v_float; break;
1527ff697e6cSBram Moolenaar case '*': f *= tv2->vval.v_float; break;
1528ff697e6cSBram Moolenaar case '/': f /= tv2->vval.v_float; break;
1529ff697e6cSBram Moolenaar }
15308c8de839SBram Moolenaar clear_tv(tv1);
15318c8de839SBram Moolenaar tv1->v_type = VAR_FLOAT;
15328c8de839SBram Moolenaar tv1->vval.v_float = f;
15338c8de839SBram Moolenaar }
15348c8de839SBram Moolenaar else
15358c8de839SBram Moolenaar #endif
15368c8de839SBram Moolenaar {
1537ff697e6cSBram Moolenaar switch (*op)
1538ff697e6cSBram Moolenaar {
1539ff697e6cSBram Moolenaar case '+': n += tv_get_number(tv2); break;
1540ff697e6cSBram Moolenaar case '-': n -= tv_get_number(tv2); break;
1541ff697e6cSBram Moolenaar case '*': n *= tv_get_number(tv2); break;
1542c5f59fabSBram Moolenaar case '/': n = num_divide(n, tv_get_number(tv2),
1543c5f59fabSBram Moolenaar &failed); break;
1544c5f59fabSBram Moolenaar case '%': n = num_modulus(n, tv_get_number(tv2),
1545c5f59fabSBram Moolenaar &failed); break;
1546ff697e6cSBram Moolenaar }
15479ef486dbSBram Moolenaar clear_tv(tv1);
15489ef486dbSBram Moolenaar tv1->v_type = VAR_NUMBER;
15499ef486dbSBram Moolenaar tv1->vval.v_number = n;
15509ef486dbSBram Moolenaar }
15518c8de839SBram Moolenaar }
15529ef486dbSBram Moolenaar else
15539ef486dbSBram Moolenaar {
15548c8de839SBram Moolenaar if (tv2->v_type == VAR_FLOAT)
15558c8de839SBram Moolenaar break;
15568c8de839SBram Moolenaar
1557ff697e6cSBram Moolenaar // str .= str
1558d155d7a8SBram Moolenaar s = tv_get_string(tv1);
1559d155d7a8SBram Moolenaar s = concat_str(s, tv_get_string_buf(tv2, numbuf));
15609ef486dbSBram Moolenaar clear_tv(tv1);
15619ef486dbSBram Moolenaar tv1->v_type = VAR_STRING;
15629ef486dbSBram Moolenaar tv1->vval.v_string = s;
15639ef486dbSBram Moolenaar }
1564c5f59fabSBram Moolenaar return failed ? FAIL : OK;
15658c8de839SBram Moolenaar
15668c8de839SBram Moolenaar case VAR_FLOAT:
15675fac4674SBram Moolenaar #ifdef FEAT_FLOAT
15688c8de839SBram Moolenaar {
15698c8de839SBram Moolenaar float_T f;
15708c8de839SBram Moolenaar
1571ff697e6cSBram Moolenaar if (*op == '%' || *op == '.'
1572ff697e6cSBram Moolenaar || (tv2->v_type != VAR_FLOAT
15738c8de839SBram Moolenaar && tv2->v_type != VAR_NUMBER
15748c8de839SBram Moolenaar && tv2->v_type != VAR_STRING))
15758c8de839SBram Moolenaar break;
15768c8de839SBram Moolenaar if (tv2->v_type == VAR_FLOAT)
15778c8de839SBram Moolenaar f = tv2->vval.v_float;
15788c8de839SBram Moolenaar else
1579d155d7a8SBram Moolenaar f = tv_get_number(tv2);
1580ff697e6cSBram Moolenaar switch (*op)
1581ff697e6cSBram Moolenaar {
1582ff697e6cSBram Moolenaar case '+': tv1->vval.v_float += f; break;
1583ff697e6cSBram Moolenaar case '-': tv1->vval.v_float -= f; break;
1584ff697e6cSBram Moolenaar case '*': tv1->vval.v_float *= f; break;
1585ff697e6cSBram Moolenaar case '/': tv1->vval.v_float /= f; break;
1586ff697e6cSBram Moolenaar }
15878c8de839SBram Moolenaar }
15888c8de839SBram Moolenaar #endif
15895fac4674SBram Moolenaar return OK;
15909ef486dbSBram Moolenaar }
15919ef486dbSBram Moolenaar }
15929ef486dbSBram Moolenaar
1593f9e3e09fSBram Moolenaar semsg(_(e_letwrong), op);
15949ef486dbSBram Moolenaar return FAIL;
15959ef486dbSBram Moolenaar }
15969ef486dbSBram Moolenaar
15979ef486dbSBram Moolenaar /*
15983d60ec2aSBram Moolenaar * Evaluate the expression used in a ":for var in expr" command.
15993d60ec2aSBram Moolenaar * "arg" points to "var".
16003d60ec2aSBram Moolenaar * Set "*errp" to TRUE for an error, FALSE otherwise;
16013d60ec2aSBram Moolenaar * Return a pointer that holds the info. Null when there is an error.
16023d60ec2aSBram Moolenaar */
16033d60ec2aSBram Moolenaar void *
eval_for_line(char_u * arg,int * errp,exarg_T * eap,evalarg_T * evalarg)16047454a06eSBram Moolenaar eval_for_line(
16057454a06eSBram Moolenaar char_u *arg,
16067454a06eSBram Moolenaar int *errp,
1607b171fb17SBram Moolenaar exarg_T *eap,
1608b7a78f7aSBram Moolenaar evalarg_T *evalarg)
16093d60ec2aSBram Moolenaar {
161033570924SBram Moolenaar forinfo_T *fi;
1611404557e6SBram Moolenaar char_u *var_list_end;
16123d60ec2aSBram Moolenaar char_u *expr;
161333570924SBram Moolenaar typval_T tv;
161433570924SBram Moolenaar list_T *l;
1615b7a78f7aSBram Moolenaar int skip = !(evalarg->eval_flags & EVAL_EVALUATE);
16163d60ec2aSBram Moolenaar
16175d18efecSBram Moolenaar *errp = TRUE; // default: there is an error
16183d60ec2aSBram Moolenaar
1619c799fe20SBram Moolenaar fi = ALLOC_CLEAR_ONE(forinfo_T);
16203d60ec2aSBram Moolenaar if (fi == NULL)
16213d60ec2aSBram Moolenaar return NULL;
16223d60ec2aSBram Moolenaar
1623404557e6SBram Moolenaar var_list_end = skip_var_list(arg, TRUE, &fi->fi_varcount,
1624404557e6SBram Moolenaar &fi->fi_semicolon, FALSE);
1625404557e6SBram Moolenaar if (var_list_end == NULL)
16263d60ec2aSBram Moolenaar return fi;
16273d60ec2aSBram Moolenaar
1628404557e6SBram Moolenaar expr = skipwhite_and_linebreak(var_list_end, evalarg);
1629b7a78f7aSBram Moolenaar if (expr[0] != 'i' || expr[1] != 'n'
1630b7a78f7aSBram Moolenaar || !(expr[2] == NUL || VIM_ISWHITE(expr[2])))
16313d60ec2aSBram Moolenaar {
1632404557e6SBram Moolenaar if (in_vim9script() && *expr == ':' && expr != var_list_end)
1633404557e6SBram Moolenaar semsg(_(e_no_white_space_allowed_before_colon_str), expr);
1634404557e6SBram Moolenaar else
16358a7d6542SBram Moolenaar emsg(_(e_missing_in));
16363d60ec2aSBram Moolenaar return fi;
16373d60ec2aSBram Moolenaar }
16383d60ec2aSBram Moolenaar
16393d60ec2aSBram Moolenaar if (skip)
16403d60ec2aSBram Moolenaar ++emsg_skip;
1641b7a78f7aSBram Moolenaar expr = skipwhite_and_linebreak(expr + 2, evalarg);
1642b7a78f7aSBram Moolenaar if (eval0(expr, &tv, eap, evalarg) == OK)
16433d60ec2aSBram Moolenaar {
16443d60ec2aSBram Moolenaar *errp = FALSE;
16453d60ec2aSBram Moolenaar if (!skip)
16463d60ec2aSBram Moolenaar {
16476e5ea8d2SBram Moolenaar if (tv.v_type == VAR_LIST)
16486e5ea8d2SBram Moolenaar {
16493d60ec2aSBram Moolenaar l = tv.vval.v_list;
16506e5ea8d2SBram Moolenaar if (l == NULL)
1651f461c8e7SBram Moolenaar {
16526e5ea8d2SBram Moolenaar // a null list is like an empty list: do nothing
1653d8585edeSBram Moolenaar clear_tv(&tv);
1654d8585edeSBram Moolenaar }
16553d60ec2aSBram Moolenaar else
16563d60ec2aSBram Moolenaar {
16578a7d6542SBram Moolenaar // Need a real list here.
16587e9f351bSBram Moolenaar CHECK_LIST_MATERIALIZE(l);
16598a7d6542SBram Moolenaar
16606e5ea8d2SBram Moolenaar // No need to increment the refcount, it's already set for
16616e5ea8d2SBram Moolenaar // the list being used in "tv".
16623d60ec2aSBram Moolenaar fi->fi_list = l;
16633d60ec2aSBram Moolenaar list_add_watch(l, &fi->fi_lw);
16643d60ec2aSBram Moolenaar fi->fi_lw.lw_item = l->lv_first;
16653d60ec2aSBram Moolenaar }
16663d60ec2aSBram Moolenaar }
16676e5ea8d2SBram Moolenaar else if (tv.v_type == VAR_BLOB)
16686e5ea8d2SBram Moolenaar {
16696e5ea8d2SBram Moolenaar fi->fi_bi = 0;
1670dd29ea18SBram Moolenaar if (tv.vval.v_blob != NULL)
1671dd29ea18SBram Moolenaar {
1672dd29ea18SBram Moolenaar typval_T btv;
1673dd29ea18SBram Moolenaar
1674dd29ea18SBram Moolenaar // Make a copy, so that the iteration still works when the
1675dd29ea18SBram Moolenaar // blob is changed.
16768a7d6542SBram Moolenaar blob_copy(tv.vval.v_blob, &btv);
1677dd29ea18SBram Moolenaar fi->fi_blob = btv.vval.v_blob;
16786e5ea8d2SBram Moolenaar }
1679dd29ea18SBram Moolenaar clear_tv(&tv);
16806e5ea8d2SBram Moolenaar }
168174e54fcbSBram Moolenaar else if (tv.v_type == VAR_STRING)
168274e54fcbSBram Moolenaar {
168374e54fcbSBram Moolenaar fi->fi_byte_idx = 0;
168474e54fcbSBram Moolenaar fi->fi_string = tv.vval.v_string;
168574e54fcbSBram Moolenaar tv.vval.v_string = NULL;
168674e54fcbSBram Moolenaar if (fi->fi_string == NULL)
168774e54fcbSBram Moolenaar fi->fi_string = vim_strsave((char_u *)"");
168874e54fcbSBram Moolenaar }
16896e5ea8d2SBram Moolenaar else
16906e5ea8d2SBram Moolenaar {
169180d7395dSSean Dewar emsg(_(e_string_list_or_blob_required));
16926e5ea8d2SBram Moolenaar clear_tv(&tv);
16936e5ea8d2SBram Moolenaar }
16946e5ea8d2SBram Moolenaar }
16953d60ec2aSBram Moolenaar }
16963d60ec2aSBram Moolenaar if (skip)
16973d60ec2aSBram Moolenaar --emsg_skip;
1698b7a78f7aSBram Moolenaar fi->fi_break_count = evalarg->eval_break_count;
16993d60ec2aSBram Moolenaar
17003d60ec2aSBram Moolenaar return fi;
17013d60ec2aSBram Moolenaar }
17023d60ec2aSBram Moolenaar
17033d60ec2aSBram Moolenaar /*
1704b7a78f7aSBram Moolenaar * Used when looping over a :for line, skip the "in expr" part.
1705b7a78f7aSBram Moolenaar */
1706b7a78f7aSBram Moolenaar void
skip_for_lines(void * fi_void,evalarg_T * evalarg)1707b7a78f7aSBram Moolenaar skip_for_lines(void *fi_void, evalarg_T *evalarg)
1708b7a78f7aSBram Moolenaar {
1709b7a78f7aSBram Moolenaar forinfo_T *fi = (forinfo_T *)fi_void;
1710b7a78f7aSBram Moolenaar int i;
1711b7a78f7aSBram Moolenaar
1712b7a78f7aSBram Moolenaar for (i = 0; i < fi->fi_break_count; ++i)
1713b7a78f7aSBram Moolenaar eval_next_line(evalarg);
1714b7a78f7aSBram Moolenaar }
1715b7a78f7aSBram Moolenaar
1716b7a78f7aSBram Moolenaar /*
17173d60ec2aSBram Moolenaar * Use the first item in a ":for" list. Advance to the next.
17183d60ec2aSBram Moolenaar * Assign the values to the variable (list). "arg" points to the first one.
17193d60ec2aSBram Moolenaar * Return TRUE when a valid item was found, FALSE when at end of list or
17203d60ec2aSBram Moolenaar * something wrong.
17213d60ec2aSBram Moolenaar */
17223d60ec2aSBram Moolenaar int
next_for_item(void * fi_void,char_u * arg)17237454a06eSBram Moolenaar next_for_item(void *fi_void, char_u *arg)
17243d60ec2aSBram Moolenaar {
172533570924SBram Moolenaar forinfo_T *fi = (forinfo_T *)fi_void;
17263d60ec2aSBram Moolenaar int result;
1727f6a8d420SBram Moolenaar int flag = ASSIGN_FOR_LOOP | (in_vim9script()
1728442b29c9SBram Moolenaar ? (ASSIGN_FINAL
1729442b29c9SBram Moolenaar // first round: error if variable exists
1730442b29c9SBram Moolenaar | (fi->fi_bi == 0 ? 0 : ASSIGN_DECL)
1731442b29c9SBram Moolenaar | ASSIGN_NO_MEMBER_TYPE)
1732f6a8d420SBram Moolenaar : 0);
173333570924SBram Moolenaar listitem_T *item;
1734ad2d4969SBram Moolenaar int skip_assign = in_vim9script() && arg[0] == '_'
1735ad2d4969SBram Moolenaar && !eval_isnamec(arg[1]);
17363d60ec2aSBram Moolenaar
17376e5ea8d2SBram Moolenaar if (fi->fi_blob != NULL)
17386e5ea8d2SBram Moolenaar {
17396e5ea8d2SBram Moolenaar typval_T tv;
17406e5ea8d2SBram Moolenaar
17416e5ea8d2SBram Moolenaar if (fi->fi_bi >= blob_len(fi->fi_blob))
17426e5ea8d2SBram Moolenaar return FALSE;
17436e5ea8d2SBram Moolenaar tv.v_type = VAR_NUMBER;
17446e5ea8d2SBram Moolenaar tv.v_lock = VAR_FIXED;
17456e5ea8d2SBram Moolenaar tv.vval.v_number = blob_get(fi->fi_blob, fi->fi_bi);
17466e5ea8d2SBram Moolenaar ++fi->fi_bi;
1747ad2d4969SBram Moolenaar if (skip_assign)
1748ad2d4969SBram Moolenaar return TRUE;
17499937a055SBram Moolenaar return ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon,
175041fe0617SBram Moolenaar fi->fi_varcount, flag, NULL) == OK;
17516e5ea8d2SBram Moolenaar }
17526e5ea8d2SBram Moolenaar
175374e54fcbSBram Moolenaar if (fi->fi_string != NULL)
175474e54fcbSBram Moolenaar {
175574e54fcbSBram Moolenaar typval_T tv;
175674e54fcbSBram Moolenaar int len;
175774e54fcbSBram Moolenaar
175874e54fcbSBram Moolenaar len = mb_ptr2len(fi->fi_string + fi->fi_byte_idx);
175974e54fcbSBram Moolenaar if (len == 0)
176074e54fcbSBram Moolenaar return FALSE;
176174e54fcbSBram Moolenaar tv.v_type = VAR_STRING;
176274e54fcbSBram Moolenaar tv.v_lock = VAR_FIXED;
176374e54fcbSBram Moolenaar tv.vval.v_string = vim_strnsave(fi->fi_string + fi->fi_byte_idx, len);
176474e54fcbSBram Moolenaar fi->fi_byte_idx += len;
1765442b29c9SBram Moolenaar ++fi->fi_bi;
1766ad2d4969SBram Moolenaar if (skip_assign)
1767ad2d4969SBram Moolenaar result = TRUE;
1768ad2d4969SBram Moolenaar else
1769bb5d87c8SBram Moolenaar result = ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon,
177074e54fcbSBram Moolenaar fi->fi_varcount, flag, NULL) == OK;
1771bb5d87c8SBram Moolenaar vim_free(tv.vval.v_string);
1772bb5d87c8SBram Moolenaar return result;
177374e54fcbSBram Moolenaar }
177474e54fcbSBram Moolenaar
17753d60ec2aSBram Moolenaar item = fi->fi_lw.lw_item;
17763d60ec2aSBram Moolenaar if (item == NULL)
17773d60ec2aSBram Moolenaar result = FALSE;
17783d60ec2aSBram Moolenaar else
17793d60ec2aSBram Moolenaar {
17803d60ec2aSBram Moolenaar fi->fi_lw.lw_item = item->li_next;
1781442b29c9SBram Moolenaar ++fi->fi_bi;
1782ad2d4969SBram Moolenaar if (skip_assign)
1783ad2d4969SBram Moolenaar result = TRUE;
1784ad2d4969SBram Moolenaar else
17859937a055SBram Moolenaar result = (ex_let_vars(arg, &item->li_tv, TRUE, fi->fi_semicolon,
178641fe0617SBram Moolenaar fi->fi_varcount, flag, NULL) == OK);
17873d60ec2aSBram Moolenaar }
17883d60ec2aSBram Moolenaar return result;
17893d60ec2aSBram Moolenaar }
17903d60ec2aSBram Moolenaar
17913d60ec2aSBram Moolenaar /*
17923d60ec2aSBram Moolenaar * Free the structure used to store info used by ":for".
17933d60ec2aSBram Moolenaar */
17943d60ec2aSBram Moolenaar void
free_for_info(void * fi_void)17957454a06eSBram Moolenaar free_for_info(void *fi_void)
17963d60ec2aSBram Moolenaar {
179733570924SBram Moolenaar forinfo_T *fi = (forinfo_T *)fi_void;
17983d60ec2aSBram Moolenaar
179974e54fcbSBram Moolenaar if (fi == NULL)
180074e54fcbSBram Moolenaar return;
180174e54fcbSBram Moolenaar if (fi->fi_list != NULL)
1802f461c8e7SBram Moolenaar {
18033d60ec2aSBram Moolenaar list_rem_watch(fi->fi_list, &fi->fi_lw);
1804f461c8e7SBram Moolenaar list_unref(fi->fi_list);
1805f461c8e7SBram Moolenaar }
180674e54fcbSBram Moolenaar else if (fi->fi_blob != NULL)
1807ecc8bc48SBram Moolenaar blob_unref(fi->fi_blob);
180874e54fcbSBram Moolenaar else
180974e54fcbSBram Moolenaar vim_free(fi->fi_string);
18103d60ec2aSBram Moolenaar vim_free(fi);
18113d60ec2aSBram Moolenaar }
18123d60ec2aSBram Moolenaar
1813071d4279SBram Moolenaar void
set_context_for_expression(expand_T * xp,char_u * arg,cmdidx_T cmdidx)18147454a06eSBram Moolenaar set_context_for_expression(
18157454a06eSBram Moolenaar expand_T *xp,
18167454a06eSBram Moolenaar char_u *arg,
18177454a06eSBram Moolenaar cmdidx_T cmdidx)
1818071d4279SBram Moolenaar {
181930fd8204SBram Moolenaar int has_expr = cmdidx != CMD_let && cmdidx != CMD_var;
1820071d4279SBram Moolenaar int c;
18213d60ec2aSBram Moolenaar char_u *p;
1822071d4279SBram Moolenaar
182330fd8204SBram Moolenaar if (cmdidx == CMD_let || cmdidx == CMD_var
182430fd8204SBram Moolenaar || cmdidx == CMD_const || cmdidx == CMD_final)
18253d60ec2aSBram Moolenaar {
18263d60ec2aSBram Moolenaar xp->xp_context = EXPAND_USER_VARS;
18272a8d1f87SBram Moolenaar if (vim_strpbrk(arg, (char_u *)"\"'+-*/%.=!?~|&$([<>,#") == NULL)
18283d60ec2aSBram Moolenaar {
18295d18efecSBram Moolenaar // ":let var1 var2 ...": find last space.
18302a8d1f87SBram Moolenaar for (p = arg + STRLEN(arg); p >= arg; )
18313d60ec2aSBram Moolenaar {
18323d60ec2aSBram Moolenaar xp->xp_pattern = p;
183391acfffcSBram Moolenaar MB_PTR_BACK(arg, p);
18341c465444SBram Moolenaar if (VIM_ISWHITE(*p))
18353d60ec2aSBram Moolenaar break;
18363d60ec2aSBram Moolenaar }
18373d60ec2aSBram Moolenaar return;
18383d60ec2aSBram Moolenaar }
18393d60ec2aSBram Moolenaar }
18403d60ec2aSBram Moolenaar else
18413d60ec2aSBram Moolenaar xp->xp_context = cmdidx == CMD_call ? EXPAND_FUNCTIONS
1842071d4279SBram Moolenaar : EXPAND_EXPRESSION;
1843071d4279SBram Moolenaar while ((xp->xp_pattern = vim_strpbrk(arg,
1844071d4279SBram Moolenaar (char_u *)"\"'+-*/%.=!?~|&$([<>,#")) != NULL)
1845071d4279SBram Moolenaar {
1846071d4279SBram Moolenaar c = *xp->xp_pattern;
1847071d4279SBram Moolenaar if (c == '&')
1848071d4279SBram Moolenaar {
1849071d4279SBram Moolenaar c = xp->xp_pattern[1];
1850071d4279SBram Moolenaar if (c == '&')
1851071d4279SBram Moolenaar {
1852071d4279SBram Moolenaar ++xp->xp_pattern;
185330fd8204SBram Moolenaar xp->xp_context = has_expr ? EXPAND_EXPRESSION : EXPAND_NOTHING;
1854071d4279SBram Moolenaar }
1855071d4279SBram Moolenaar else if (c != ' ')
185611cbeb13SBram Moolenaar {
1857071d4279SBram Moolenaar xp->xp_context = EXPAND_SETTINGS;
185811cbeb13SBram Moolenaar if ((c == 'l' || c == 'g') && xp->xp_pattern[2] == ':')
185911cbeb13SBram Moolenaar xp->xp_pattern += 2;
186011cbeb13SBram Moolenaar
186111cbeb13SBram Moolenaar }
1862071d4279SBram Moolenaar }
1863071d4279SBram Moolenaar else if (c == '$')
1864071d4279SBram Moolenaar {
18655d18efecSBram Moolenaar // environment variable
1866071d4279SBram Moolenaar xp->xp_context = EXPAND_ENV_VARS;
1867071d4279SBram Moolenaar }
1868071d4279SBram Moolenaar else if (c == '=')
1869071d4279SBram Moolenaar {
187030fd8204SBram Moolenaar has_expr = TRUE;
1871071d4279SBram Moolenaar xp->xp_context = EXPAND_EXPRESSION;
1872071d4279SBram Moolenaar }
1873a32095fcSBram Moolenaar else if (c == '#'
1874a32095fcSBram Moolenaar && xp->xp_context == EXPAND_EXPRESSION)
1875a32095fcSBram Moolenaar {
18765d18efecSBram Moolenaar // Autoload function/variable contains '#'.
1877a32095fcSBram Moolenaar break;
1878a32095fcSBram Moolenaar }
18798a349ff9SBram Moolenaar else if ((c == '<' || c == '#')
1880071d4279SBram Moolenaar && xp->xp_context == EXPAND_FUNCTIONS
1881071d4279SBram Moolenaar && vim_strchr(xp->xp_pattern, '(') == NULL)
1882071d4279SBram Moolenaar {
18835d18efecSBram Moolenaar // Function name can start with "<SNR>" and contain '#'.
1884071d4279SBram Moolenaar break;
1885071d4279SBram Moolenaar }
188630fd8204SBram Moolenaar else if (has_expr)
1887071d4279SBram Moolenaar {
18885d18efecSBram Moolenaar if (c == '"') // string
1889071d4279SBram Moolenaar {
1890071d4279SBram Moolenaar while ((c = *++xp->xp_pattern) != NUL && c != '"')
1891071d4279SBram Moolenaar if (c == '\\' && xp->xp_pattern[1] != NUL)
1892071d4279SBram Moolenaar ++xp->xp_pattern;
1893071d4279SBram Moolenaar xp->xp_context = EXPAND_NOTHING;
1894071d4279SBram Moolenaar }
18955d18efecSBram Moolenaar else if (c == '\'') // literal string
1896071d4279SBram Moolenaar {
18975d18efecSBram Moolenaar // Trick: '' is like stopping and starting a literal string.
1898071d4279SBram Moolenaar while ((c = *++xp->xp_pattern) != NUL && c != '\'')
1899071d4279SBram Moolenaar /* skip */ ;
1900071d4279SBram Moolenaar xp->xp_context = EXPAND_NOTHING;
1901071d4279SBram Moolenaar }
1902071d4279SBram Moolenaar else if (c == '|')
1903071d4279SBram Moolenaar {
1904071d4279SBram Moolenaar if (xp->xp_pattern[1] == '|')
1905071d4279SBram Moolenaar {
1906071d4279SBram Moolenaar ++xp->xp_pattern;
1907071d4279SBram Moolenaar xp->xp_context = EXPAND_EXPRESSION;
1908071d4279SBram Moolenaar }
1909071d4279SBram Moolenaar else
1910071d4279SBram Moolenaar xp->xp_context = EXPAND_COMMANDS;
1911071d4279SBram Moolenaar }
1912071d4279SBram Moolenaar else
1913071d4279SBram Moolenaar xp->xp_context = EXPAND_EXPRESSION;
1914071d4279SBram Moolenaar }
1915071d4279SBram Moolenaar else
19165d18efecSBram Moolenaar // Doesn't look like something valid, expand as an expression
19175d18efecSBram Moolenaar // anyway.
19183d60ec2aSBram Moolenaar xp->xp_context = EXPAND_EXPRESSION;
1919071d4279SBram Moolenaar arg = xp->xp_pattern;
1920071d4279SBram Moolenaar if (*arg != NUL)
1921071d4279SBram Moolenaar while ((c = *++arg) != NUL && (c == ' ' || c == '\t'))
1922071d4279SBram Moolenaar /* skip */ ;
1923071d4279SBram Moolenaar }
19244941b5efSBram Moolenaar
19254941b5efSBram Moolenaar // ":exe one two" completes "two"
19264941b5efSBram Moolenaar if ((cmdidx == CMD_execute
19274941b5efSBram Moolenaar || cmdidx == CMD_echo
19284941b5efSBram Moolenaar || cmdidx == CMD_echon
19294941b5efSBram Moolenaar || cmdidx == CMD_echomsg)
19304941b5efSBram Moolenaar && xp->xp_context == EXPAND_EXPRESSION)
19314941b5efSBram Moolenaar {
19324941b5efSBram Moolenaar for (;;)
19334941b5efSBram Moolenaar {
19344941b5efSBram Moolenaar char_u *n = skiptowhite(arg);
19354941b5efSBram Moolenaar
19364941b5efSBram Moolenaar if (n == arg || IS_WHITE_OR_NUL(*skipwhite(n)))
19374941b5efSBram Moolenaar break;
19384941b5efSBram Moolenaar arg = skipwhite(n);
19394941b5efSBram Moolenaar }
19404941b5efSBram Moolenaar }
19414941b5efSBram Moolenaar
1942071d4279SBram Moolenaar xp->xp_pattern = arg;
1943071d4279SBram Moolenaar }
1944071d4279SBram Moolenaar
1945071d4279SBram Moolenaar /*
1946ea6553beSBram Moolenaar * Return TRUE if "pat" matches "text".
1947ea6553beSBram Moolenaar * Does not use 'cpo' and always uses 'magic'.
1948ea6553beSBram Moolenaar */
1949ecaa70eaSBram Moolenaar int
pattern_match(char_u * pat,char_u * text,int ic)1950ea6553beSBram Moolenaar pattern_match(char_u *pat, char_u *text, int ic)
1951ea6553beSBram Moolenaar {
1952ea6553beSBram Moolenaar int matches = FALSE;
1953ea6553beSBram Moolenaar char_u *save_cpo;
1954ea6553beSBram Moolenaar regmatch_T regmatch;
1955ea6553beSBram Moolenaar
19565d18efecSBram Moolenaar // avoid 'l' flag in 'cpoptions'
1957ea6553beSBram Moolenaar save_cpo = p_cpo;
1958e5a2dc87SBram Moolenaar p_cpo = empty_option;
1959ea6553beSBram Moolenaar regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
1960ea6553beSBram Moolenaar if (regmatch.regprog != NULL)
1961ea6553beSBram Moolenaar {
1962ea6553beSBram Moolenaar regmatch.rm_ic = ic;
1963ea6553beSBram Moolenaar matches = vim_regexec_nl(®match, text, (colnr_T)0);
1964ea6553beSBram Moolenaar vim_regfree(regmatch.regprog);
1965ea6553beSBram Moolenaar }
1966ea6553beSBram Moolenaar p_cpo = save_cpo;
1967ea6553beSBram Moolenaar return matches;
1968ea6553beSBram Moolenaar }
1969ea6553beSBram Moolenaar
1970ea6553beSBram Moolenaar /*
1971761fdf01SBram Moolenaar * Handle a name followed by "(". Both for just "name(arg)" and for
1972761fdf01SBram Moolenaar * "expr->name(arg)".
1973761fdf01SBram Moolenaar * Returns OK or FAIL.
1974761fdf01SBram Moolenaar */
1975761fdf01SBram Moolenaar static int
eval_func(char_u ** arg,evalarg_T * evalarg,char_u * name,int name_len,typval_T * rettv,int flags,typval_T * basetv)1976761fdf01SBram Moolenaar eval_func(
1977761fdf01SBram Moolenaar char_u **arg, // points to "(", will be advanced
1978e6b5324eSBram Moolenaar evalarg_T *evalarg,
1979761fdf01SBram Moolenaar char_u *name,
1980761fdf01SBram Moolenaar int name_len,
1981761fdf01SBram Moolenaar typval_T *rettv,
198232e35117SBram Moolenaar int flags,
1983761fdf01SBram Moolenaar typval_T *basetv) // "expr" for "expr->name(arg)"
1984761fdf01SBram Moolenaar {
198532e35117SBram Moolenaar int evaluate = flags & EVAL_EVALUATE;
1986761fdf01SBram Moolenaar char_u *s = name;
1987761fdf01SBram Moolenaar int len = name_len;
1988761fdf01SBram Moolenaar partial_T *partial;
1989761fdf01SBram Moolenaar int ret = OK;
199032b3f820SBram Moolenaar type_T *type = NULL;
1991761fdf01SBram Moolenaar
1992761fdf01SBram Moolenaar if (!evaluate)
1993761fdf01SBram Moolenaar check_vars(s, len);
1994761fdf01SBram Moolenaar
19955d18efecSBram Moolenaar // If "s" is the name of a variable of type VAR_FUNC
19965d18efecSBram Moolenaar // use its contents.
199732b3f820SBram Moolenaar s = deref_func_name(s, &len, &partial,
199832b3f820SBram Moolenaar in_vim9script() ? &type : NULL, !evaluate);
1999761fdf01SBram Moolenaar
20005d18efecSBram Moolenaar // Need to make a copy, in case evaluating the arguments makes
20015d18efecSBram Moolenaar // the name invalid.
2002761fdf01SBram Moolenaar s = vim_strsave(s);
200332e35117SBram Moolenaar if (s == NULL || (flags & EVAL_CONSTANT))
2004761fdf01SBram Moolenaar ret = FAIL;
2005761fdf01SBram Moolenaar else
2006761fdf01SBram Moolenaar {
2007761fdf01SBram Moolenaar funcexe_T funcexe;
2008761fdf01SBram Moolenaar
2009761fdf01SBram Moolenaar // Invoke the function.
2010a80faa89SBram Moolenaar CLEAR_FIELD(funcexe);
2011761fdf01SBram Moolenaar funcexe.firstline = curwin->w_cursor.lnum;
2012761fdf01SBram Moolenaar funcexe.lastline = curwin->w_cursor.lnum;
2013761fdf01SBram Moolenaar funcexe.evaluate = evaluate;
2014761fdf01SBram Moolenaar funcexe.partial = partial;
2015761fdf01SBram Moolenaar funcexe.basetv = basetv;
201632b3f820SBram Moolenaar funcexe.check_type = type;
2017e6b5324eSBram Moolenaar ret = get_func_tv(s, len, rettv, arg, evalarg, &funcexe);
2018761fdf01SBram Moolenaar }
2019761fdf01SBram Moolenaar vim_free(s);
2020761fdf01SBram Moolenaar
20215d18efecSBram Moolenaar // If evaluate is FALSE rettv->v_type was not set in
20225d18efecSBram Moolenaar // get_func_tv, but it's needed in handle_subscript() to parse
20235d18efecSBram Moolenaar // what follows. So set it here.
2024761fdf01SBram Moolenaar if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(')
2025761fdf01SBram Moolenaar {
2026761fdf01SBram Moolenaar rettv->vval.v_string = NULL;
2027761fdf01SBram Moolenaar rettv->v_type = VAR_FUNC;
2028761fdf01SBram Moolenaar }
2029761fdf01SBram Moolenaar
20305d18efecSBram Moolenaar // Stop the expression evaluation when immediately
20315d18efecSBram Moolenaar // aborting on error, or when an interrupt occurred or
20325d18efecSBram Moolenaar // an exception was thrown but not caught.
2033761fdf01SBram Moolenaar if (evaluate && aborting())
2034761fdf01SBram Moolenaar {
2035761fdf01SBram Moolenaar if (ret == OK)
2036761fdf01SBram Moolenaar clear_tv(rettv);
2037761fdf01SBram Moolenaar ret = FAIL;
2038761fdf01SBram Moolenaar }
2039761fdf01SBram Moolenaar return ret;
2040761fdf01SBram Moolenaar }
2041761fdf01SBram Moolenaar
2042761fdf01SBram Moolenaar /*
204393be1644SBram Moolenaar * Get the next line source line without advancing. But do skip over comment
204493be1644SBram Moolenaar * lines.
204503717bf6SBram Moolenaar * Only called for Vim9 script.
204693be1644SBram Moolenaar */
204793be1644SBram Moolenaar static char_u *
getline_peek_skip_comments(evalarg_T * evalarg)204893be1644SBram Moolenaar getline_peek_skip_comments(evalarg_T *evalarg)
204993be1644SBram Moolenaar {
205093be1644SBram Moolenaar for (;;)
205193be1644SBram Moolenaar {
205293be1644SBram Moolenaar char_u *next = getline_peek(evalarg->eval_getline,
205393be1644SBram Moolenaar evalarg->eval_cookie);
205493be1644SBram Moolenaar char_u *p;
205593be1644SBram Moolenaar
205693be1644SBram Moolenaar if (next == NULL)
205793be1644SBram Moolenaar break;
205893be1644SBram Moolenaar p = skipwhite(next);
205993be1644SBram Moolenaar if (*p != NUL && !vim9_comment_start(p))
206093be1644SBram Moolenaar return next;
206193be1644SBram Moolenaar (void)eval_next_line(evalarg);
206293be1644SBram Moolenaar }
206393be1644SBram Moolenaar return NULL;
206493be1644SBram Moolenaar }
206593be1644SBram Moolenaar
206693be1644SBram Moolenaar /*
2067962d7213SBram Moolenaar * If inside Vim9 script, "arg" points to the end of a line (ignoring a #
2068962d7213SBram Moolenaar * comment) and there is a next line, return the next line (skipping blanks)
2069962d7213SBram Moolenaar * and set "getnext".
2070a6aa1642SBram Moolenaar * Otherwise return the next non-white at or after "arg" and set "getnext" to
2071a6aa1642SBram Moolenaar * FALSE.
20725409f5d8SBram Moolenaar * "arg" must point somewhere inside a line, not at the start.
20735409f5d8SBram Moolenaar */
2074a2438132SYegappan Lakshmanan static char_u *
eval_next_non_blank(char_u * arg,evalarg_T * evalarg,int * getnext)20755409f5d8SBram Moolenaar eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext)
20765409f5d8SBram Moolenaar {
20779d489566SBram Moolenaar char_u *p = skipwhite(arg);
20789d489566SBram Moolenaar
20795409f5d8SBram Moolenaar *getnext = FALSE;
2080eb6880b6SBram Moolenaar if (in_vim9script()
20815409f5d8SBram Moolenaar && evalarg != NULL
20827a4b8980SBram Moolenaar && (evalarg->eval_cookie != NULL || evalarg->eval_cctx != NULL)
2083a6aa1642SBram Moolenaar && (*p == NUL || (vim9_comment_start(p) && VIM_ISWHITE(p[-1]))))
20845409f5d8SBram Moolenaar {
20859d489566SBram Moolenaar char_u *next;
20867a4b8980SBram Moolenaar
20877a4b8980SBram Moolenaar if (evalarg->eval_cookie != NULL)
208893be1644SBram Moolenaar next = getline_peek_skip_comments(evalarg);
20897a4b8980SBram Moolenaar else
20909d489566SBram Moolenaar next = peek_next_line_from_context(evalarg->eval_cctx);
20915409f5d8SBram Moolenaar
20929d489566SBram Moolenaar if (next != NULL)
20935409f5d8SBram Moolenaar {
20945409f5d8SBram Moolenaar *getnext = TRUE;
20959d489566SBram Moolenaar return skipwhite(next);
20965409f5d8SBram Moolenaar }
20975409f5d8SBram Moolenaar }
20989d489566SBram Moolenaar return p;
20995409f5d8SBram Moolenaar }
21005409f5d8SBram Moolenaar
21015409f5d8SBram Moolenaar /*
2102e40fbc2cSBram Moolenaar * To be called after eval_next_non_blank() sets "getnext" to TRUE.
210303717bf6SBram Moolenaar * Only called for Vim9 script.
2104b171fb17SBram Moolenaar */
2105a2438132SYegappan Lakshmanan static char_u *
eval_next_line(evalarg_T * evalarg)2106b171fb17SBram Moolenaar eval_next_line(evalarg_T *evalarg)
2107b171fb17SBram Moolenaar {
2108e40fbc2cSBram Moolenaar garray_T *gap = &evalarg->eval_ga;
2109e40fbc2cSBram Moolenaar char_u *line;
2110e40fbc2cSBram Moolenaar
21117a4b8980SBram Moolenaar if (evalarg->eval_cookie != NULL)
2112825b5441SBram Moolenaar line = evalarg->eval_getline(0, evalarg->eval_cookie, 0,
2113825b5441SBram Moolenaar GETLINE_CONCAT_ALL);
21147a4b8980SBram Moolenaar else
21157a4b8980SBram Moolenaar line = next_line_from_context(evalarg->eval_cctx, TRUE);
2116b7a78f7aSBram Moolenaar ++evalarg->eval_break_count;
2117e40fbc2cSBram Moolenaar if (gap->ga_itemsize > 0 && ga_grow(gap, 1) == OK)
2118e40fbc2cSBram Moolenaar {
211903717bf6SBram Moolenaar char_u *p = skipwhite(line);
212003717bf6SBram Moolenaar
212103717bf6SBram Moolenaar // Going to concatenate the lines after parsing. For an empty or
212203717bf6SBram Moolenaar // comment line use an empty string.
212303717bf6SBram Moolenaar if (*p == NUL || vim9_comment_start(p))
212403717bf6SBram Moolenaar {
212503717bf6SBram Moolenaar vim_free(line);
212603717bf6SBram Moolenaar line = vim_strsave((char_u *)"");
212703717bf6SBram Moolenaar }
212803717bf6SBram Moolenaar
2129e40fbc2cSBram Moolenaar ((char_u **)gap->ga_data)[gap->ga_len] = line;
2130e40fbc2cSBram Moolenaar ++gap->ga_len;
2131e40fbc2cSBram Moolenaar }
21328e2730a3SBram Moolenaar else if (evalarg->eval_cookie != NULL)
2133e40fbc2cSBram Moolenaar {
2134b171fb17SBram Moolenaar vim_free(evalarg->eval_tofree);
2135e40fbc2cSBram Moolenaar evalarg->eval_tofree = line;
2136e40fbc2cSBram Moolenaar }
2137c6ba2f9dSBram Moolenaar
2138c6ba2f9dSBram Moolenaar // Advanced to the next line, "arg" no longer points into the previous
2139c6ba2f9dSBram Moolenaar // line.
2140*844fb64aSBram Moolenaar evalarg->eval_using_cmdline = FALSE;
2141e40fbc2cSBram Moolenaar return skipwhite(line);
2142b171fb17SBram Moolenaar }
2143b171fb17SBram Moolenaar
2144e6b5324eSBram Moolenaar /*
2145e6b5324eSBram Moolenaar * Call eval_next_non_blank() and get the next line if needed.
2146e6b5324eSBram Moolenaar */
21479215f012SBram Moolenaar char_u *
skipwhite_and_linebreak(char_u * arg,evalarg_T * evalarg)21489215f012SBram Moolenaar skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg)
21499215f012SBram Moolenaar {
21509215f012SBram Moolenaar int getnext;
21519215f012SBram Moolenaar char_u *p = skipwhite(arg);
21529215f012SBram Moolenaar
2153962d7213SBram Moolenaar if (evalarg == NULL)
2154962d7213SBram Moolenaar return skipwhite(arg);
21559215f012SBram Moolenaar eval_next_non_blank(p, evalarg, &getnext);
21569215f012SBram Moolenaar if (getnext)
21579215f012SBram Moolenaar return eval_next_line(evalarg);
21589215f012SBram Moolenaar return p;
21599215f012SBram Moolenaar }
21609215f012SBram Moolenaar
2161b171fb17SBram Moolenaar /*
2162*844fb64aSBram Moolenaar * Initialize "evalarg" for use.
2163*844fb64aSBram Moolenaar */
2164*844fb64aSBram Moolenaar void
init_evalarg(evalarg_T * evalarg)2165*844fb64aSBram Moolenaar init_evalarg(evalarg_T *evalarg)
2166*844fb64aSBram Moolenaar {
2167*844fb64aSBram Moolenaar CLEAR_POINTER(evalarg);
2168*844fb64aSBram Moolenaar ga_init2(&evalarg->eval_tofree_ga, sizeof(char_u *), 20);
2169*844fb64aSBram Moolenaar }
2170*844fb64aSBram Moolenaar
2171*844fb64aSBram Moolenaar /*
21728e2730a3SBram Moolenaar * After using "evalarg" filled from "eap": free the memory.
2173faf8626bSBram Moolenaar */
2174faf8626bSBram Moolenaar void
clear_evalarg(evalarg_T * evalarg,exarg_T * eap)2175faf8626bSBram Moolenaar clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
2176faf8626bSBram Moolenaar {
21778e2730a3SBram Moolenaar if (evalarg != NULL)
21788e2730a3SBram Moolenaar {
21798e2730a3SBram Moolenaar if (evalarg->eval_tofree != NULL)
2180b7a78f7aSBram Moolenaar {
2181b7a78f7aSBram Moolenaar if (eap != NULL)
2182faf8626bSBram Moolenaar {
2183faf8626bSBram Moolenaar // We may need to keep the original command line, e.g. for
2184faf8626bSBram Moolenaar // ":let" it has the variable names. But we may also need the
2185faf8626bSBram Moolenaar // new one, "nextcmd" points into it. Keep both.
2186faf8626bSBram Moolenaar vim_free(eap->cmdline_tofree);
2187faf8626bSBram Moolenaar eap->cmdline_tofree = *eap->cmdlinep;
2188faf8626bSBram Moolenaar *eap->cmdlinep = evalarg->eval_tofree;
2189b7a78f7aSBram Moolenaar }
2190b7a78f7aSBram Moolenaar else
2191b7a78f7aSBram Moolenaar vim_free(evalarg->eval_tofree);
2192faf8626bSBram Moolenaar evalarg->eval_tofree = NULL;
2193faf8626bSBram Moolenaar }
21948e2730a3SBram Moolenaar
2195*844fb64aSBram Moolenaar ga_clear_strings(&evalarg->eval_tofree_ga);
219667da21a1SBram Moolenaar VIM_CLEAR(evalarg->eval_tofree_lambda);
21978e2730a3SBram Moolenaar }
2198faf8626bSBram Moolenaar }
2199faf8626bSBram Moolenaar
2200faf8626bSBram Moolenaar /*
2201071d4279SBram Moolenaar * The "evaluate" argument: When FALSE, the argument is only parsed but not
2202c70646c6SBram Moolenaar * executed. The function may return OK, but the rettv will be of type
2203071d4279SBram Moolenaar * VAR_UNKNOWN. The function still returns FAIL for a syntax error.
2204071d4279SBram Moolenaar */
2205071d4279SBram Moolenaar
2206071d4279SBram Moolenaar /*
2207071d4279SBram Moolenaar * Handle zero level expression.
2208071d4279SBram Moolenaar * This calls eval1() and handles error message and nextcmd.
2209c70646c6SBram Moolenaar * Put the result in "rettv" when returning OK and "evaluate" is TRUE.
22104463f296SBram Moolenaar * Note: "rettv.v_lock" is not set.
22115409f5d8SBram Moolenaar * "evalarg" can be NULL, EVALARG_EVALUATE or a pointer.
2212071d4279SBram Moolenaar * Return OK or FAIL.
2213071d4279SBram Moolenaar */
2214a9b579f3SBram Moolenaar int
eval0(char_u * arg,typval_T * rettv,exarg_T * eap,evalarg_T * evalarg)22157454a06eSBram Moolenaar eval0(
22167454a06eSBram Moolenaar char_u *arg,
22177454a06eSBram Moolenaar typval_T *rettv,
2218b171fb17SBram Moolenaar exarg_T *eap,
22195409f5d8SBram Moolenaar evalarg_T *evalarg)
2220071d4279SBram Moolenaar {
2221071d4279SBram Moolenaar int ret;
2222071d4279SBram Moolenaar char_u *p;
2223c0f5a78cSBram Moolenaar int did_emsg_before = did_emsg;
2224c0f5a78cSBram Moolenaar int called_emsg_before = called_emsg;
22255409f5d8SBram Moolenaar int flags = evalarg == NULL ? 0 : evalarg->eval_flags;
2226fae55a9cSBram Moolenaar int end_error = FALSE;
2227071d4279SBram Moolenaar
2228071d4279SBram Moolenaar p = skipwhite(arg);
22295409f5d8SBram Moolenaar ret = eval1(&p, rettv, evalarg);
22309d489566SBram Moolenaar p = skipwhite(p);
2231b171fb17SBram Moolenaar
2232fae55a9cSBram Moolenaar if (ret != FAIL)
2233fae55a9cSBram Moolenaar end_error = !ends_excmd2(arg, p);
2234fae55a9cSBram Moolenaar if (ret == FAIL || end_error)
2235071d4279SBram Moolenaar {
2236071d4279SBram Moolenaar if (ret != FAIL)
2237c70646c6SBram Moolenaar clear_tv(rettv);
2238071d4279SBram Moolenaar /*
2239071d4279SBram Moolenaar * Report the invalid expression unless the expression evaluation has
2240071d4279SBram Moolenaar * been cancelled due to an aborting error, an interrupt, or an
2241c0f5a78cSBram Moolenaar * exception, or we already gave a more specific error.
2242c0f5a78cSBram Moolenaar * Also check called_emsg for when using assert_fails().
2243071d4279SBram Moolenaar */
224432e35117SBram Moolenaar if (!aborting()
224532e35117SBram Moolenaar && did_emsg == did_emsg_before
224632e35117SBram Moolenaar && called_emsg == called_emsg_before
22475c7a299cSBram Moolenaar && (flags & EVAL_CONSTANT) == 0
22485c7a299cSBram Moolenaar && (!in_vim9script() || !vim9_bad_comment(p)))
2249fae55a9cSBram Moolenaar {
2250fae55a9cSBram Moolenaar if (end_error)
2251fae55a9cSBram Moolenaar semsg(_(e_trailing_arg), p);
2252fae55a9cSBram Moolenaar else
2253108010aaSBram Moolenaar semsg(_(e_invalid_expression_str), arg);
2254fae55a9cSBram Moolenaar }
2255d0fe620cSBram Moolenaar
2256d0fe620cSBram Moolenaar // Some of the expression may not have been consumed. Do not check for
22578143a53cSBram Moolenaar // a next command to avoid more errors, unless "|" is following, which
22588143a53cSBram Moolenaar // could only be a command separator.
22598143a53cSBram Moolenaar if (eap != NULL && skipwhite(p)[0] == '|' && skipwhite(p)[1] != '|')
22608143a53cSBram Moolenaar eap->nextcmd = check_nextcmd(p);
2261d0fe620cSBram Moolenaar return FAIL;
2262071d4279SBram Moolenaar }
2263b171fb17SBram Moolenaar
2264b171fb17SBram Moolenaar if (eap != NULL)
226563b91736SBram Moolenaar set_nextcmd(eap, p);
2266b171fb17SBram Moolenaar
2267071d4279SBram Moolenaar return ret;
2268071d4279SBram Moolenaar }
2269071d4279SBram Moolenaar
2270071d4279SBram Moolenaar /*
2271071d4279SBram Moolenaar * Handle top level expression:
2272b67cc16eSBram Moolenaar * expr2 ? expr1 : expr1
227392f26c25SBram Moolenaar * expr2 ?? expr1
2274071d4279SBram Moolenaar *
2275071d4279SBram Moolenaar * "arg" must point to the first non-white of the expression.
2276fdac71c5SBram Moolenaar * "arg" is advanced to just after the recognized expression.
2277071d4279SBram Moolenaar *
22784463f296SBram Moolenaar * Note: "rettv.v_lock" is not set.
22794463f296SBram Moolenaar *
2280071d4279SBram Moolenaar * Return OK or FAIL.
2281071d4279SBram Moolenaar */
2282cd52459cSBram Moolenaar int
eval1(char_u ** arg,typval_T * rettv,evalarg_T * evalarg)22835409f5d8SBram Moolenaar eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
2284071d4279SBram Moolenaar {
2285793648fbSBram Moolenaar char_u *p;
2286793648fbSBram Moolenaar int getnext;
2287793648fbSBram Moolenaar
22884a091b99SBram Moolenaar CLEAR_POINTER(rettv);
22894a091b99SBram Moolenaar
2290071d4279SBram Moolenaar /*
2291071d4279SBram Moolenaar * Get the first variable.
2292071d4279SBram Moolenaar */
22935409f5d8SBram Moolenaar if (eval2(arg, rettv, evalarg) == FAIL)
2294071d4279SBram Moolenaar return FAIL;
2295071d4279SBram Moolenaar
2296793648fbSBram Moolenaar p = eval_next_non_blank(*arg, evalarg, &getnext);
2297793648fbSBram Moolenaar if (*p == '?')
2298071d4279SBram Moolenaar {
229992f26c25SBram Moolenaar int op_falsy = p[1] == '?';
23005409f5d8SBram Moolenaar int result;
23015409f5d8SBram Moolenaar typval_T var2;
23028af81d65SBram Moolenaar evalarg_T *evalarg_used = evalarg;
23038af81d65SBram Moolenaar evalarg_T local_evalarg;
23045409f5d8SBram Moolenaar int orig_flags;
23057acde518SBram Moolenaar int evaluate;
230613106605SBram Moolenaar int vim9script = in_vim9script();
23075409f5d8SBram Moolenaar
23085409f5d8SBram Moolenaar if (evalarg == NULL)
23095409f5d8SBram Moolenaar {
2310*844fb64aSBram Moolenaar init_evalarg(&local_evalarg);
23118af81d65SBram Moolenaar evalarg_used = &local_evalarg;
23125409f5d8SBram Moolenaar }
23138af81d65SBram Moolenaar orig_flags = evalarg_used->eval_flags;
23148af81d65SBram Moolenaar evaluate = evalarg_used->eval_flags & EVAL_EVALUATE;
23155409f5d8SBram Moolenaar
23168af81d65SBram Moolenaar if (getnext)
23178af81d65SBram Moolenaar *arg = eval_next_line(evalarg_used);
23189d489566SBram Moolenaar else
2319fdac71c5SBram Moolenaar {
232013106605SBram Moolenaar if (evaluate && vim9script && !VIM_ISWHITE(p[-1]))
2321fdac71c5SBram Moolenaar {
232290193e61SBram Moolenaar error_white_both(p, op_falsy ? 2 : 1);
2323fdac71c5SBram Moolenaar clear_tv(rettv);
2324fdac71c5SBram Moolenaar return FAIL;
2325fdac71c5SBram Moolenaar }
23269d489566SBram Moolenaar *arg = p;
2327fdac71c5SBram Moolenaar }
23288af81d65SBram Moolenaar
2329071d4279SBram Moolenaar result = FALSE;
23305409f5d8SBram Moolenaar if (evaluate)
2331071d4279SBram Moolenaar {
23329ba0eb85SBram Moolenaar int error = FALSE;
23339ba0eb85SBram Moolenaar
233413106605SBram Moolenaar if (op_falsy)
233556acb094SBram Moolenaar result = tv2bool(rettv);
233613106605SBram Moolenaar else if (vim9script)
233713106605SBram Moolenaar result = tv_get_bool_chk(rettv, &error);
233856acb094SBram Moolenaar else if (tv_get_number_chk(rettv, &error) != 0)
2339071d4279SBram Moolenaar result = TRUE;
234092f26c25SBram Moolenaar if (error || !op_falsy || !result)
2341c70646c6SBram Moolenaar clear_tv(rettv);
23429ba0eb85SBram Moolenaar if (error)
23439ba0eb85SBram Moolenaar return FAIL;
2344071d4279SBram Moolenaar }
2345071d4279SBram Moolenaar
2346071d4279SBram Moolenaar /*
234732e35117SBram Moolenaar * Get the second variable. Recursive!
2348071d4279SBram Moolenaar */
234992f26c25SBram Moolenaar if (op_falsy)
235092f26c25SBram Moolenaar ++*arg;
235113106605SBram Moolenaar if (evaluate && vim9script && !IS_WHITE_OR_NUL((*arg)[1]))
2352fdac71c5SBram Moolenaar {
23534ac198c6Smityu error_white_both(*arg - (op_falsy ? 1 : 0), op_falsy ? 2 : 1);
2354fdac71c5SBram Moolenaar clear_tv(rettv);
2355fdac71c5SBram Moolenaar return FAIL;
2356fdac71c5SBram Moolenaar }
23578af81d65SBram Moolenaar *arg = skipwhite_and_linebreak(*arg + 1, evalarg_used);
235892f26c25SBram Moolenaar evalarg_used->eval_flags = (op_falsy ? !result : result)
235992f26c25SBram Moolenaar ? orig_flags : orig_flags & ~EVAL_EVALUATE;
236092f26c25SBram Moolenaar if (eval1(arg, &var2, evalarg_used) == FAIL)
236169e44552SBram Moolenaar {
236269e44552SBram Moolenaar evalarg_used->eval_flags = orig_flags;
2363071d4279SBram Moolenaar return FAIL;
236469e44552SBram Moolenaar }
236592f26c25SBram Moolenaar if (!op_falsy || !result)
236692f26c25SBram Moolenaar *rettv = var2;
2367071d4279SBram Moolenaar
236892f26c25SBram Moolenaar if (!op_falsy)
236992f26c25SBram Moolenaar {
2370071d4279SBram Moolenaar /*
2371071d4279SBram Moolenaar * Check for the ":".
2372071d4279SBram Moolenaar */
23738af81d65SBram Moolenaar p = eval_next_non_blank(*arg, evalarg_used, &getnext);
2374793648fbSBram Moolenaar if (*p != ':')
2375071d4279SBram Moolenaar {
23768a7d6542SBram Moolenaar emsg(_(e_missing_colon));
2377071d4279SBram Moolenaar if (evaluate && result)
2378c70646c6SBram Moolenaar clear_tv(rettv);
237969e44552SBram Moolenaar evalarg_used->eval_flags = orig_flags;
2380071d4279SBram Moolenaar return FAIL;
2381071d4279SBram Moolenaar }
2382793648fbSBram Moolenaar if (getnext)
23838af81d65SBram Moolenaar *arg = eval_next_line(evalarg_used);
23849d489566SBram Moolenaar else
2385fdac71c5SBram Moolenaar {
238613106605SBram Moolenaar if (evaluate && vim9script && !VIM_ISWHITE(p[-1]))
2387fdac71c5SBram Moolenaar {
2388fdac71c5SBram Moolenaar error_white_both(p, 1);
2389fdac71c5SBram Moolenaar clear_tv(rettv);
239069e44552SBram Moolenaar evalarg_used->eval_flags = orig_flags;
2391fdac71c5SBram Moolenaar return FAIL;
2392fdac71c5SBram Moolenaar }
23939d489566SBram Moolenaar *arg = p;
2394fdac71c5SBram Moolenaar }
2395071d4279SBram Moolenaar
2396071d4279SBram Moolenaar /*
239732e35117SBram Moolenaar * Get the third variable. Recursive!
2398071d4279SBram Moolenaar */
239913106605SBram Moolenaar if (evaluate && vim9script && !IS_WHITE_OR_NUL((*arg)[1]))
2400fdac71c5SBram Moolenaar {
24014ac198c6Smityu error_white_both(*arg, 1);
2402fdac71c5SBram Moolenaar clear_tv(rettv);
240369e44552SBram Moolenaar evalarg_used->eval_flags = orig_flags;
2404fdac71c5SBram Moolenaar return FAIL;
2405fdac71c5SBram Moolenaar }
24068af81d65SBram Moolenaar *arg = skipwhite_and_linebreak(*arg + 1, evalarg_used);
24078af81d65SBram Moolenaar evalarg_used->eval_flags = !result ? orig_flags
24085409f5d8SBram Moolenaar : orig_flags & ~EVAL_EVALUATE;
24098af81d65SBram Moolenaar if (eval1(arg, &var2, evalarg_used) == FAIL)
2410071d4279SBram Moolenaar {
2411071d4279SBram Moolenaar if (evaluate && result)
2412c70646c6SBram Moolenaar clear_tv(rettv);
241369e44552SBram Moolenaar evalarg_used->eval_flags = orig_flags;
2414071d4279SBram Moolenaar return FAIL;
2415071d4279SBram Moolenaar }
2416071d4279SBram Moolenaar if (evaluate && !result)
2417c70646c6SBram Moolenaar *rettv = var2;
241892f26c25SBram Moolenaar }
24198af81d65SBram Moolenaar
24208af81d65SBram Moolenaar if (evalarg == NULL)
24218af81d65SBram Moolenaar clear_evalarg(&local_evalarg, NULL);
24228af81d65SBram Moolenaar else
24238af81d65SBram Moolenaar evalarg->eval_flags = orig_flags;
2424071d4279SBram Moolenaar }
2425071d4279SBram Moolenaar
2426071d4279SBram Moolenaar return OK;
2427071d4279SBram Moolenaar }
2428071d4279SBram Moolenaar
2429071d4279SBram Moolenaar /*
2430071d4279SBram Moolenaar * Handle first level expression:
2431071d4279SBram Moolenaar * expr2 || expr2 || expr2 logical OR
2432071d4279SBram Moolenaar *
2433071d4279SBram Moolenaar * "arg" must point to the first non-white of the expression.
2434fdac71c5SBram Moolenaar * "arg" is advanced to just after the recognized expression.
2435071d4279SBram Moolenaar *
2436071d4279SBram Moolenaar * Return OK or FAIL.
2437071d4279SBram Moolenaar */
2438071d4279SBram Moolenaar static int
eval2(char_u ** arg,typval_T * rettv,evalarg_T * evalarg)24395409f5d8SBram Moolenaar eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
2440071d4279SBram Moolenaar {
2441be7ee488SBram Moolenaar char_u *p;
2442be7ee488SBram Moolenaar int getnext;
2443071d4279SBram Moolenaar
2444071d4279SBram Moolenaar /*
2445071d4279SBram Moolenaar * Get the first variable.
2446071d4279SBram Moolenaar */
24475409f5d8SBram Moolenaar if (eval3(arg, rettv, evalarg) == FAIL)
2448071d4279SBram Moolenaar return FAIL;
2449071d4279SBram Moolenaar
2450071d4279SBram Moolenaar /*
24518af81d65SBram Moolenaar * Handle the "||" operator.
2452071d4279SBram Moolenaar */
2453be7ee488SBram Moolenaar p = eval_next_non_blank(*arg, evalarg, &getnext);
24548af81d65SBram Moolenaar if (p[0] == '|' && p[1] == '|')
2455071d4279SBram Moolenaar {
24568af81d65SBram Moolenaar evalarg_T *evalarg_used = evalarg;
24578af81d65SBram Moolenaar evalarg_T local_evalarg;
24585409f5d8SBram Moolenaar int evaluate;
24595409f5d8SBram Moolenaar int orig_flags;
24608af81d65SBram Moolenaar long result = FALSE;
24618af81d65SBram Moolenaar typval_T var2;
24622bb2658bSBram Moolenaar int error = FALSE;
24638c34ea54SBram Moolenaar int vim9script = in_vim9script();
2464be7ee488SBram Moolenaar
24655409f5d8SBram Moolenaar if (evalarg == NULL)
24665409f5d8SBram Moolenaar {
2467*844fb64aSBram Moolenaar init_evalarg(&local_evalarg);
24688af81d65SBram Moolenaar evalarg_used = &local_evalarg;
24695409f5d8SBram Moolenaar }
24708af81d65SBram Moolenaar orig_flags = evalarg_used->eval_flags;
24715409f5d8SBram Moolenaar evaluate = orig_flags & EVAL_EVALUATE;
24728af81d65SBram Moolenaar if (evaluate)
2473071d4279SBram Moolenaar {
24748c34ea54SBram Moolenaar if (vim9script)
24752bb2658bSBram Moolenaar result = tv_get_bool_chk(rettv, &error);
24762bb2658bSBram Moolenaar else if (tv_get_number_chk(rettv, &error) != 0)
2477071d4279SBram Moolenaar result = TRUE;
2478c70646c6SBram Moolenaar clear_tv(rettv);
24799ba0eb85SBram Moolenaar if (error)
24809ba0eb85SBram Moolenaar return FAIL;
2481071d4279SBram Moolenaar }
2482071d4279SBram Moolenaar
2483071d4279SBram Moolenaar /*
24848af81d65SBram Moolenaar * Repeat until there is no following "||".
24858af81d65SBram Moolenaar */
24868af81d65SBram Moolenaar while (p[0] == '|' && p[1] == '|')
24878af81d65SBram Moolenaar {
24888af81d65SBram Moolenaar if (getnext)
24898af81d65SBram Moolenaar *arg = eval_next_line(evalarg_used);
24909d489566SBram Moolenaar else
24913c1c9fd9SBram Moolenaar {
24923c1c9fd9SBram Moolenaar if (evaluate && in_vim9script() && !VIM_ISWHITE(p[-1]))
24933c1c9fd9SBram Moolenaar {
24943c1c9fd9SBram Moolenaar error_white_both(p, 2);
24953c1c9fd9SBram Moolenaar clear_tv(rettv);
24963c1c9fd9SBram Moolenaar return FAIL;
24973c1c9fd9SBram Moolenaar }
24989d489566SBram Moolenaar *arg = p;
24993c1c9fd9SBram Moolenaar }
25008af81d65SBram Moolenaar
25018af81d65SBram Moolenaar /*
2502071d4279SBram Moolenaar * Get the second variable.
2503071d4279SBram Moolenaar */
25043c1c9fd9SBram Moolenaar if (evaluate && in_vim9script() && !IS_WHITE_OR_NUL((*arg)[2]))
25053c1c9fd9SBram Moolenaar {
25064ac198c6Smityu error_white_both(*arg, 2);
25073c1c9fd9SBram Moolenaar clear_tv(rettv);
25083c1c9fd9SBram Moolenaar return FAIL;
25093c1c9fd9SBram Moolenaar }
25108af81d65SBram Moolenaar *arg = skipwhite_and_linebreak(*arg + 2, evalarg_used);
25118af81d65SBram Moolenaar evalarg_used->eval_flags = !result ? orig_flags
25125409f5d8SBram Moolenaar : orig_flags & ~EVAL_EVALUATE;
25138af81d65SBram Moolenaar if (eval3(arg, &var2, evalarg_used) == FAIL)
2514071d4279SBram Moolenaar return FAIL;
2515071d4279SBram Moolenaar
2516071d4279SBram Moolenaar /*
2517071d4279SBram Moolenaar * Compute the result.
2518071d4279SBram Moolenaar */
2519071d4279SBram Moolenaar if (evaluate && !result)
2520071d4279SBram Moolenaar {
25218c34ea54SBram Moolenaar if (vim9script)
25222bb2658bSBram Moolenaar result = tv_get_bool_chk(&var2, &error);
25232bb2658bSBram Moolenaar else if (tv_get_number_chk(&var2, &error) != 0)
2524071d4279SBram Moolenaar result = TRUE;
2525c70646c6SBram Moolenaar clear_tv(&var2);
25269ba0eb85SBram Moolenaar if (error)
25279ba0eb85SBram Moolenaar return FAIL;
2528071d4279SBram Moolenaar }
25292bb2658bSBram Moolenaar if (evaluate)
25302bb2658bSBram Moolenaar {
25312bb2658bSBram Moolenaar if (vim9script)
25322bb2658bSBram Moolenaar {
25332bb2658bSBram Moolenaar rettv->v_type = VAR_BOOL;
25342bb2658bSBram Moolenaar rettv->vval.v_number = result ? VVAL_TRUE : VVAL_FALSE;
25358c34ea54SBram Moolenaar }
25362bb2658bSBram Moolenaar else
2537071d4279SBram Moolenaar {
2538c70646c6SBram Moolenaar rettv->v_type = VAR_NUMBER;
2539c70646c6SBram Moolenaar rettv->vval.v_number = result;
2540071d4279SBram Moolenaar }
25412bb2658bSBram Moolenaar }
2542be7ee488SBram Moolenaar
25438af81d65SBram Moolenaar p = eval_next_non_blank(*arg, evalarg_used, &getnext);
25448af81d65SBram Moolenaar }
25458af81d65SBram Moolenaar
25468af81d65SBram Moolenaar if (evalarg == NULL)
25478af81d65SBram Moolenaar clear_evalarg(&local_evalarg, NULL);
25488af81d65SBram Moolenaar else
25498af81d65SBram Moolenaar evalarg->eval_flags = orig_flags;
2550071d4279SBram Moolenaar }
2551071d4279SBram Moolenaar
2552071d4279SBram Moolenaar return OK;
2553071d4279SBram Moolenaar }
2554071d4279SBram Moolenaar
2555071d4279SBram Moolenaar /*
2556071d4279SBram Moolenaar * Handle second level expression:
2557071d4279SBram Moolenaar * expr3 && expr3 && expr3 logical AND
2558071d4279SBram Moolenaar *
2559071d4279SBram Moolenaar * "arg" must point to the first non-white of the expression.
2560fdac71c5SBram Moolenaar * "arg" is advanced to just after the recognized expression.
2561071d4279SBram Moolenaar *
2562071d4279SBram Moolenaar * Return OK or FAIL.
2563071d4279SBram Moolenaar */
2564071d4279SBram Moolenaar static int
eval3(char_u ** arg,typval_T * rettv,evalarg_T * evalarg)25655409f5d8SBram Moolenaar eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
2566071d4279SBram Moolenaar {
2567be7ee488SBram Moolenaar char_u *p;
2568be7ee488SBram Moolenaar int getnext;
2569071d4279SBram Moolenaar
2570071d4279SBram Moolenaar /*
2571071d4279SBram Moolenaar * Get the first variable.
2572071d4279SBram Moolenaar */
25735409f5d8SBram Moolenaar if (eval4(arg, rettv, evalarg) == FAIL)
2574071d4279SBram Moolenaar return FAIL;
2575071d4279SBram Moolenaar
2576071d4279SBram Moolenaar /*
25778af81d65SBram Moolenaar * Handle the "&&" operator.
2578071d4279SBram Moolenaar */
2579be7ee488SBram Moolenaar p = eval_next_non_blank(*arg, evalarg, &getnext);
25808af81d65SBram Moolenaar if (p[0] == '&' && p[1] == '&')
2581071d4279SBram Moolenaar {
25828af81d65SBram Moolenaar evalarg_T *evalarg_used = evalarg;
25838af81d65SBram Moolenaar evalarg_T local_evalarg;
25845409f5d8SBram Moolenaar int orig_flags;
25855409f5d8SBram Moolenaar int evaluate;
25868af81d65SBram Moolenaar long result = TRUE;
25878af81d65SBram Moolenaar typval_T var2;
25882bb2658bSBram Moolenaar int error = FALSE;
25898c34ea54SBram Moolenaar int vim9script = in_vim9script();
2590be7ee488SBram Moolenaar
25915409f5d8SBram Moolenaar if (evalarg == NULL)
25925409f5d8SBram Moolenaar {
2593*844fb64aSBram Moolenaar init_evalarg(&local_evalarg);
25948af81d65SBram Moolenaar evalarg_used = &local_evalarg;
25955409f5d8SBram Moolenaar }
25968af81d65SBram Moolenaar orig_flags = evalarg_used->eval_flags;
25975409f5d8SBram Moolenaar evaluate = orig_flags & EVAL_EVALUATE;
25988af81d65SBram Moolenaar if (evaluate)
2599071d4279SBram Moolenaar {
26008c34ea54SBram Moolenaar if (vim9script)
26012bb2658bSBram Moolenaar result = tv_get_bool_chk(rettv, &error);
26022bb2658bSBram Moolenaar else if (tv_get_number_chk(rettv, &error) == 0)
2603071d4279SBram Moolenaar result = FALSE;
2604c70646c6SBram Moolenaar clear_tv(rettv);
26059ba0eb85SBram Moolenaar if (error)
26069ba0eb85SBram Moolenaar return FAIL;
2607071d4279SBram Moolenaar }
2608071d4279SBram Moolenaar
2609071d4279SBram Moolenaar /*
26108af81d65SBram Moolenaar * Repeat until there is no following "&&".
26118af81d65SBram Moolenaar */
26128af81d65SBram Moolenaar while (p[0] == '&' && p[1] == '&')
26138af81d65SBram Moolenaar {
26148af81d65SBram Moolenaar if (getnext)
26158af81d65SBram Moolenaar *arg = eval_next_line(evalarg_used);
26169d489566SBram Moolenaar else
26173c1c9fd9SBram Moolenaar {
26182bb2658bSBram Moolenaar if (evaluate && vim9script && !VIM_ISWHITE(p[-1]))
26193c1c9fd9SBram Moolenaar {
26203c1c9fd9SBram Moolenaar error_white_both(p, 2);
26213c1c9fd9SBram Moolenaar clear_tv(rettv);
26223c1c9fd9SBram Moolenaar return FAIL;
26233c1c9fd9SBram Moolenaar }
26249d489566SBram Moolenaar *arg = p;
26253c1c9fd9SBram Moolenaar }
26268af81d65SBram Moolenaar
26278af81d65SBram Moolenaar /*
2628071d4279SBram Moolenaar * Get the second variable.
2629071d4279SBram Moolenaar */
26303c1c9fd9SBram Moolenaar if (evaluate && in_vim9script() && !IS_WHITE_OR_NUL((*arg)[2]))
26313c1c9fd9SBram Moolenaar {
26324ac198c6Smityu error_white_both(*arg, 2);
26333c1c9fd9SBram Moolenaar clear_tv(rettv);
26343c1c9fd9SBram Moolenaar return FAIL;
26353c1c9fd9SBram Moolenaar }
26368af81d65SBram Moolenaar *arg = skipwhite_and_linebreak(*arg + 2, evalarg_used);
26378af81d65SBram Moolenaar evalarg_used->eval_flags = result ? orig_flags
26385409f5d8SBram Moolenaar : orig_flags & ~EVAL_EVALUATE;
2639c1ec0422SBram Moolenaar CLEAR_FIELD(var2);
26408af81d65SBram Moolenaar if (eval4(arg, &var2, evalarg_used) == FAIL)
2641071d4279SBram Moolenaar return FAIL;
2642071d4279SBram Moolenaar
2643071d4279SBram Moolenaar /*
2644071d4279SBram Moolenaar * Compute the result.
2645071d4279SBram Moolenaar */
2646071d4279SBram Moolenaar if (evaluate && result)
2647071d4279SBram Moolenaar {
26488c34ea54SBram Moolenaar if (vim9script)
26492bb2658bSBram Moolenaar result = tv_get_bool_chk(&var2, &error);
26502bb2658bSBram Moolenaar else if (tv_get_number_chk(&var2, &error) == 0)
2651071d4279SBram Moolenaar result = FALSE;
2652c70646c6SBram Moolenaar clear_tv(&var2);
26539ba0eb85SBram Moolenaar if (error)
26549ba0eb85SBram Moolenaar return FAIL;
2655071d4279SBram Moolenaar }
26562bb2658bSBram Moolenaar if (evaluate)
26572bb2658bSBram Moolenaar {
26582bb2658bSBram Moolenaar if (vim9script)
26592bb2658bSBram Moolenaar {
26602bb2658bSBram Moolenaar rettv->v_type = VAR_BOOL;
26612bb2658bSBram Moolenaar rettv->vval.v_number = result ? VVAL_TRUE : VVAL_FALSE;
26628c34ea54SBram Moolenaar }
26632bb2658bSBram Moolenaar else
2664071d4279SBram Moolenaar {
2665c70646c6SBram Moolenaar rettv->v_type = VAR_NUMBER;
2666c70646c6SBram Moolenaar rettv->vval.v_number = result;
2667071d4279SBram Moolenaar }
26682bb2658bSBram Moolenaar }
2669be7ee488SBram Moolenaar
26708af81d65SBram Moolenaar p = eval_next_non_blank(*arg, evalarg_used, &getnext);
26718af81d65SBram Moolenaar }
26728af81d65SBram Moolenaar
26738af81d65SBram Moolenaar if (evalarg == NULL)
26748af81d65SBram Moolenaar clear_evalarg(&local_evalarg, NULL);
26758af81d65SBram Moolenaar else
26768af81d65SBram Moolenaar evalarg->eval_flags = orig_flags;
2677071d4279SBram Moolenaar }
2678071d4279SBram Moolenaar
2679071d4279SBram Moolenaar return OK;
2680071d4279SBram Moolenaar }
2681071d4279SBram Moolenaar
2682071d4279SBram Moolenaar /*
2683071d4279SBram Moolenaar * Handle third level expression:
2684071d4279SBram Moolenaar * var1 == var2
2685071d4279SBram Moolenaar * var1 =~ var2
2686071d4279SBram Moolenaar * var1 != var2
2687071d4279SBram Moolenaar * var1 !~ var2
2688071d4279SBram Moolenaar * var1 > var2
2689071d4279SBram Moolenaar * var1 >= var2
2690071d4279SBram Moolenaar * var1 < var2
2691071d4279SBram Moolenaar * var1 <= var2
26928a283e50SBram Moolenaar * var1 is var2
26938a283e50SBram Moolenaar * var1 isnot var2
2694071d4279SBram Moolenaar *
2695071d4279SBram Moolenaar * "arg" must point to the first non-white of the expression.
2696ff1cd39cSBram Moolenaar * "arg" is advanced to just after the recognized expression.
2697071d4279SBram Moolenaar *
2698071d4279SBram Moolenaar * Return OK or FAIL.
2699071d4279SBram Moolenaar */
2700071d4279SBram Moolenaar static int
eval4(char_u ** arg,typval_T * rettv,evalarg_T * evalarg)27015409f5d8SBram Moolenaar eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
2702071d4279SBram Moolenaar {
2703071d4279SBram Moolenaar char_u *p;
2704e6536aa7SBram Moolenaar int getnext;
2705657137caSBram Moolenaar exprtype_T type = EXPR_UNKNOWN;
2706071d4279SBram Moolenaar int len = 2;
2707696ba231SBram Moolenaar int type_is = FALSE;
2708071d4279SBram Moolenaar
2709071d4279SBram Moolenaar /*
2710071d4279SBram Moolenaar * Get the first variable.
2711071d4279SBram Moolenaar */
27125409f5d8SBram Moolenaar if (eval5(arg, rettv, evalarg) == FAIL)
2713071d4279SBram Moolenaar return FAIL;
2714071d4279SBram Moolenaar
2715e6536aa7SBram Moolenaar p = eval_next_non_blank(*arg, evalarg, &getnext);
2716696ba231SBram Moolenaar type = get_compare_type(p, &len, &type_is);
2717071d4279SBram Moolenaar
2718071d4279SBram Moolenaar /*
27198c8de839SBram Moolenaar * If there is a comparative operator, use it.
2720071d4279SBram Moolenaar */
272187396072SBram Moolenaar if (type != EXPR_UNKNOWN)
2722071d4279SBram Moolenaar {
2723c71f36a8SBram Moolenaar typval_T var2;
2724c71f36a8SBram Moolenaar int ic;
2725c71f36a8SBram Moolenaar int vim9script = in_vim9script();
2726ff1cd39cSBram Moolenaar int evaluate = evalarg == NULL
2727ff1cd39cSBram Moolenaar ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
2728c71f36a8SBram Moolenaar
2729e6536aa7SBram Moolenaar if (getnext)
27304ac198c6Smityu {
2731e6536aa7SBram Moolenaar *arg = eval_next_line(evalarg);
27324ac198c6Smityu p = *arg;
27334ac198c6Smityu }
2734ff1cd39cSBram Moolenaar else if (evaluate && vim9script && !VIM_ISWHITE(**arg))
2735ff1cd39cSBram Moolenaar {
27364ac198c6Smityu error_white_both(*arg, len);
2737ff1cd39cSBram Moolenaar clear_tv(rettv);
2738ff1cd39cSBram Moolenaar return FAIL;
2739ff1cd39cSBram Moolenaar }
2740e6536aa7SBram Moolenaar
2741696ba231SBram Moolenaar if (vim9script && type_is && (p[len] == '?' || p[len] == '#'))
2742696ba231SBram Moolenaar {
2743108010aaSBram Moolenaar semsg(_(e_invalid_expression_str), p);
2744696ba231SBram Moolenaar clear_tv(rettv);
2745696ba231SBram Moolenaar return FAIL;
2746696ba231SBram Moolenaar }
2747696ba231SBram Moolenaar
27485d18efecSBram Moolenaar // extra question mark appended: ignore case
2749071d4279SBram Moolenaar if (p[len] == '?')
2750071d4279SBram Moolenaar {
2751071d4279SBram Moolenaar ic = TRUE;
2752071d4279SBram Moolenaar ++len;
2753071d4279SBram Moolenaar }
27545d18efecSBram Moolenaar // extra '#' appended: match case
2755071d4279SBram Moolenaar else if (p[len] == '#')
2756071d4279SBram Moolenaar {
2757071d4279SBram Moolenaar ic = FALSE;
2758071d4279SBram Moolenaar ++len;
2759071d4279SBram Moolenaar }
2760c71f36a8SBram Moolenaar // nothing appended: use 'ignorecase' if not in Vim script
2761071d4279SBram Moolenaar else
2762c71f36a8SBram Moolenaar ic = vim9script ? FALSE : p_ic;
2763071d4279SBram Moolenaar
2764071d4279SBram Moolenaar /*
2765071d4279SBram Moolenaar * Get the second variable.
2766071d4279SBram Moolenaar */
2767ff1cd39cSBram Moolenaar if (evaluate && vim9script && !IS_WHITE_OR_NUL(p[len]))
2768ff1cd39cSBram Moolenaar {
276990193e61SBram Moolenaar error_white_both(p, len);
2770ff1cd39cSBram Moolenaar clear_tv(rettv);
2771ff1cd39cSBram Moolenaar return FAIL;
2772ff1cd39cSBram Moolenaar }
27739215f012SBram Moolenaar *arg = skipwhite_and_linebreak(p + len, evalarg);
27745409f5d8SBram Moolenaar if (eval5(arg, &var2, evalarg) == FAIL)
2775071d4279SBram Moolenaar {
2776c70646c6SBram Moolenaar clear_tv(rettv);
2777071d4279SBram Moolenaar return FAIL;
2778071d4279SBram Moolenaar }
2779ff1cd39cSBram Moolenaar if (evaluate)
278031988701SBram Moolenaar {
2781543e6f34SBram Moolenaar int ret;
278231988701SBram Moolenaar
2783c71f36a8SBram Moolenaar if (vim9script && check_compare_types(type, rettv, &var2) == FAIL)
2784543e6f34SBram Moolenaar {
2785543e6f34SBram Moolenaar ret = FAIL;
2786543e6f34SBram Moolenaar clear_tv(rettv);
2787543e6f34SBram Moolenaar }
2788543e6f34SBram Moolenaar else
2789543e6f34SBram Moolenaar ret = typval_compare(rettv, &var2, type, ic);
279031988701SBram Moolenaar clear_tv(&var2);
279131988701SBram Moolenaar return ret;
279231988701SBram Moolenaar }
2793071d4279SBram Moolenaar }
2794071d4279SBram Moolenaar
2795071d4279SBram Moolenaar return OK;
2796071d4279SBram Moolenaar }
2797071d4279SBram Moolenaar
2798081db1a6SBram Moolenaar /*
2799081db1a6SBram Moolenaar * Make a copy of blob "tv1" and append blob "tv2".
2800081db1a6SBram Moolenaar */
28018a7d6542SBram Moolenaar void
eval_addblob(typval_T * tv1,typval_T * tv2)28028a7d6542SBram Moolenaar eval_addblob(typval_T *tv1, typval_T *tv2)
28038a7d6542SBram Moolenaar {
28048a7d6542SBram Moolenaar blob_T *b1 = tv1->vval.v_blob;
28058a7d6542SBram Moolenaar blob_T *b2 = tv2->vval.v_blob;
28068a7d6542SBram Moolenaar blob_T *b = blob_alloc();
28078a7d6542SBram Moolenaar int i;
28088a7d6542SBram Moolenaar
28098a7d6542SBram Moolenaar if (b != NULL)
28108a7d6542SBram Moolenaar {
28118a7d6542SBram Moolenaar for (i = 0; i < blob_len(b1); i++)
28128a7d6542SBram Moolenaar ga_append(&b->bv_ga, blob_get(b1, i));
28138a7d6542SBram Moolenaar for (i = 0; i < blob_len(b2); i++)
28148a7d6542SBram Moolenaar ga_append(&b->bv_ga, blob_get(b2, i));
28158a7d6542SBram Moolenaar
28168a7d6542SBram Moolenaar clear_tv(tv1);
28178a7d6542SBram Moolenaar rettv_blob_set(tv1, b);
28188a7d6542SBram Moolenaar }
28198a7d6542SBram Moolenaar }
28208a7d6542SBram Moolenaar
2821081db1a6SBram Moolenaar /*
2822081db1a6SBram Moolenaar * Make a copy of list "tv1" and append list "tv2".
2823081db1a6SBram Moolenaar */
28248a7d6542SBram Moolenaar int
eval_addlist(typval_T * tv1,typval_T * tv2)28258a7d6542SBram Moolenaar eval_addlist(typval_T *tv1, typval_T *tv2)
28268a7d6542SBram Moolenaar {
28278a7d6542SBram Moolenaar typval_T var3;
28288a7d6542SBram Moolenaar
28298a7d6542SBram Moolenaar // concatenate Lists
28308a7d6542SBram Moolenaar if (list_concat(tv1->vval.v_list, tv2->vval.v_list, &var3) == FAIL)
28318a7d6542SBram Moolenaar {
28328a7d6542SBram Moolenaar clear_tv(tv1);
28338a7d6542SBram Moolenaar clear_tv(tv2);
28348a7d6542SBram Moolenaar return FAIL;
28358a7d6542SBram Moolenaar }
28368a7d6542SBram Moolenaar clear_tv(tv1);
28378a7d6542SBram Moolenaar *tv1 = var3;
28388a7d6542SBram Moolenaar return OK;
28398a7d6542SBram Moolenaar }
28408a7d6542SBram Moolenaar
2841071d4279SBram Moolenaar /*
2842071d4279SBram Moolenaar * Handle fourth level expression:
2843071d4279SBram Moolenaar * + number addition
2844071d4279SBram Moolenaar * - number subtraction
2845558ca4aeSBram Moolenaar * . string concatenation (if script version is 1)
28460f248b00SBram Moolenaar * .. string concatenation
2847071d4279SBram Moolenaar *
2848071d4279SBram Moolenaar * "arg" must point to the first non-white of the expression.
2849ff1cd39cSBram Moolenaar * "arg" is advanced to just after the recognized expression.
2850071d4279SBram Moolenaar *
2851071d4279SBram Moolenaar * Return OK or FAIL.
2852071d4279SBram Moolenaar */
2853071d4279SBram Moolenaar static int
eval5(char_u ** arg,typval_T * rettv,evalarg_T * evalarg)28545409f5d8SBram Moolenaar eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
2855071d4279SBram Moolenaar {
2856071d4279SBram Moolenaar /*
2857071d4279SBram Moolenaar * Get the first variable.
2858071d4279SBram Moolenaar */
28595409f5d8SBram Moolenaar if (eval6(arg, rettv, evalarg, FALSE) == FAIL)
2860071d4279SBram Moolenaar return FAIL;
2861071d4279SBram Moolenaar
2862071d4279SBram Moolenaar /*
2863071d4279SBram Moolenaar * Repeat computing, until no '+', '-' or '.' is following.
2864071d4279SBram Moolenaar */
2865071d4279SBram Moolenaar for (;;)
2866071d4279SBram Moolenaar {
28673ac9c470SBram Moolenaar int evaluate;
28685409f5d8SBram Moolenaar int getnext;
28695409f5d8SBram Moolenaar char_u *p;
28705409f5d8SBram Moolenaar int op;
2871bb1b5e24SBram Moolenaar int oplen;
28725409f5d8SBram Moolenaar int concat;
28735409f5d8SBram Moolenaar typval_T var2;
28742e086612SBram Moolenaar int vim9script = in_vim9script();
28755409f5d8SBram Moolenaar
2876558ca4aeSBram Moolenaar // "." is only string concatenation when scriptversion is 1
2877f76ec1eeSBram Moolenaar // "+=", "-=" and "..=" are assignments
2878bdc0f1c6SBram Moolenaar // "++" and "--" on the next line are a separate command.
28795409f5d8SBram Moolenaar p = eval_next_non_blank(*arg, evalarg, &getnext);
28805409f5d8SBram Moolenaar op = *p;
2881dd9de50fSBram Moolenaar concat = op == '.' && (*(p + 1) == '.' || in_old_script(2));
2882f76ec1eeSBram Moolenaar if ((op != '+' && op != '-' && !concat) || p[1] == '='
2883f76ec1eeSBram Moolenaar || (p[1] == '.' && p[2] == '='))
2884071d4279SBram Moolenaar break;
2885bdc0f1c6SBram Moolenaar if (getnext && (op == '+' || op == '-') && p[0] == p[1])
2886bdc0f1c6SBram Moolenaar break;
28873ac9c470SBram Moolenaar
2888bb1b5e24SBram Moolenaar evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
2889b4caa163SBram Moolenaar oplen = (concat && p[1] == '.') ? 2 : 1;
28905409f5d8SBram Moolenaar if (getnext)
2891b171fb17SBram Moolenaar *arg = eval_next_line(evalarg);
28929d489566SBram Moolenaar else
2893bb1b5e24SBram Moolenaar {
28942e086612SBram Moolenaar if (evaluate && vim9script && !VIM_ISWHITE(**arg))
2895bb1b5e24SBram Moolenaar {
28964ac198c6Smityu error_white_both(*arg, oplen);
2897bb1b5e24SBram Moolenaar clear_tv(rettv);
2898bb1b5e24SBram Moolenaar return FAIL;
2899bb1b5e24SBram Moolenaar }
29009d489566SBram Moolenaar *arg = p;
2901bb1b5e24SBram Moolenaar }
29026e5ea8d2SBram Moolenaar if ((op != '+' || (rettv->v_type != VAR_LIST
29036e5ea8d2SBram Moolenaar && rettv->v_type != VAR_BLOB))
29048c8de839SBram Moolenaar #ifdef FEAT_FLOAT
29058c8de839SBram Moolenaar && (op == '.' || rettv->v_type != VAR_FLOAT)
29068c8de839SBram Moolenaar #endif
2907081db1a6SBram Moolenaar && evaluate)
29089ba0eb85SBram Moolenaar {
2909081db1a6SBram Moolenaar int error = FALSE;
2910081db1a6SBram Moolenaar
29115d18efecSBram Moolenaar // For "list + ...", an illegal use of the first operand as
29125d18efecSBram Moolenaar // a number cannot be determined before evaluating the 2nd
29135d18efecSBram Moolenaar // operand: if this is also a list, all is ok.
29145d18efecSBram Moolenaar // For "something . ...", "something - ..." or "non-list + ...",
29155d18efecSBram Moolenaar // we know that the first operand needs to be a string or number
29165d18efecSBram Moolenaar // without evaluating the 2nd operand. So check before to avoid
29175d18efecSBram Moolenaar // side effects after an error.
2918081db1a6SBram Moolenaar if (op != '.')
2919081db1a6SBram Moolenaar tv_get_number_chk(rettv, &error);
2920081db1a6SBram Moolenaar if ((op == '.' && tv_get_string_chk(rettv) == NULL) || error)
29219ba0eb85SBram Moolenaar {
29229ba0eb85SBram Moolenaar clear_tv(rettv);
29239ba0eb85SBram Moolenaar return FAIL;
29249ba0eb85SBram Moolenaar }
29259ba0eb85SBram Moolenaar }
29269ba0eb85SBram Moolenaar
2927071d4279SBram Moolenaar /*
2928071d4279SBram Moolenaar * Get the second variable.
2929071d4279SBram Moolenaar */
29302e086612SBram Moolenaar if (evaluate && vim9script && !IS_WHITE_OR_NUL((*arg)[oplen]))
2931bb1b5e24SBram Moolenaar {
293289dcb4dcSmityu error_white_both(*arg, oplen);
2933bb1b5e24SBram Moolenaar clear_tv(rettv);
2934bb1b5e24SBram Moolenaar return FAIL;
2935bb1b5e24SBram Moolenaar }
2936bb1b5e24SBram Moolenaar *arg = skipwhite_and_linebreak(*arg + oplen, evalarg);
29372e086612SBram Moolenaar if (eval6(arg, &var2, evalarg, !vim9script && op == '.') == FAIL)
2938071d4279SBram Moolenaar {
2939c70646c6SBram Moolenaar clear_tv(rettv);
2940071d4279SBram Moolenaar return FAIL;
2941071d4279SBram Moolenaar }
2942071d4279SBram Moolenaar
29435409f5d8SBram Moolenaar if (evaluate)
2944071d4279SBram Moolenaar {
2945071d4279SBram Moolenaar /*
2946071d4279SBram Moolenaar * Compute the result.
2947071d4279SBram Moolenaar */
2948071d4279SBram Moolenaar if (op == '.')
2949071d4279SBram Moolenaar {
29505409f5d8SBram Moolenaar char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
29515409f5d8SBram Moolenaar char_u *s1 = tv_get_string_buf(rettv, buf1);
2952418f1df5SBram Moolenaar char_u *s2 = NULL;
29535409f5d8SBram Moolenaar
29542e086612SBram Moolenaar if (vim9script && (var2.v_type == VAR_VOID
2955418f1df5SBram Moolenaar || var2.v_type == VAR_CHANNEL
2956418f1df5SBram Moolenaar || var2.v_type == VAR_JOB))
295768db996bSBram Moolenaar semsg(_(e_using_invalid_value_as_string_str),
295868db996bSBram Moolenaar vartype_name(var2.v_type));
2959418f1df5SBram Moolenaar #ifdef FEAT_FLOAT
29602e086612SBram Moolenaar else if (vim9script && var2.v_type == VAR_FLOAT)
2961418f1df5SBram Moolenaar {
2962418f1df5SBram Moolenaar vim_snprintf((char *)buf2, NUMBUFLEN, "%g",
2963418f1df5SBram Moolenaar var2.vval.v_float);
2964418f1df5SBram Moolenaar s2 = buf2;
2965418f1df5SBram Moolenaar }
2966418f1df5SBram Moolenaar #endif
2967418f1df5SBram Moolenaar else
2968418f1df5SBram Moolenaar s2 = tv_get_string_buf_chk(&var2, buf2);
29695d18efecSBram Moolenaar if (s2 == NULL) // type error ?
29709ba0eb85SBram Moolenaar {
29719ba0eb85SBram Moolenaar clear_tv(rettv);
29729ba0eb85SBram Moolenaar clear_tv(&var2);
29739ba0eb85SBram Moolenaar return FAIL;
29749ba0eb85SBram Moolenaar }
29759ef486dbSBram Moolenaar p = concat_str(s1, s2);
2976c70646c6SBram Moolenaar clear_tv(rettv);
2977c70646c6SBram Moolenaar rettv->v_type = VAR_STRING;
2978c70646c6SBram Moolenaar rettv->vval.v_string = p;
2979071d4279SBram Moolenaar }
29806e5ea8d2SBram Moolenaar else if (op == '+' && rettv->v_type == VAR_BLOB
29816e5ea8d2SBram Moolenaar && var2.v_type == VAR_BLOB)
29828a7d6542SBram Moolenaar eval_addblob(rettv, &var2);
2983e9a41264SBram Moolenaar else if (op == '+' && rettv->v_type == VAR_LIST
2984e9a41264SBram Moolenaar && var2.v_type == VAR_LIST)
29858a283e50SBram Moolenaar {
29868a7d6542SBram Moolenaar if (eval_addlist(rettv, &var2) == FAIL)
29878a283e50SBram Moolenaar return FAIL;
29888a283e50SBram Moolenaar }
2989071d4279SBram Moolenaar else
2990071d4279SBram Moolenaar {
29919ba0eb85SBram Moolenaar int error = FALSE;
29925409f5d8SBram Moolenaar varnumber_T n1, n2;
29938c8de839SBram Moolenaar #ifdef FEAT_FLOAT
29945409f5d8SBram Moolenaar float_T f1 = 0, f2 = 0;
29955409f5d8SBram Moolenaar
29968c8de839SBram Moolenaar if (rettv->v_type == VAR_FLOAT)
29978c8de839SBram Moolenaar {
29988c8de839SBram Moolenaar f1 = rettv->vval.v_float;
29998c8de839SBram Moolenaar n1 = 0;
30008c8de839SBram Moolenaar }
30018c8de839SBram Moolenaar else
30028c8de839SBram Moolenaar #endif
30038c8de839SBram Moolenaar {
3004d155d7a8SBram Moolenaar n1 = tv_get_number_chk(rettv, &error);
30059ba0eb85SBram Moolenaar if (error)
30069ba0eb85SBram Moolenaar {
3007f2dd9cb9SBram Moolenaar // This can only happen for "list + non-list" or
3008f2dd9cb9SBram Moolenaar // "blob + non-blob". For "non-list + ..." or
3009f2dd9cb9SBram Moolenaar // "something - ...", we returned before evaluating the
3010f2dd9cb9SBram Moolenaar // 2nd operand.
30119ba0eb85SBram Moolenaar clear_tv(rettv);
3012f2dd9cb9SBram Moolenaar clear_tv(&var2);
30139ba0eb85SBram Moolenaar return FAIL;
30149ba0eb85SBram Moolenaar }
30158c8de839SBram Moolenaar #ifdef FEAT_FLOAT
30168c8de839SBram Moolenaar if (var2.v_type == VAR_FLOAT)
30178c8de839SBram Moolenaar f1 = n1;
30188c8de839SBram Moolenaar #endif
30198c8de839SBram Moolenaar }
30208c8de839SBram Moolenaar #ifdef FEAT_FLOAT
30218c8de839SBram Moolenaar if (var2.v_type == VAR_FLOAT)
30228c8de839SBram Moolenaar {
30238c8de839SBram Moolenaar f2 = var2.vval.v_float;
30248c8de839SBram Moolenaar n2 = 0;
30258c8de839SBram Moolenaar }
30268c8de839SBram Moolenaar else
30278c8de839SBram Moolenaar #endif
30288c8de839SBram Moolenaar {
3029d155d7a8SBram Moolenaar n2 = tv_get_number_chk(&var2, &error);
30309ba0eb85SBram Moolenaar if (error)
30319ba0eb85SBram Moolenaar {
30329ba0eb85SBram Moolenaar clear_tv(rettv);
30339ba0eb85SBram Moolenaar clear_tv(&var2);
30349ba0eb85SBram Moolenaar return FAIL;
30359ba0eb85SBram Moolenaar }
30368c8de839SBram Moolenaar #ifdef FEAT_FLOAT
30378c8de839SBram Moolenaar if (rettv->v_type == VAR_FLOAT)
30388c8de839SBram Moolenaar f2 = n2;
30398c8de839SBram Moolenaar #endif
30408c8de839SBram Moolenaar }
3041c70646c6SBram Moolenaar clear_tv(rettv);
30428c8de839SBram Moolenaar
30438c8de839SBram Moolenaar #ifdef FEAT_FLOAT
30445d18efecSBram Moolenaar // If there is a float on either side the result is a float.
30458c8de839SBram Moolenaar if (rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT)
30468c8de839SBram Moolenaar {
30478c8de839SBram Moolenaar if (op == '+')
30488c8de839SBram Moolenaar f1 = f1 + f2;
30498c8de839SBram Moolenaar else
30508c8de839SBram Moolenaar f1 = f1 - f2;
30518c8de839SBram Moolenaar rettv->v_type = VAR_FLOAT;
30528c8de839SBram Moolenaar rettv->vval.v_float = f1;
30538c8de839SBram Moolenaar }
30548c8de839SBram Moolenaar else
30558c8de839SBram Moolenaar #endif
30568c8de839SBram Moolenaar {
3057071d4279SBram Moolenaar if (op == '+')
3058071d4279SBram Moolenaar n1 = n1 + n2;
3059071d4279SBram Moolenaar else
3060071d4279SBram Moolenaar n1 = n1 - n2;
3061c70646c6SBram Moolenaar rettv->v_type = VAR_NUMBER;
3062c70646c6SBram Moolenaar rettv->vval.v_number = n1;
3063071d4279SBram Moolenaar }
30648c8de839SBram Moolenaar }
3065c70646c6SBram Moolenaar clear_tv(&var2);
3066071d4279SBram Moolenaar }
3067071d4279SBram Moolenaar }
3068071d4279SBram Moolenaar return OK;
3069071d4279SBram Moolenaar }
3070071d4279SBram Moolenaar
3071071d4279SBram Moolenaar /*
3072071d4279SBram Moolenaar * Handle fifth level expression:
3073071d4279SBram Moolenaar * * number multiplication
3074071d4279SBram Moolenaar * / number division
3075071d4279SBram Moolenaar * % number modulo
3076071d4279SBram Moolenaar *
3077071d4279SBram Moolenaar * "arg" must point to the first non-white of the expression.
3078ff1cd39cSBram Moolenaar * "arg" is advanced to just after the recognized expression.
3079071d4279SBram Moolenaar *
3080071d4279SBram Moolenaar * Return OK or FAIL.
3081071d4279SBram Moolenaar */
3082071d4279SBram Moolenaar static int
eval6(char_u ** arg,typval_T * rettv,evalarg_T * evalarg,int want_string)30837454a06eSBram Moolenaar eval6(
30847454a06eSBram Moolenaar char_u **arg,
30857454a06eSBram Moolenaar typval_T *rettv,
30865409f5d8SBram Moolenaar evalarg_T *evalarg,
30875d18efecSBram Moolenaar int want_string) // after "." operator
3088071d4279SBram Moolenaar {
30898c8de839SBram Moolenaar #ifdef FEAT_FLOAT
30908c8de839SBram Moolenaar int use_float = FALSE;
30918c8de839SBram Moolenaar #endif
3092071d4279SBram Moolenaar
3093071d4279SBram Moolenaar /*
3094071d4279SBram Moolenaar * Get the first variable.
3095071d4279SBram Moolenaar */
3096459fbdbfSBram Moolenaar if (eval7t(arg, rettv, evalarg, want_string) == FAIL)
3097071d4279SBram Moolenaar return FAIL;
3098071d4279SBram Moolenaar
3099071d4279SBram Moolenaar /*
3100071d4279SBram Moolenaar * Repeat computing, until no '*', '/' or '%' is following.
3101071d4279SBram Moolenaar */
3102071d4279SBram Moolenaar for (;;)
3103071d4279SBram Moolenaar {
31043ac9c470SBram Moolenaar int evaluate;
31055409f5d8SBram Moolenaar int getnext;
31063ac9c470SBram Moolenaar typval_T var2;
31079d489566SBram Moolenaar char_u *p;
31083ac9c470SBram Moolenaar int op;
31093ac9c470SBram Moolenaar varnumber_T n1, n2;
31103ac9c470SBram Moolenaar #ifdef FEAT_FLOAT
31113ac9c470SBram Moolenaar float_T f1, f2;
31123ac9c470SBram Moolenaar #endif
31133ac9c470SBram Moolenaar int error;
31145409f5d8SBram Moolenaar
3115f76ec1eeSBram Moolenaar // "*=", "/=" and "%=" are assignments
31169d489566SBram Moolenaar p = eval_next_non_blank(*arg, evalarg, &getnext);
31179d489566SBram Moolenaar op = *p;
3118f76ec1eeSBram Moolenaar if ((op != '*' && op != '/' && op != '%') || p[1] == '=')
3119071d4279SBram Moolenaar break;
31203ac9c470SBram Moolenaar
3121b4caa163SBram Moolenaar evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
31225409f5d8SBram Moolenaar if (getnext)
3123b171fb17SBram Moolenaar *arg = eval_next_line(evalarg);
31249d489566SBram Moolenaar else
3125b4caa163SBram Moolenaar {
3126b4caa163SBram Moolenaar if (evaluate && in_vim9script() && !VIM_ISWHITE(**arg))
3127b4caa163SBram Moolenaar {
31284ac198c6Smityu error_white_both(*arg, 1);
3129b4caa163SBram Moolenaar clear_tv(rettv);
3130b4caa163SBram Moolenaar return FAIL;
3131b4caa163SBram Moolenaar }
31329d489566SBram Moolenaar *arg = p;
3133b4caa163SBram Moolenaar }
3134071d4279SBram Moolenaar
31353ac9c470SBram Moolenaar #ifdef FEAT_FLOAT
31363ac9c470SBram Moolenaar f1 = 0;
31373ac9c470SBram Moolenaar f2 = 0;
31383ac9c470SBram Moolenaar #endif
31393ac9c470SBram Moolenaar error = FALSE;
31405409f5d8SBram Moolenaar if (evaluate)
3141071d4279SBram Moolenaar {
31428c8de839SBram Moolenaar #ifdef FEAT_FLOAT
31438c8de839SBram Moolenaar if (rettv->v_type == VAR_FLOAT)
31448c8de839SBram Moolenaar {
31458c8de839SBram Moolenaar f1 = rettv->vval.v_float;
31468c8de839SBram Moolenaar use_float = TRUE;
31478c8de839SBram Moolenaar n1 = 0;
31488c8de839SBram Moolenaar }
31498c8de839SBram Moolenaar else
31508c8de839SBram Moolenaar #endif
3151d155d7a8SBram Moolenaar n1 = tv_get_number_chk(rettv, &error);
3152c70646c6SBram Moolenaar clear_tv(rettv);
31539ba0eb85SBram Moolenaar if (error)
31549ba0eb85SBram Moolenaar return FAIL;
3155071d4279SBram Moolenaar }
3156071d4279SBram Moolenaar else
3157071d4279SBram Moolenaar n1 = 0;
3158071d4279SBram Moolenaar
3159071d4279SBram Moolenaar /*
3160071d4279SBram Moolenaar * Get the second variable.
3161071d4279SBram Moolenaar */
3162b4caa163SBram Moolenaar if (evaluate && in_vim9script() && !IS_WHITE_OR_NUL((*arg)[1]))
3163b4caa163SBram Moolenaar {
3164a9749534SBram Moolenaar error_white_both(*arg, 1);
3165b4caa163SBram Moolenaar clear_tv(rettv);
3166b4caa163SBram Moolenaar return FAIL;
3167b4caa163SBram Moolenaar }
3168b4caa163SBram Moolenaar *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
3169459fbdbfSBram Moolenaar if (eval7t(arg, &var2, evalarg, FALSE) == FAIL)
3170071d4279SBram Moolenaar return FAIL;
3171071d4279SBram Moolenaar
31725409f5d8SBram Moolenaar if (evaluate)
3173071d4279SBram Moolenaar {
31748c8de839SBram Moolenaar #ifdef FEAT_FLOAT
31758c8de839SBram Moolenaar if (var2.v_type == VAR_FLOAT)
31768c8de839SBram Moolenaar {
31778c8de839SBram Moolenaar if (!use_float)
31788c8de839SBram Moolenaar {
31798c8de839SBram Moolenaar f1 = n1;
31808c8de839SBram Moolenaar use_float = TRUE;
31818c8de839SBram Moolenaar }
31828c8de839SBram Moolenaar f2 = var2.vval.v_float;
31838c8de839SBram Moolenaar n2 = 0;
31848c8de839SBram Moolenaar }
31858c8de839SBram Moolenaar else
31868c8de839SBram Moolenaar #endif
31878c8de839SBram Moolenaar {
3188d155d7a8SBram Moolenaar n2 = tv_get_number_chk(&var2, &error);
3189c70646c6SBram Moolenaar clear_tv(&var2);
31909ba0eb85SBram Moolenaar if (error)
31919ba0eb85SBram Moolenaar return FAIL;
31928c8de839SBram Moolenaar #ifdef FEAT_FLOAT
31938c8de839SBram Moolenaar if (use_float)
31948c8de839SBram Moolenaar f2 = n2;
31958c8de839SBram Moolenaar #endif
31968c8de839SBram Moolenaar }
3197071d4279SBram Moolenaar
3198071d4279SBram Moolenaar /*
3199071d4279SBram Moolenaar * Compute the result.
32008c8de839SBram Moolenaar * When either side is a float the result is a float.
3201071d4279SBram Moolenaar */
32028c8de839SBram Moolenaar #ifdef FEAT_FLOAT
32038c8de839SBram Moolenaar if (use_float)
32048c8de839SBram Moolenaar {
32058c8de839SBram Moolenaar if (op == '*')
32068c8de839SBram Moolenaar f1 = f1 * f2;
32078c8de839SBram Moolenaar else if (op == '/')
32088c8de839SBram Moolenaar {
3209f878bcfbSBram Moolenaar # ifdef VMS
32105d18efecSBram Moolenaar // VMS crashes on divide by zero, work around it
3211f878bcfbSBram Moolenaar if (f2 == 0.0)
3212f878bcfbSBram Moolenaar {
3213f878bcfbSBram Moolenaar if (f1 == 0)
32145d18efecSBram Moolenaar f1 = -1 * __F_FLT_MAX - 1L; // similar to NaN
3215f878bcfbSBram Moolenaar else if (f1 < 0)
3216314f11d4SBram Moolenaar f1 = -1 * __F_FLT_MAX;
3217f878bcfbSBram Moolenaar else
3218314f11d4SBram Moolenaar f1 = __F_FLT_MAX;
3219f878bcfbSBram Moolenaar }
3220f878bcfbSBram Moolenaar else
3221f878bcfbSBram Moolenaar f1 = f1 / f2;
3222f878bcfbSBram Moolenaar # else
32235d18efecSBram Moolenaar // We rely on the floating point library to handle divide
32245d18efecSBram Moolenaar // by zero to result in "inf" and not a crash.
32258c8de839SBram Moolenaar f1 = f1 / f2;
3226f878bcfbSBram Moolenaar # endif
32278c8de839SBram Moolenaar }
32288c8de839SBram Moolenaar else
32298c8de839SBram Moolenaar {
32308a7d6542SBram Moolenaar emsg(_(e_modulus));
32318c8de839SBram Moolenaar return FAIL;
32328c8de839SBram Moolenaar }
32338c8de839SBram Moolenaar rettv->v_type = VAR_FLOAT;
32348c8de839SBram Moolenaar rettv->vval.v_float = f1;
32358c8de839SBram Moolenaar }
32368c8de839SBram Moolenaar else
32378c8de839SBram Moolenaar #endif
32388c8de839SBram Moolenaar {
3239c5f59fabSBram Moolenaar int failed = FALSE;
3240c5f59fabSBram Moolenaar
3241071d4279SBram Moolenaar if (op == '*')
3242071d4279SBram Moolenaar n1 = n1 * n2;
3243071d4279SBram Moolenaar else if (op == '/')
3244c5f59fabSBram Moolenaar n1 = num_divide(n1, n2, &failed);
324522fcfad2SBram Moolenaar else
3246c5f59fabSBram Moolenaar n1 = num_modulus(n1, n2, &failed);
3247c5f59fabSBram Moolenaar if (failed)
3248c5f59fabSBram Moolenaar return FAIL;
3249e21c1580SBram Moolenaar
3250c70646c6SBram Moolenaar rettv->v_type = VAR_NUMBER;
3251c70646c6SBram Moolenaar rettv->vval.v_number = n1;
3252071d4279SBram Moolenaar }
3253071d4279SBram Moolenaar }
32548c8de839SBram Moolenaar }
3255071d4279SBram Moolenaar
3256071d4279SBram Moolenaar return OK;
3257071d4279SBram Moolenaar }
3258071d4279SBram Moolenaar
3259459fbdbfSBram Moolenaar /*
3260459fbdbfSBram Moolenaar * Handle a type cast before a base level expression.
3261459fbdbfSBram Moolenaar * "arg" must point to the first non-white of the expression.
3262459fbdbfSBram Moolenaar * "arg" is advanced to just after the recognized expression.
3263459fbdbfSBram Moolenaar * Return OK or FAIL.
3264459fbdbfSBram Moolenaar */
3265459fbdbfSBram Moolenaar static int
eval7t(char_u ** arg,typval_T * rettv,evalarg_T * evalarg,int want_string)3266459fbdbfSBram Moolenaar eval7t(
3267459fbdbfSBram Moolenaar char_u **arg,
3268459fbdbfSBram Moolenaar typval_T *rettv,
3269459fbdbfSBram Moolenaar evalarg_T *evalarg,
3270459fbdbfSBram Moolenaar int want_string) // after "." operator
3271459fbdbfSBram Moolenaar {
3272459fbdbfSBram Moolenaar type_T *want_type = NULL;
3273459fbdbfSBram Moolenaar garray_T type_list; // list of pointers to allocated types
3274459fbdbfSBram Moolenaar int res;
3275459fbdbfSBram Moolenaar int evaluate = evalarg == NULL ? 0
3276459fbdbfSBram Moolenaar : (evalarg->eval_flags & EVAL_EVALUATE);
3277459fbdbfSBram Moolenaar
3278459fbdbfSBram Moolenaar // Recognize <type> in Vim9 script only.
3279678b207fSBram Moolenaar if (in_vim9script() && **arg == '<' && eval_isnamec1((*arg)[1])
3280678b207fSBram Moolenaar && STRNCMP(*arg, "<SNR>", 5) != 0)
3281459fbdbfSBram Moolenaar {
3282459fbdbfSBram Moolenaar ++*arg;
3283459fbdbfSBram Moolenaar ga_init2(&type_list, sizeof(type_T *), 10);
3284459fbdbfSBram Moolenaar want_type = parse_type(arg, &type_list, TRUE);
3285459fbdbfSBram Moolenaar if (want_type == NULL && (evaluate || **arg != '>'))
3286459fbdbfSBram Moolenaar {
3287459fbdbfSBram Moolenaar clear_type_list(&type_list);
3288459fbdbfSBram Moolenaar return FAIL;
3289459fbdbfSBram Moolenaar }
3290459fbdbfSBram Moolenaar
3291459fbdbfSBram Moolenaar if (**arg != '>')
3292459fbdbfSBram Moolenaar {
3293459fbdbfSBram Moolenaar if (*skipwhite(*arg) == '>')
3294459fbdbfSBram Moolenaar semsg(_(e_no_white_space_allowed_before_str_str), ">", *arg);
3295459fbdbfSBram Moolenaar else
3296459fbdbfSBram Moolenaar emsg(_(e_missing_gt));
3297459fbdbfSBram Moolenaar clear_type_list(&type_list);
3298459fbdbfSBram Moolenaar return FAIL;
3299459fbdbfSBram Moolenaar }
3300459fbdbfSBram Moolenaar ++*arg;
3301459fbdbfSBram Moolenaar *arg = skipwhite_and_linebreak(*arg, evalarg);
3302459fbdbfSBram Moolenaar }
3303459fbdbfSBram Moolenaar
3304459fbdbfSBram Moolenaar res = eval7(arg, rettv, evalarg, want_string);
3305459fbdbfSBram Moolenaar
3306459fbdbfSBram Moolenaar if (want_type != NULL && evaluate)
3307459fbdbfSBram Moolenaar {
3308459fbdbfSBram Moolenaar if (res == OK)
3309459fbdbfSBram Moolenaar {
3310459fbdbfSBram Moolenaar type_T *actual = typval2type(rettv, get_copyID(), &type_list, TRUE);
3311459fbdbfSBram Moolenaar
331260dc8274SBram Moolenaar if (!equal_type(want_type, actual, 0))
3313459fbdbfSBram Moolenaar {
3314459fbdbfSBram Moolenaar if (want_type == &t_bool && actual != &t_bool
3315459fbdbfSBram Moolenaar && (actual->tt_flags & TTFLAG_BOOL_OK))
3316459fbdbfSBram Moolenaar {
3317459fbdbfSBram Moolenaar int n = tv2bool(rettv);
3318459fbdbfSBram Moolenaar
3319459fbdbfSBram Moolenaar // can use "0" and "1" for boolean in some places
3320459fbdbfSBram Moolenaar clear_tv(rettv);
3321459fbdbfSBram Moolenaar rettv->v_type = VAR_BOOL;
3322459fbdbfSBram Moolenaar rettv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
3323459fbdbfSBram Moolenaar }
3324459fbdbfSBram Moolenaar else
3325459fbdbfSBram Moolenaar {
33262b59df00SBram Moolenaar where_T where = WHERE_INIT;
3327459fbdbfSBram Moolenaar
3328459fbdbfSBram Moolenaar where.wt_variable = TRUE;
3329459fbdbfSBram Moolenaar res = check_type(want_type, actual, TRUE, where);
3330459fbdbfSBram Moolenaar }
3331459fbdbfSBram Moolenaar }
3332459fbdbfSBram Moolenaar }
3333459fbdbfSBram Moolenaar clear_type_list(&type_list);
3334459fbdbfSBram Moolenaar }
3335459fbdbfSBram Moolenaar
3336459fbdbfSBram Moolenaar return res;
3337459fbdbfSBram Moolenaar }
3338459fbdbfSBram Moolenaar
3339b23279d7SBram Moolenaar int
eval_leader(char_u ** arg,int vim9)3340b23279d7SBram Moolenaar eval_leader(char_u **arg, int vim9)
3341b23279d7SBram Moolenaar {
3342b23279d7SBram Moolenaar char_u *s = *arg;
3343b23279d7SBram Moolenaar char_u *p = *arg;
3344b23279d7SBram Moolenaar
3345b23279d7SBram Moolenaar while (*p == '!' || *p == '-' || *p == '+')
3346b23279d7SBram Moolenaar {
3347b23279d7SBram Moolenaar char_u *n = skipwhite(p + 1);
3348b23279d7SBram Moolenaar
3349b23279d7SBram Moolenaar // ++, --, -+ and +- are not accepted in Vim9 script
3350b23279d7SBram Moolenaar if (vim9 && (*p == '-' || *p == '+') && (*n == '-' || *n == '+'))
3351b23279d7SBram Moolenaar {
3352108010aaSBram Moolenaar semsg(_(e_invalid_expression_str), s);
3353b23279d7SBram Moolenaar return FAIL;
3354b23279d7SBram Moolenaar }
3355b23279d7SBram Moolenaar p = n;
3356b23279d7SBram Moolenaar }
3357b23279d7SBram Moolenaar *arg = p;
3358b23279d7SBram Moolenaar return OK;
3359b23279d7SBram Moolenaar }
3360b23279d7SBram Moolenaar
3361071d4279SBram Moolenaar /*
3362071d4279SBram Moolenaar * Handle sixth level expression:
3363071d4279SBram Moolenaar * number number constant
33646e5ea8d2SBram Moolenaar * 0zFFFFFFFF Blob constant
3365bae0c16cSBram Moolenaar * "string" string constant
3366bae0c16cSBram Moolenaar * 'string' literal string constant
3367071d4279SBram Moolenaar * &option-name option value
3368071d4279SBram Moolenaar * @r register contents
3369071d4279SBram Moolenaar * identifier variable value
3370071d4279SBram Moolenaar * function() function call
3371071d4279SBram Moolenaar * $VAR environment variable
3372071d4279SBram Moolenaar * (expression) nested expression
33732e6aff38SBram Moolenaar * [expr, expr] List
33748a7d6542SBram Moolenaar * {arg, arg -> expr} Lambda
33752e6aff38SBram Moolenaar * {key: val, key: val} Dictionary
33764c6d9045SBram Moolenaar * #{key: val, key: val} Dictionary with literal keys
3377071d4279SBram Moolenaar *
3378071d4279SBram Moolenaar * Also handle:
3379071d4279SBram Moolenaar * ! in front logical NOT
3380071d4279SBram Moolenaar * - in front unary minus
3381071d4279SBram Moolenaar * + in front unary plus (ignored)
33828c711458SBram Moolenaar * trailing [] subscript in String or List
33838c711458SBram Moolenaar * trailing .name entry in Dictionary
3384ac92e25aSBram Moolenaar * trailing ->name() method call
3385071d4279SBram Moolenaar *
3386071d4279SBram Moolenaar * "arg" must point to the first non-white of the expression.
3387ff1cd39cSBram Moolenaar * "arg" is advanced to just after the recognized expression.
3388071d4279SBram Moolenaar *
3389071d4279SBram Moolenaar * Return OK or FAIL.
3390071d4279SBram Moolenaar */
3391071d4279SBram Moolenaar static int
eval7(char_u ** arg,typval_T * rettv,evalarg_T * evalarg,int want_string)33927454a06eSBram Moolenaar eval7(
33937454a06eSBram Moolenaar char_u **arg,
33947454a06eSBram Moolenaar typval_T *rettv,
33955409f5d8SBram Moolenaar evalarg_T *evalarg,
33968a7d6542SBram Moolenaar int want_string) // after "." operator
3397071d4279SBram Moolenaar {
33985409f5d8SBram Moolenaar int evaluate = evalarg != NULL
33995409f5d8SBram Moolenaar && (evalarg->eval_flags & EVAL_EVALUATE);
3400071d4279SBram Moolenaar int len;
3401071d4279SBram Moolenaar char_u *s;
3402071d4279SBram Moolenaar char_u *start_leader, *end_leader;
3403071d4279SBram Moolenaar int ret = OK;
3404071d4279SBram Moolenaar char_u *alias;
3405071d4279SBram Moolenaar
3406071d4279SBram Moolenaar /*
3407c70646c6SBram Moolenaar * Initialise variable so that clear_tv() can't mistake this for a
340849cd9579SBram Moolenaar * string and free a string that isn't there.
3409071d4279SBram Moolenaar */
3410c70646c6SBram Moolenaar rettv->v_type = VAR_UNKNOWN;
3411071d4279SBram Moolenaar
3412071d4279SBram Moolenaar /*
3413edf3f97aSBram Moolenaar * Skip '!', '-' and '+' characters. They are handled later.
3414071d4279SBram Moolenaar */
3415071d4279SBram Moolenaar start_leader = *arg;
3416b23279d7SBram Moolenaar if (eval_leader(arg, in_vim9script()) == FAIL)
3417b23279d7SBram Moolenaar return FAIL;
3418071d4279SBram Moolenaar end_leader = *arg;
3419071d4279SBram Moolenaar
3420558ca4aeSBram Moolenaar if (**arg == '.' && (!isdigit(*(*arg + 1))
3421558ca4aeSBram Moolenaar #ifdef FEAT_FLOAT
3422dd9de50fSBram Moolenaar || in_old_script(2)
3423558ca4aeSBram Moolenaar #endif
3424558ca4aeSBram Moolenaar ))
3425558ca4aeSBram Moolenaar {
3426108010aaSBram Moolenaar semsg(_(e_invalid_expression_str), *arg);
3427558ca4aeSBram Moolenaar ++*arg;
3428558ca4aeSBram Moolenaar return FAIL;
3429558ca4aeSBram Moolenaar }
3430558ca4aeSBram Moolenaar
3431071d4279SBram Moolenaar switch (**arg)
3432071d4279SBram Moolenaar {
3433071d4279SBram Moolenaar /*
3434071d4279SBram Moolenaar * Number constant.
3435071d4279SBram Moolenaar */
3436071d4279SBram Moolenaar case '0':
3437071d4279SBram Moolenaar case '1':
3438071d4279SBram Moolenaar case '2':
3439071d4279SBram Moolenaar case '3':
3440071d4279SBram Moolenaar case '4':
3441071d4279SBram Moolenaar case '5':
3442071d4279SBram Moolenaar case '6':
3443071d4279SBram Moolenaar case '7':
3444071d4279SBram Moolenaar case '8':
3445071d4279SBram Moolenaar case '9':
34469a78e6dfSBram Moolenaar case '.': ret = eval_number(arg, rettv, evaluate, want_string);
34470b1cd52fSBram Moolenaar
34480b1cd52fSBram Moolenaar // Apply prefixed "-" and "+" now. Matters especially when
34490b1cd52fSBram Moolenaar // "->" follows.
34503e06a1e2SBram Moolenaar if (ret == OK && evaluate && end_leader > start_leader
34513e06a1e2SBram Moolenaar && rettv->v_type != VAR_BLOB)
34520b1cd52fSBram Moolenaar ret = eval7_leader(rettv, TRUE, start_leader, &end_leader);
34536e5ea8d2SBram Moolenaar break;
3454071d4279SBram Moolenaar
3455071d4279SBram Moolenaar /*
3456071d4279SBram Moolenaar * String constant: "string".
3457071d4279SBram Moolenaar */
34589a78e6dfSBram Moolenaar case '"': ret = eval_string(arg, rettv, evaluate);
3459071d4279SBram Moolenaar break;
3460071d4279SBram Moolenaar
3461071d4279SBram Moolenaar /*
34628c711458SBram Moolenaar * Literal string constant: 'str''ing'.
3463071d4279SBram Moolenaar */
34649a78e6dfSBram Moolenaar case '\'': ret = eval_lit_string(arg, rettv, evaluate);
346549cd9579SBram Moolenaar break;
346649cd9579SBram Moolenaar
346749cd9579SBram Moolenaar /*
346849cd9579SBram Moolenaar * List: [expr, expr]
346949cd9579SBram Moolenaar */
34709a78e6dfSBram Moolenaar case '[': ret = eval_list(arg, rettv, evalarg, TRUE);
3471071d4279SBram Moolenaar break;
3472071d4279SBram Moolenaar
3473071d4279SBram Moolenaar /*
34744c6d9045SBram Moolenaar * Dictionary: #{key: val, key: val}
3475d5abb4c8SBram Moolenaar */
34765c7a299cSBram Moolenaar case '#': if (in_vim9script())
34775c7a299cSBram Moolenaar {
34785c7a299cSBram Moolenaar ret = vim9_bad_comment(*arg) ? FAIL : NOTDONE;
34795c7a299cSBram Moolenaar }
34805c7a299cSBram Moolenaar else if ((*arg)[1] == '{')
3481d5abb4c8SBram Moolenaar {
3482d5abb4c8SBram Moolenaar ++*arg;
34838ea9390bSBram Moolenaar ret = eval_dict(arg, rettv, evalarg, TRUE);
3484d5abb4c8SBram Moolenaar }
3485d5abb4c8SBram Moolenaar else
3486d5abb4c8SBram Moolenaar ret = NOTDONE;
3487d5abb4c8SBram Moolenaar break;
3488d5abb4c8SBram Moolenaar
3489d5abb4c8SBram Moolenaar /*
3490069c1e7fSBram Moolenaar * Lambda: {arg, arg -> expr}
3491d5abb4c8SBram Moolenaar * Dictionary: {'key': val, 'key': val}
34928c711458SBram Moolenaar */
34932949cfdbSBram Moolenaar case '{': if (in_vim9script())
34942949cfdbSBram Moolenaar ret = NOTDONE;
34952949cfdbSBram Moolenaar else
34962949cfdbSBram Moolenaar ret = get_lambda_tv(arg, rettv, in_vim9script(), evalarg);
3497069c1e7fSBram Moolenaar if (ret == NOTDONE)
34988ea9390bSBram Moolenaar ret = eval_dict(arg, rettv, evalarg, FALSE);
34998c711458SBram Moolenaar break;
35008c711458SBram Moolenaar
35018c711458SBram Moolenaar /*
3502e9a41264SBram Moolenaar * Option value: &name
3503071d4279SBram Moolenaar */
35049a78e6dfSBram Moolenaar case '&': ret = eval_option(arg, rettv, evaluate);
3505071d4279SBram Moolenaar break;
3506071d4279SBram Moolenaar
3507071d4279SBram Moolenaar /*
3508071d4279SBram Moolenaar * Environment variable: $VAR.
3509071d4279SBram Moolenaar */
35109a78e6dfSBram Moolenaar case '$': ret = eval_env_var(arg, rettv, evaluate);
3511071d4279SBram Moolenaar break;
3512071d4279SBram Moolenaar
3513071d4279SBram Moolenaar /*
3514071d4279SBram Moolenaar * Register contents: @r.
3515071d4279SBram Moolenaar */
3516071d4279SBram Moolenaar case '@': ++*arg;
3517071d4279SBram Moolenaar if (evaluate)
3518071d4279SBram Moolenaar {
351990193e61SBram Moolenaar if (in_vim9script() && IS_WHITE_OR_NUL(**arg))
352090193e61SBram Moolenaar semsg(_(e_syntax_error_at_str), *arg);
352190193e61SBram Moolenaar else if (in_vim9script() && !valid_yank_reg(**arg, FALSE))
352290193e61SBram Moolenaar emsg_invreg(**arg);
352390193e61SBram Moolenaar else
352490193e61SBram Moolenaar {
3525c70646c6SBram Moolenaar rettv->v_type = VAR_STRING;
3526b7cb42bcSBram Moolenaar rettv->vval.v_string = get_reg_contents(**arg,
3527b7cb42bcSBram Moolenaar GREG_EXPR_SRC);
3528071d4279SBram Moolenaar }
352990193e61SBram Moolenaar }
3530071d4279SBram Moolenaar if (**arg != NUL)
3531071d4279SBram Moolenaar ++*arg;
3532071d4279SBram Moolenaar break;
3533071d4279SBram Moolenaar
3534071d4279SBram Moolenaar /*
3535071d4279SBram Moolenaar * nested expression: (expression).
3536ecb66450SBram Moolenaar * or lambda: (arg) => expr
3537071d4279SBram Moolenaar */
3538c754b4ccSBram Moolenaar case '(': ret = NOTDONE;
3539c754b4ccSBram Moolenaar if (in_vim9script())
354006409501SBram Moolenaar {
3541c754b4ccSBram Moolenaar ret = get_lambda_tv(arg, rettv, TRUE, evalarg);
354206409501SBram Moolenaar if (ret == OK && evaluate)
354306409501SBram Moolenaar {
354406409501SBram Moolenaar ufunc_T *ufunc = rettv->vval.v_partial->pt_func;
354506409501SBram Moolenaar
3546a9931535SBram Moolenaar // Compile it here to get the return type. The return
3547a9931535SBram Moolenaar // type is optional, when it's missing use t_unknown.
3548a9931535SBram Moolenaar // This is recognized in compile_return().
3549a9931535SBram Moolenaar if (ufunc->uf_ret_type->tt_type == VAR_VOID)
3550a9931535SBram Moolenaar ufunc->uf_ret_type = &t_unknown;
3551c7dac853SBram Moolenaar if (compile_def_function(ufunc,
3552e99d422bSBram Moolenaar FALSE, COMPILE_TYPE(ufunc), NULL) == FAIL)
3553c7dac853SBram Moolenaar {
3554c7dac853SBram Moolenaar clear_tv(rettv);
3555c7dac853SBram Moolenaar ret = FAIL;
3556c7dac853SBram Moolenaar }
355706409501SBram Moolenaar }
355806409501SBram Moolenaar }
3559c754b4ccSBram Moolenaar if (ret == NOTDONE)
3560c754b4ccSBram Moolenaar {
35619215f012SBram Moolenaar *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
35625409f5d8SBram Moolenaar ret = eval1(arg, rettv, evalarg); // recursive!
35637a4981b9SBram Moolenaar
35649215f012SBram Moolenaar *arg = skipwhite_and_linebreak(*arg, evalarg);
3565071d4279SBram Moolenaar if (**arg == ')')
3566071d4279SBram Moolenaar ++*arg;
3567071d4279SBram Moolenaar else if (ret == OK)
3568071d4279SBram Moolenaar {
35698a7d6542SBram Moolenaar emsg(_(e_missing_close));
3570c70646c6SBram Moolenaar clear_tv(rettv);
3571071d4279SBram Moolenaar ret = FAIL;
3572071d4279SBram Moolenaar }
35735409f5d8SBram Moolenaar }
3574071d4279SBram Moolenaar break;
3575071d4279SBram Moolenaar
35768c711458SBram Moolenaar default: ret = NOTDONE;
35778c711458SBram Moolenaar break;
35788c711458SBram Moolenaar }
35798c711458SBram Moolenaar
35808c711458SBram Moolenaar if (ret == NOTDONE)
35818c711458SBram Moolenaar {
3582071d4279SBram Moolenaar /*
35838c711458SBram Moolenaar * Must be a variable or function name.
35848c711458SBram Moolenaar * Can also be a curly-braces kind of name: {expr}.
3585071d4279SBram Moolenaar */
35868c711458SBram Moolenaar s = *arg;
35872a8d1f87SBram Moolenaar len = get_name_len(arg, &alias, evaluate, TRUE);
3588071d4279SBram Moolenaar if (alias != NULL)
3589071d4279SBram Moolenaar s = alias;
3590071d4279SBram Moolenaar
35912a8d1f87SBram Moolenaar if (len <= 0)
3592071d4279SBram Moolenaar ret = FAIL;
3593071d4279SBram Moolenaar else
3594071d4279SBram Moolenaar {
35953ac9c470SBram Moolenaar int flags = evalarg == NULL ? 0 : evalarg->eval_flags;
35963ac9c470SBram Moolenaar
3597f93bbd02SBram Moolenaar if (evaluate && in_vim9script() && len == 1 && *s == '_')
3598962c43bfSBram Moolenaar {
3599962c43bfSBram Moolenaar emsg(_(e_cannot_use_underscore_here));
3600962c43bfSBram Moolenaar ret = FAIL;
3601962c43bfSBram Moolenaar }
3602962c43bfSBram Moolenaar else if ((in_vim9script() ? **arg : *skipwhite(*arg)) == '(')
3603bbd3e3c3SBram Moolenaar {
36049a78e6dfSBram Moolenaar // "name(..." recursive!
3605bbd3e3c3SBram Moolenaar *arg = skipwhite(*arg);
3606e6b5324eSBram Moolenaar ret = eval_func(arg, evalarg, s, len, rettv, flags, NULL);
3607bbd3e3c3SBram Moolenaar }
3608227a69deSBram Moolenaar else if (flags & EVAL_CONSTANT)
3609227a69deSBram Moolenaar ret = FAIL;
3610071d4279SBram Moolenaar else if (evaluate)
36115d2eb0ffSBram Moolenaar {
36125d2eb0ffSBram Moolenaar // get the value of "true", "false" or a variable
36135d2eb0ffSBram Moolenaar if (len == 4 && in_vim9script() && STRNCMP(s, "true", 4) == 0)
36145d2eb0ffSBram Moolenaar {
36155d2eb0ffSBram Moolenaar rettv->v_type = VAR_BOOL;
36165d2eb0ffSBram Moolenaar rettv->vval.v_number = VVAL_TRUE;
36176e4cfffeSBram Moolenaar ret = OK;
36185d2eb0ffSBram Moolenaar }
36195d2eb0ffSBram Moolenaar else if (len == 5 && in_vim9script()
36205f639384SBram Moolenaar && STRNCMP(s, "false", 5) == 0)
36215d2eb0ffSBram Moolenaar {
36225d2eb0ffSBram Moolenaar rettv->v_type = VAR_BOOL;
36235d2eb0ffSBram Moolenaar rettv->vval.v_number = VVAL_FALSE;
36246e4cfffeSBram Moolenaar ret = OK;
36255d2eb0ffSBram Moolenaar }
36265f639384SBram Moolenaar else if (len == 4 && in_vim9script()
36275f639384SBram Moolenaar && STRNCMP(s, "null", 4) == 0)
36285f639384SBram Moolenaar {
36295f639384SBram Moolenaar rettv->v_type = VAR_SPECIAL;
36305f639384SBram Moolenaar rettv->vval.v_number = VVAL_NULL;
36315f639384SBram Moolenaar ret = OK;
36325f639384SBram Moolenaar }
36335d2eb0ffSBram Moolenaar else
3634cb4e80faSBram Moolenaar ret = eval_variable(s, len, rettv, NULL,
3635cb4e80faSBram Moolenaar EVAL_VAR_VERBOSE + EVAL_VAR_IMPORT);
36365d2eb0ffSBram Moolenaar }
36379ef486dbSBram Moolenaar else
36381e96d9bfSBram Moolenaar {
36399a78e6dfSBram Moolenaar // skip the name
36401e96d9bfSBram Moolenaar check_vars(s, len);
36419ef486dbSBram Moolenaar ret = OK;
3642071d4279SBram Moolenaar }
36431e96d9bfSBram Moolenaar }
3644071d4279SBram Moolenaar vim_free(alias);
3645071d4279SBram Moolenaar }
36468c711458SBram Moolenaar
36475d18efecSBram Moolenaar // Handle following '[', '(' and '.' for expr[expr], expr.name,
36485d18efecSBram Moolenaar // expr(expr), expr->name(expr)
3649e9a41264SBram Moolenaar if (ret == OK)
3650e40fbc2cSBram Moolenaar ret = handle_subscript(arg, rettv, evalarg, TRUE);
3651071d4279SBram Moolenaar
3652071d4279SBram Moolenaar /*
3653071d4279SBram Moolenaar * Apply logical NOT and unary '-', from right to left, ignore '+'.
3654071d4279SBram Moolenaar */
3655071d4279SBram Moolenaar if (ret == OK && evaluate && end_leader > start_leader)
36560b1cd52fSBram Moolenaar ret = eval7_leader(rettv, FALSE, start_leader, &end_leader);
36579cfe8f6eSBram Moolenaar return ret;
36589cfe8f6eSBram Moolenaar }
36599cfe8f6eSBram Moolenaar
36609cfe8f6eSBram Moolenaar /*
36619cfe8f6eSBram Moolenaar * Apply the leading "!" and "-" before an eval7 expression to "rettv".
36620b1cd52fSBram Moolenaar * When "numeric_only" is TRUE only handle "+" and "-".
36639cfe8f6eSBram Moolenaar * Adjusts "end_leaderp" until it is at "start_leader".
36649cfe8f6eSBram Moolenaar */
36659cfe8f6eSBram Moolenaar static int
eval7_leader(typval_T * rettv,int numeric_only,char_u * start_leader,char_u ** end_leaderp)36660b1cd52fSBram Moolenaar eval7_leader(
36670b1cd52fSBram Moolenaar typval_T *rettv,
36680b1cd52fSBram Moolenaar int numeric_only,
36690b1cd52fSBram Moolenaar char_u *start_leader,
36700b1cd52fSBram Moolenaar char_u **end_leaderp)
3671071d4279SBram Moolenaar {
36729cfe8f6eSBram Moolenaar char_u *end_leader = *end_leaderp;
36739cfe8f6eSBram Moolenaar int ret = OK;
36749ba0eb85SBram Moolenaar int error = FALSE;
367522fcfad2SBram Moolenaar varnumber_T val = 0;
36766e4cfffeSBram Moolenaar vartype_T type = rettv->v_type;
36778c8de839SBram Moolenaar #ifdef FEAT_FLOAT
36788c8de839SBram Moolenaar float_T f = 0.0;
36799ba0eb85SBram Moolenaar
36808c8de839SBram Moolenaar if (rettv->v_type == VAR_FLOAT)
36818c8de839SBram Moolenaar f = rettv->vval.v_float;
36828c8de839SBram Moolenaar else
36838c8de839SBram Moolenaar #endif
368427491cd3SBram Moolenaar {
368527491cd3SBram Moolenaar while (VIM_ISWHITE(end_leader[-1]))
368627491cd3SBram Moolenaar --end_leader;
36873e06a1e2SBram Moolenaar if (in_vim9script() && end_leader[-1] == '!')
36883e06a1e2SBram Moolenaar val = tv2bool(rettv);
36893e06a1e2SBram Moolenaar else
3690d155d7a8SBram Moolenaar val = tv_get_number_chk(rettv, &error);
369127491cd3SBram Moolenaar }
36929ba0eb85SBram Moolenaar if (error)
36939ba0eb85SBram Moolenaar {
36949ba0eb85SBram Moolenaar clear_tv(rettv);
36959ba0eb85SBram Moolenaar ret = FAIL;
36969ba0eb85SBram Moolenaar }
36979ba0eb85SBram Moolenaar else
36989ba0eb85SBram Moolenaar {
3699071d4279SBram Moolenaar while (end_leader > start_leader)
3700071d4279SBram Moolenaar {
3701071d4279SBram Moolenaar --end_leader;
3702071d4279SBram Moolenaar if (*end_leader == '!')
37038c8de839SBram Moolenaar {
37040b1cd52fSBram Moolenaar if (numeric_only)
37050b1cd52fSBram Moolenaar {
37060b1cd52fSBram Moolenaar ++end_leader;
37070b1cd52fSBram Moolenaar break;
37080b1cd52fSBram Moolenaar }
37098c8de839SBram Moolenaar #ifdef FEAT_FLOAT
37108c8de839SBram Moolenaar if (rettv->v_type == VAR_FLOAT)
3711659bb227SBram Moolenaar {
3712659bb227SBram Moolenaar if (in_vim9script())
3713659bb227SBram Moolenaar {
3714659bb227SBram Moolenaar rettv->v_type = VAR_BOOL;
3715659bb227SBram Moolenaar val = f == 0.0 ? VVAL_TRUE : VVAL_FALSE;
3716659bb227SBram Moolenaar }
3717659bb227SBram Moolenaar else
37188c8de839SBram Moolenaar f = !f;
3719659bb227SBram Moolenaar }
37208c8de839SBram Moolenaar else
37218c8de839SBram Moolenaar #endif
37226e4cfffeSBram Moolenaar {
3723071d4279SBram Moolenaar val = !val;
37246e4cfffeSBram Moolenaar type = VAR_BOOL;
37256e4cfffeSBram Moolenaar }
37268c8de839SBram Moolenaar }
3727071d4279SBram Moolenaar else if (*end_leader == '-')
37288c8de839SBram Moolenaar {
37298c8de839SBram Moolenaar #ifdef FEAT_FLOAT
37308c8de839SBram Moolenaar if (rettv->v_type == VAR_FLOAT)
37318c8de839SBram Moolenaar f = -f;
37328c8de839SBram Moolenaar else
37338c8de839SBram Moolenaar #endif
37346e4cfffeSBram Moolenaar {
3735071d4279SBram Moolenaar val = -val;
37366e4cfffeSBram Moolenaar type = VAR_NUMBER;
37376e4cfffeSBram Moolenaar }
3738071d4279SBram Moolenaar }
37398c8de839SBram Moolenaar }
37408c8de839SBram Moolenaar #ifdef FEAT_FLOAT
37418c8de839SBram Moolenaar if (rettv->v_type == VAR_FLOAT)
37428c8de839SBram Moolenaar {
37438c8de839SBram Moolenaar clear_tv(rettv);
37448c8de839SBram Moolenaar rettv->vval.v_float = f;
37458c8de839SBram Moolenaar }
37468c8de839SBram Moolenaar else
37478c8de839SBram Moolenaar #endif
37488c8de839SBram Moolenaar {
3749c70646c6SBram Moolenaar clear_tv(rettv);
37506e4cfffeSBram Moolenaar if (in_vim9script())
37516e4cfffeSBram Moolenaar rettv->v_type = type;
37526e4cfffeSBram Moolenaar else
3753c70646c6SBram Moolenaar rettv->v_type = VAR_NUMBER;
3754c70646c6SBram Moolenaar rettv->vval.v_number = val;
3755071d4279SBram Moolenaar }
37569ba0eb85SBram Moolenaar }
37579cfe8f6eSBram Moolenaar *end_leaderp = end_leader;
3758071d4279SBram Moolenaar return ret;
3759071d4279SBram Moolenaar }
3760071d4279SBram Moolenaar
3761071d4279SBram Moolenaar /*
376222a0c0c4SBram Moolenaar * Call the function referred to in "rettv".
376322a0c0c4SBram Moolenaar */
376422a0c0c4SBram Moolenaar static int
call_func_rettv(char_u ** arg,evalarg_T * evalarg,typval_T * rettv,int evaluate,dict_T * selfdict,typval_T * basetv)376522a0c0c4SBram Moolenaar call_func_rettv(
376622a0c0c4SBram Moolenaar char_u **arg,
3767e6b5324eSBram Moolenaar evalarg_T *evalarg,
376822a0c0c4SBram Moolenaar typval_T *rettv,
376922a0c0c4SBram Moolenaar int evaluate,
377022a0c0c4SBram Moolenaar dict_T *selfdict,
377122a0c0c4SBram Moolenaar typval_T *basetv)
377222a0c0c4SBram Moolenaar {
377322a0c0c4SBram Moolenaar partial_T *pt = NULL;
377422a0c0c4SBram Moolenaar funcexe_T funcexe;
377522a0c0c4SBram Moolenaar typval_T functv;
377622a0c0c4SBram Moolenaar char_u *s;
377722a0c0c4SBram Moolenaar int ret;
377822a0c0c4SBram Moolenaar
377922a0c0c4SBram Moolenaar // need to copy the funcref so that we can clear rettv
378022a0c0c4SBram Moolenaar if (evaluate)
378122a0c0c4SBram Moolenaar {
378222a0c0c4SBram Moolenaar functv = *rettv;
378322a0c0c4SBram Moolenaar rettv->v_type = VAR_UNKNOWN;
378422a0c0c4SBram Moolenaar
37855d18efecSBram Moolenaar // Invoke the function. Recursive!
378622a0c0c4SBram Moolenaar if (functv.v_type == VAR_PARTIAL)
378722a0c0c4SBram Moolenaar {
378822a0c0c4SBram Moolenaar pt = functv.vval.v_partial;
378922a0c0c4SBram Moolenaar s = partial_name(pt);
379022a0c0c4SBram Moolenaar }
379122a0c0c4SBram Moolenaar else
379222db0d54SBram Moolenaar {
379322a0c0c4SBram Moolenaar s = functv.vval.v_string;
379422db0d54SBram Moolenaar if (s == NULL || *s == NUL)
379522db0d54SBram Moolenaar {
379622db0d54SBram Moolenaar emsg(_(e_empty_function_name));
3797744aecf8SBram Moolenaar ret = FAIL;
379822db0d54SBram Moolenaar goto theend;
379922db0d54SBram Moolenaar }
380022db0d54SBram Moolenaar }
380122a0c0c4SBram Moolenaar }
380222a0c0c4SBram Moolenaar else
380322a0c0c4SBram Moolenaar s = (char_u *)"";
380422a0c0c4SBram Moolenaar
3805a80faa89SBram Moolenaar CLEAR_FIELD(funcexe);
380622a0c0c4SBram Moolenaar funcexe.firstline = curwin->w_cursor.lnum;
380722a0c0c4SBram Moolenaar funcexe.lastline = curwin->w_cursor.lnum;
380822a0c0c4SBram Moolenaar funcexe.evaluate = evaluate;
380922a0c0c4SBram Moolenaar funcexe.partial = pt;
381022a0c0c4SBram Moolenaar funcexe.selfdict = selfdict;
381122a0c0c4SBram Moolenaar funcexe.basetv = basetv;
3812e6b5324eSBram Moolenaar ret = get_func_tv(s, -1, rettv, arg, evalarg, &funcexe);
381322a0c0c4SBram Moolenaar
381422db0d54SBram Moolenaar theend:
38155d18efecSBram Moolenaar // Clear the funcref afterwards, so that deleting it while
38165d18efecSBram Moolenaar // evaluating the arguments is possible (see test55).
381722a0c0c4SBram Moolenaar if (evaluate)
381822a0c0c4SBram Moolenaar clear_tv(&functv);
381922a0c0c4SBram Moolenaar
382022a0c0c4SBram Moolenaar return ret;
382122a0c0c4SBram Moolenaar }
382222a0c0c4SBram Moolenaar
382322a0c0c4SBram Moolenaar /*
382422a0c0c4SBram Moolenaar * Evaluate "->method()".
38257cebe8baSBram Moolenaar * "*arg" points to "method".
382622a0c0c4SBram Moolenaar * Returns FAIL or OK. "*arg" is advanced to after the ')'.
382722a0c0c4SBram Moolenaar */
382822a0c0c4SBram Moolenaar static int
eval_lambda(char_u ** arg,typval_T * rettv,evalarg_T * evalarg,int verbose)382922a0c0c4SBram Moolenaar eval_lambda(
383022a0c0c4SBram Moolenaar char_u **arg,
383122a0c0c4SBram Moolenaar typval_T *rettv,
3832e40fbc2cSBram Moolenaar evalarg_T *evalarg,
38335d18efecSBram Moolenaar int verbose) // give error messages
383422a0c0c4SBram Moolenaar {
3835e40fbc2cSBram Moolenaar int evaluate = evalarg != NULL
3836e40fbc2cSBram Moolenaar && (evalarg->eval_flags & EVAL_EVALUATE);
383722a0c0c4SBram Moolenaar typval_T base = *rettv;
383822a0c0c4SBram Moolenaar int ret;
383922a0c0c4SBram Moolenaar
384022a0c0c4SBram Moolenaar rettv->v_type = VAR_UNKNOWN;
384122a0c0c4SBram Moolenaar
38422949cfdbSBram Moolenaar if (**arg == '{')
38432949cfdbSBram Moolenaar {
38442949cfdbSBram Moolenaar // ->{lambda}()
3845b4d16cb1SBram Moolenaar ret = get_lambda_tv(arg, rettv, FALSE, evalarg);
38462949cfdbSBram Moolenaar }
38472949cfdbSBram Moolenaar else
38482949cfdbSBram Moolenaar {
38492949cfdbSBram Moolenaar // ->(lambda)()
38502949cfdbSBram Moolenaar ++*arg;
38512949cfdbSBram Moolenaar ret = eval1(arg, rettv, evalarg);
38522949cfdbSBram Moolenaar *arg = skipwhite_and_linebreak(*arg, evalarg);
38532949cfdbSBram Moolenaar if (**arg != ')')
38542949cfdbSBram Moolenaar {
38552949cfdbSBram Moolenaar emsg(_(e_missing_close));
38562949cfdbSBram Moolenaar ret = FAIL;
38572949cfdbSBram Moolenaar }
38582949cfdbSBram Moolenaar ++*arg;
38592949cfdbSBram Moolenaar }
38600ff822d2SBram Moolenaar if (ret != OK)
386122a0c0c4SBram Moolenaar return FAIL;
386222a0c0c4SBram Moolenaar else if (**arg != '(')
386322a0c0c4SBram Moolenaar {
386422a0c0c4SBram Moolenaar if (verbose)
386522a0c0c4SBram Moolenaar {
386622a0c0c4SBram Moolenaar if (*skipwhite(*arg) == '(')
3867db99f9f2SBram Moolenaar emsg(_(e_nowhitespace));
386822a0c0c4SBram Moolenaar else
38698a7d6542SBram Moolenaar semsg(_(e_missing_paren), "lambda");
387022a0c0c4SBram Moolenaar }
387122a0c0c4SBram Moolenaar clear_tv(rettv);
38728617348eSBram Moolenaar ret = FAIL;
387322a0c0c4SBram Moolenaar }
38748617348eSBram Moolenaar else
3875e6b5324eSBram Moolenaar ret = call_func_rettv(arg, evalarg, rettv, evaluate, NULL, &base);
38768617348eSBram Moolenaar
38778617348eSBram Moolenaar // Clear the funcref afterwards, so that deleting it while
38788617348eSBram Moolenaar // evaluating the arguments is possible (see test55).
38798617348eSBram Moolenaar if (evaluate)
38808617348eSBram Moolenaar clear_tv(&base);
38818617348eSBram Moolenaar
38828617348eSBram Moolenaar return ret;
388322a0c0c4SBram Moolenaar }
388422a0c0c4SBram Moolenaar
388522a0c0c4SBram Moolenaar /*
3886ac92e25aSBram Moolenaar * Evaluate "->method()".
38877cebe8baSBram Moolenaar * "*arg" points to "method".
3888ac92e25aSBram Moolenaar * Returns FAIL or OK. "*arg" is advanced to after the ')'.
3889ac92e25aSBram Moolenaar */
3890ac92e25aSBram Moolenaar static int
eval_method(char_u ** arg,typval_T * rettv,evalarg_T * evalarg,int verbose)3891ac92e25aSBram Moolenaar eval_method(
3892ac92e25aSBram Moolenaar char_u **arg,
3893ac92e25aSBram Moolenaar typval_T *rettv,
3894e6b5324eSBram Moolenaar evalarg_T *evalarg,
38955d18efecSBram Moolenaar int verbose) // give error messages
3896ac92e25aSBram Moolenaar {
3897ac92e25aSBram Moolenaar char_u *name;
3898ac92e25aSBram Moolenaar long len;
3899761fdf01SBram Moolenaar char_u *alias;
3900ac92e25aSBram Moolenaar typval_T base = *rettv;
3901761fdf01SBram Moolenaar int ret;
3902e6b5324eSBram Moolenaar int evaluate = evalarg != NULL
3903e6b5324eSBram Moolenaar && (evalarg->eval_flags & EVAL_EVALUATE);
3904ac92e25aSBram Moolenaar
3905761fdf01SBram Moolenaar rettv->v_type = VAR_UNKNOWN;
3906ac92e25aSBram Moolenaar
3907ac92e25aSBram Moolenaar name = *arg;
3908761fdf01SBram Moolenaar len = get_name_len(arg, &alias, evaluate, TRUE);
3909761fdf01SBram Moolenaar if (alias != NULL)
3910761fdf01SBram Moolenaar name = alias;
3911761fdf01SBram Moolenaar
3912761fdf01SBram Moolenaar if (len <= 0)
3913ac92e25aSBram Moolenaar {
3914ac92e25aSBram Moolenaar if (verbose)
3915ac92e25aSBram Moolenaar emsg(_("E260: Missing name after ->"));
3916761fdf01SBram Moolenaar ret = FAIL;
3917ac92e25aSBram Moolenaar }
3918761fdf01SBram Moolenaar else
3919761fdf01SBram Moolenaar {
3920bb1b5e24SBram Moolenaar *arg = skipwhite(*arg);
3921761fdf01SBram Moolenaar if (**arg != '(')
3922ac92e25aSBram Moolenaar {
3923ac92e25aSBram Moolenaar if (verbose)
39248a7d6542SBram Moolenaar semsg(_(e_missing_paren), name);
3925761fdf01SBram Moolenaar ret = FAIL;
3926ac92e25aSBram Moolenaar }
39275184132eSBram Moolenaar else if (VIM_ISWHITE((*arg)[-1]))
39285184132eSBram Moolenaar {
39295184132eSBram Moolenaar if (verbose)
3930db99f9f2SBram Moolenaar emsg(_(e_nowhitespace));
39315184132eSBram Moolenaar ret = FAIL;
39325184132eSBram Moolenaar }
3933761fdf01SBram Moolenaar else
3934e6b5324eSBram Moolenaar ret = eval_func(arg, evalarg, name, len, rettv,
393532e35117SBram Moolenaar evaluate ? EVAL_EVALUATE : 0, &base);
3936761fdf01SBram Moolenaar }
3937ac92e25aSBram Moolenaar
393822a0c0c4SBram Moolenaar // Clear the funcref afterwards, so that deleting it while
393922a0c0c4SBram Moolenaar // evaluating the arguments is possible (see test55).
3940ac92e25aSBram Moolenaar if (evaluate)
3941ac92e25aSBram Moolenaar clear_tv(&base);
3942ac92e25aSBram Moolenaar
3943ac92e25aSBram Moolenaar return ret;
3944ac92e25aSBram Moolenaar }
3945ac92e25aSBram Moolenaar
3946ac92e25aSBram Moolenaar /*
39479e54a0e7SBram Moolenaar * Evaluate an "[expr]" or "[expr:expr]" index. Also "dict.key".
39489e54a0e7SBram Moolenaar * "*arg" points to the '[' or '.'.
394949cd9579SBram Moolenaar * Returns FAIL or OK. "*arg" is advanced to after the ']'.
395049cd9579SBram Moolenaar */
395149cd9579SBram Moolenaar static int
eval_index(char_u ** arg,typval_T * rettv,evalarg_T * evalarg,int verbose)39527454a06eSBram Moolenaar eval_index(
39537454a06eSBram Moolenaar char_u **arg,
39547454a06eSBram Moolenaar typval_T *rettv,
3955e40fbc2cSBram Moolenaar evalarg_T *evalarg,
39565d18efecSBram Moolenaar int verbose) // give error messages
395749cd9579SBram Moolenaar {
3958e40fbc2cSBram Moolenaar int evaluate = evalarg != NULL
3959e40fbc2cSBram Moolenaar && (evalarg->eval_flags & EVAL_EVALUATE);
396049cd9579SBram Moolenaar int empty1 = FALSE, empty2 = FALSE;
396133570924SBram Moolenaar typval_T var1, var2;
39628c711458SBram Moolenaar int range = FALSE;
39638c711458SBram Moolenaar char_u *key = NULL;
3964cc673e74SBram Moolenaar int keylen = -1;
3965de4f95b0SBram Moolenaar int vim9 = in_vim9script();
396649cd9579SBram Moolenaar
3967cc673e74SBram Moolenaar if (check_can_index(rettv, evaluate, verbose) == FAIL)
396849cd9579SBram Moolenaar return FAIL;
396949cd9579SBram Moolenaar
39700a38dd29SBram Moolenaar init_tv(&var1);
39710a38dd29SBram Moolenaar init_tv(&var2);
39728c711458SBram Moolenaar if (**arg == '.')
39738c711458SBram Moolenaar {
397449cd9579SBram Moolenaar /*
39758c711458SBram Moolenaar * dict.name
39768c711458SBram Moolenaar */
39778c711458SBram Moolenaar key = *arg + 1;
3978cc673e74SBram Moolenaar for (keylen = 0; eval_isdictc(key[keylen]); ++keylen)
39798c711458SBram Moolenaar ;
3980cc673e74SBram Moolenaar if (keylen == 0)
39818c711458SBram Moolenaar return FAIL;
3982c6e57b74SBram Moolenaar *arg = key + keylen;
39838c711458SBram Moolenaar }
39848c711458SBram Moolenaar else
39858c711458SBram Moolenaar {
39868c711458SBram Moolenaar /*
39878c711458SBram Moolenaar * something[idx]
39888c711458SBram Moolenaar *
398949cd9579SBram Moolenaar * Get the (first) variable from inside the [].
399049cd9579SBram Moolenaar */
3991442af2f8SBram Moolenaar *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
399249cd9579SBram Moolenaar if (**arg == ':')
399349cd9579SBram Moolenaar empty1 = TRUE;
3994e40fbc2cSBram Moolenaar else if (eval1(arg, &var1, evalarg) == FAIL) // recursive!
399549cd9579SBram Moolenaar return FAIL;
3996de4f95b0SBram Moolenaar else if (vim9 && **arg == ':')
3997de4f95b0SBram Moolenaar {
3998e7a73e07SBram Moolenaar semsg(_(e_white_space_required_before_and_after_str_at_str),
3999e7a73e07SBram Moolenaar ":", *arg);
4000de4f95b0SBram Moolenaar clear_tv(&var1);
4001de4f95b0SBram Moolenaar return FAIL;
4002de4f95b0SBram Moolenaar }
40032e5910bfSBram Moolenaar else if (evaluate)
40042e5910bfSBram Moolenaar {
40052e5910bfSBram Moolenaar #ifdef FEAT_FLOAT
40062e5910bfSBram Moolenaar // allow for indexing with float
40072e5910bfSBram Moolenaar if (vim9 && rettv->v_type == VAR_DICT
40082e5910bfSBram Moolenaar && var1.v_type == VAR_FLOAT)
40092e5910bfSBram Moolenaar {
40102e5910bfSBram Moolenaar var1.vval.v_string = typval_tostring(&var1, TRUE);
40112e5910bfSBram Moolenaar var1.v_type = VAR_STRING;
40122e5910bfSBram Moolenaar }
40132e5910bfSBram Moolenaar #endif
40142e5910bfSBram Moolenaar if (tv_get_string_chk(&var1) == NULL)
40159ba0eb85SBram Moolenaar {
40165d18efecSBram Moolenaar // not a number or string
40179ba0eb85SBram Moolenaar clear_tv(&var1);
40189ba0eb85SBram Moolenaar return FAIL;
40199ba0eb85SBram Moolenaar }
40202e5910bfSBram Moolenaar }
402149cd9579SBram Moolenaar
402249cd9579SBram Moolenaar /*
402349cd9579SBram Moolenaar * Get the second variable from inside the [:].
402449cd9579SBram Moolenaar */
4025442af2f8SBram Moolenaar *arg = skipwhite_and_linebreak(*arg, evalarg);
402649cd9579SBram Moolenaar if (**arg == ':')
402749cd9579SBram Moolenaar {
402849cd9579SBram Moolenaar range = TRUE;
4029de4f95b0SBram Moolenaar ++*arg;
4030a04d447dSBram Moolenaar if (vim9 && !IS_WHITE_OR_NUL(**arg) && **arg != ']')
4031de4f95b0SBram Moolenaar {
4032e7a73e07SBram Moolenaar semsg(_(e_white_space_required_before_and_after_str_at_str),
4033e7a73e07SBram Moolenaar ":", *arg - 1);
4034de4f95b0SBram Moolenaar if (!empty1)
4035de4f95b0SBram Moolenaar clear_tv(&var1);
4036de4f95b0SBram Moolenaar return FAIL;
4037de4f95b0SBram Moolenaar }
4038de4f95b0SBram Moolenaar *arg = skipwhite_and_linebreak(*arg, evalarg);
403949cd9579SBram Moolenaar if (**arg == ']')
404049cd9579SBram Moolenaar empty2 = TRUE;
4041e40fbc2cSBram Moolenaar else if (eval1(arg, &var2, evalarg) == FAIL) // recursive!
404249cd9579SBram Moolenaar {
40439ba0eb85SBram Moolenaar if (!empty1)
4044c70646c6SBram Moolenaar clear_tv(&var1);
404549cd9579SBram Moolenaar return FAIL;
404649cd9579SBram Moolenaar }
4047d155d7a8SBram Moolenaar else if (evaluate && tv_get_string_chk(&var2) == NULL)
40489ba0eb85SBram Moolenaar {
40495d18efecSBram Moolenaar // not a number or string
40509ba0eb85SBram Moolenaar if (!empty1)
40519ba0eb85SBram Moolenaar clear_tv(&var1);
40529ba0eb85SBram Moolenaar clear_tv(&var2);
40539ba0eb85SBram Moolenaar return FAIL;
40549ba0eb85SBram Moolenaar }
405549cd9579SBram Moolenaar }
405649cd9579SBram Moolenaar
40575d18efecSBram Moolenaar // Check for the ']'.
4058442af2f8SBram Moolenaar *arg = skipwhite_and_linebreak(*arg, evalarg);
405949cd9579SBram Moolenaar if (**arg != ']')
406049cd9579SBram Moolenaar {
40612a8d1f87SBram Moolenaar if (verbose)
4062f9e3e09fSBram Moolenaar emsg(_(e_missbrac));
4063c70646c6SBram Moolenaar clear_tv(&var1);
406449cd9579SBram Moolenaar if (range)
4065c70646c6SBram Moolenaar clear_tv(&var2);
406649cd9579SBram Moolenaar return FAIL;
406749cd9579SBram Moolenaar }
4068f923571eSBram Moolenaar *arg = *arg + 1; // skip over the ']'
40698c711458SBram Moolenaar }
407049cd9579SBram Moolenaar
407149cd9579SBram Moolenaar if (evaluate)
407249cd9579SBram Moolenaar {
4073cc673e74SBram Moolenaar int res = eval_index_inner(rettv, range,
40746601b629SBram Moolenaar empty1 ? NULL : &var1, empty2 ? NULL : &var2, FALSE,
4075cc673e74SBram Moolenaar key, keylen, verbose);
40766601b629SBram Moolenaar
4077cc673e74SBram Moolenaar if (!empty1)
4078c70646c6SBram Moolenaar clear_tv(&var1);
407949cd9579SBram Moolenaar if (range)
4080cc673e74SBram Moolenaar clear_tv(&var2);
4081cc673e74SBram Moolenaar return res;
4082cc673e74SBram Moolenaar }
4083cc673e74SBram Moolenaar return OK;
4084cc673e74SBram Moolenaar }
4085cc673e74SBram Moolenaar
4086cc673e74SBram Moolenaar /*
4087cc673e74SBram Moolenaar * Check if "rettv" can have an [index] or [sli:ce]
4088cc673e74SBram Moolenaar */
4089cc673e74SBram Moolenaar int
check_can_index(typval_T * rettv,int evaluate,int verbose)4090cc673e74SBram Moolenaar check_can_index(typval_T *rettv, int evaluate, int verbose)
409149cd9579SBram Moolenaar {
4092cc673e74SBram Moolenaar switch (rettv->v_type)
4093cc673e74SBram Moolenaar {
4094cc673e74SBram Moolenaar case VAR_FUNC:
4095cc673e74SBram Moolenaar case VAR_PARTIAL:
4096cc673e74SBram Moolenaar if (verbose)
4097cc673e74SBram Moolenaar emsg(_("E695: Cannot index a Funcref"));
4098cc673e74SBram Moolenaar return FAIL;
4099cc673e74SBram Moolenaar case VAR_FLOAT:
4100cc673e74SBram Moolenaar #ifdef FEAT_FLOAT
4101cc673e74SBram Moolenaar if (verbose)
4102cc673e74SBram Moolenaar emsg(_(e_float_as_string));
4103cc673e74SBram Moolenaar return FAIL;
4104cc673e74SBram Moolenaar #endif
4105cc673e74SBram Moolenaar case VAR_BOOL:
4106cc673e74SBram Moolenaar case VAR_SPECIAL:
4107cc673e74SBram Moolenaar case VAR_JOB:
4108cc673e74SBram Moolenaar case VAR_CHANNEL:
4109f18332fbSBram Moolenaar case VAR_INSTR:
4110cc673e74SBram Moolenaar if (verbose)
4111cc673e74SBram Moolenaar emsg(_(e_cannot_index_special_variable));
4112cc673e74SBram Moolenaar return FAIL;
4113cc673e74SBram Moolenaar case VAR_UNKNOWN:
4114cc673e74SBram Moolenaar case VAR_ANY:
4115cc673e74SBram Moolenaar case VAR_VOID:
4116cc673e74SBram Moolenaar if (evaluate)
4117cc673e74SBram Moolenaar {
4118cc673e74SBram Moolenaar emsg(_(e_cannot_index_special_variable));
4119cc673e74SBram Moolenaar return FAIL;
4120cc673e74SBram Moolenaar }
4121cc673e74SBram Moolenaar // FALLTHROUGH
4122cc673e74SBram Moolenaar
4123cc673e74SBram Moolenaar case VAR_STRING:
4124cc673e74SBram Moolenaar case VAR_LIST:
4125cc673e74SBram Moolenaar case VAR_DICT:
4126cc673e74SBram Moolenaar case VAR_BLOB:
4127cc673e74SBram Moolenaar break;
4128cc673e74SBram Moolenaar case VAR_NUMBER:
4129cc673e74SBram Moolenaar if (in_vim9script())
4130cc673e74SBram Moolenaar emsg(_(e_cannot_index_number));
4131cc673e74SBram Moolenaar break;
4132cc673e74SBram Moolenaar }
4133cc673e74SBram Moolenaar return OK;
4134cc673e74SBram Moolenaar }
4135cc673e74SBram Moolenaar
4136cc673e74SBram Moolenaar /*
41376601b629SBram Moolenaar * slice() function
41386601b629SBram Moolenaar */
41396601b629SBram Moolenaar void
f_slice(typval_T * argvars,typval_T * rettv)41406601b629SBram Moolenaar f_slice(typval_T *argvars, typval_T *rettv)
41416601b629SBram Moolenaar {
414283494b4aSYegappan Lakshmanan if (in_vim9script()
41434490ec4eSYegappan Lakshmanan && ((argvars[0].v_type != VAR_STRING
41444490ec4eSYegappan Lakshmanan && argvars[0].v_type != VAR_LIST
414583494b4aSYegappan Lakshmanan && argvars[0].v_type != VAR_BLOB
414683494b4aSYegappan Lakshmanan && check_for_list_arg(argvars, 0) == FAIL)
414783494b4aSYegappan Lakshmanan || check_for_number_arg(argvars, 1) == FAIL
414883494b4aSYegappan Lakshmanan || check_for_opt_number_arg(argvars, 2) == FAIL))
414983494b4aSYegappan Lakshmanan return;
415083494b4aSYegappan Lakshmanan
41516601b629SBram Moolenaar if (check_can_index(argvars, TRUE, FALSE) == OK)
41526601b629SBram Moolenaar {
41536601b629SBram Moolenaar copy_tv(argvars, rettv);
41546601b629SBram Moolenaar eval_index_inner(rettv, TRUE, argvars + 1,
41556601b629SBram Moolenaar argvars[2].v_type == VAR_UNKNOWN ? NULL : argvars + 2,
41566601b629SBram Moolenaar TRUE, NULL, 0, FALSE);
41576601b629SBram Moolenaar }
41586601b629SBram Moolenaar }
41596601b629SBram Moolenaar
41606601b629SBram Moolenaar /*
4161cc673e74SBram Moolenaar * Apply index or range to "rettv".
4162cc673e74SBram Moolenaar * "var1" is the first index, NULL for [:expr].
4163cc673e74SBram Moolenaar * "var2" is the second index, NULL for [expr] and [expr: ]
41646601b629SBram Moolenaar * "exclusive" is TRUE for slice(): second index is exclusive, use character
41656601b629SBram Moolenaar * index for string.
4166cc673e74SBram Moolenaar * Alternatively, "key" is not NULL, then key[keylen] is the dict index.
4167cc673e74SBram Moolenaar */
4168cc673e74SBram Moolenaar int
eval_index_inner(typval_T * rettv,int is_range,typval_T * var1,typval_T * var2,int exclusive,char_u * key,int keylen,int verbose)4169cc673e74SBram Moolenaar eval_index_inner(
4170cc673e74SBram Moolenaar typval_T *rettv,
4171cc673e74SBram Moolenaar int is_range,
4172cc673e74SBram Moolenaar typval_T *var1,
4173cc673e74SBram Moolenaar typval_T *var2,
41746601b629SBram Moolenaar int exclusive,
4175cc673e74SBram Moolenaar char_u *key,
4176cc673e74SBram Moolenaar int keylen,
4177cc673e74SBram Moolenaar int verbose)
4178cc673e74SBram Moolenaar {
41796601b629SBram Moolenaar varnumber_T n1, n2 = 0;
4180cc673e74SBram Moolenaar long len;
4181cc673e74SBram Moolenaar
4182cc673e74SBram Moolenaar n1 = 0;
4183cc673e74SBram Moolenaar if (var1 != NULL && rettv->v_type != VAR_DICT)
4184cc673e74SBram Moolenaar n1 = tv_get_number(var1);
4185cc673e74SBram Moolenaar
4186cc673e74SBram Moolenaar if (is_range)
4187cc673e74SBram Moolenaar {
4188cc673e74SBram Moolenaar if (rettv->v_type == VAR_DICT)
4189cc673e74SBram Moolenaar {
4190cc673e74SBram Moolenaar if (verbose)
4191cc673e74SBram Moolenaar emsg(_(e_cannot_slice_dictionary));
4192cc673e74SBram Moolenaar return FAIL;
4193cc673e74SBram Moolenaar }
41946601b629SBram Moolenaar if (var2 != NULL)
4195cc673e74SBram Moolenaar n2 = tv_get_number(var2);
41966601b629SBram Moolenaar else
41976601b629SBram Moolenaar n2 = VARNUM_MAX;
419849cd9579SBram Moolenaar }
419949cd9579SBram Moolenaar
4200c70646c6SBram Moolenaar switch (rettv->v_type)
420149cd9579SBram Moolenaar {
4202835dc636SBram Moolenaar case VAR_UNKNOWN:
42034c683750SBram Moolenaar case VAR_ANY:
42048a7d6542SBram Moolenaar case VAR_VOID:
4205a03f2335SBram Moolenaar case VAR_FUNC:
42061735bc98SBram Moolenaar case VAR_PARTIAL:
4207a03f2335SBram Moolenaar case VAR_FLOAT:
42089b4a15d5SBram Moolenaar case VAR_BOOL:
4209835dc636SBram Moolenaar case VAR_SPECIAL:
4210835dc636SBram Moolenaar case VAR_JOB:
42117707344dSBram Moolenaar case VAR_CHANNEL:
4212f18332fbSBram Moolenaar case VAR_INSTR:
42135d18efecSBram Moolenaar break; // not evaluating, skipping over subscript
4214a03f2335SBram Moolenaar
421549cd9579SBram Moolenaar case VAR_NUMBER:
421649cd9579SBram Moolenaar case VAR_STRING:
4217cc673e74SBram Moolenaar {
4218cc673e74SBram Moolenaar char_u *s = tv_get_string(rettv);
4219cc673e74SBram Moolenaar
422049cd9579SBram Moolenaar len = (long)STRLEN(s);
42216601b629SBram Moolenaar if (in_vim9script() || exclusive)
422211107babSBram Moolenaar {
4223cc673e74SBram Moolenaar if (is_range)
42246601b629SBram Moolenaar s = string_slice(s, n1, n2, exclusive);
422511107babSBram Moolenaar else
422611107babSBram Moolenaar s = char_from_string(s, n1);
422711107babSBram Moolenaar }
4228cc673e74SBram Moolenaar else if (is_range)
422949cd9579SBram Moolenaar {
42305d18efecSBram Moolenaar // The resulting variable is a substring. If the indexes
42315d18efecSBram Moolenaar // are out of range the result is empty.
423249cd9579SBram Moolenaar if (n1 < 0)
423349cd9579SBram Moolenaar {
423449cd9579SBram Moolenaar n1 = len + n1;
423549cd9579SBram Moolenaar if (n1 < 0)
423649cd9579SBram Moolenaar n1 = 0;
423749cd9579SBram Moolenaar }
423849cd9579SBram Moolenaar if (n2 < 0)
423949cd9579SBram Moolenaar n2 = len + n2;
424049cd9579SBram Moolenaar else if (n2 >= len)
424149cd9579SBram Moolenaar n2 = len;
424249cd9579SBram Moolenaar if (n1 >= len || n2 < 0 || n1 > n2)
424349cd9579SBram Moolenaar s = NULL;
424449cd9579SBram Moolenaar else
4245df44a27bSBram Moolenaar s = vim_strnsave(s + n1, n2 - n1 + 1);
424649cd9579SBram Moolenaar }
424749cd9579SBram Moolenaar else
424849cd9579SBram Moolenaar {
42495d18efecSBram Moolenaar // The resulting variable is a string of a single
42505d18efecSBram Moolenaar // character. If the index is too big or negative the
42515d18efecSBram Moolenaar // result is empty.
425249cd9579SBram Moolenaar if (n1 >= len || n1 < 0)
425349cd9579SBram Moolenaar s = NULL;
425449cd9579SBram Moolenaar else
425549cd9579SBram Moolenaar s = vim_strnsave(s + n1, 1);
425649cd9579SBram Moolenaar }
4257c70646c6SBram Moolenaar clear_tv(rettv);
4258c70646c6SBram Moolenaar rettv->v_type = VAR_STRING;
4259c70646c6SBram Moolenaar rettv->vval.v_string = s;
4260cc673e74SBram Moolenaar }
426149cd9579SBram Moolenaar break;
426249cd9579SBram Moolenaar
42636e5ea8d2SBram Moolenaar case VAR_BLOB:
4264cfc3023cSBram Moolenaar blob_slice_or_index(rettv->vval.v_blob, is_range, n1, n2,
4265cfc3023cSBram Moolenaar exclusive, rettv);
42666e5ea8d2SBram Moolenaar break;
42676e5ea8d2SBram Moolenaar
426849cd9579SBram Moolenaar case VAR_LIST:
4269cc673e74SBram Moolenaar if (var1 == NULL)
4270ed591877SBram Moolenaar n1 = 0;
4271cc673e74SBram Moolenaar if (var2 == NULL)
42726601b629SBram Moolenaar n2 = VARNUM_MAX;
4273ed591877SBram Moolenaar if (list_slice_or_index(rettv->vval.v_list,
42746601b629SBram Moolenaar is_range, n1, n2, exclusive, rettv, verbose) == FAIL)
427549cd9579SBram Moolenaar return FAIL;
427649cd9579SBram Moolenaar break;
42778c711458SBram Moolenaar
42788c711458SBram Moolenaar case VAR_DICT:
42798c711458SBram Moolenaar {
428033570924SBram Moolenaar dictitem_T *item;
4281cc673e74SBram Moolenaar typval_T tmp;
42828c711458SBram Moolenaar
42830921ecffSBram Moolenaar if (key == NULL)
42848c711458SBram Moolenaar {
4285cc673e74SBram Moolenaar key = tv_get_string_chk(var1);
4286cc673e74SBram Moolenaar if (key == NULL)
42878c711458SBram Moolenaar return FAIL;
428849cd9579SBram Moolenaar }
428949cd9579SBram Moolenaar
4290cc673e74SBram Moolenaar item = dict_find(rettv->vval.v_dict, key, (int)keylen);
42918c711458SBram Moolenaar
42922a8d1f87SBram Moolenaar if (item == NULL && verbose)
4293f9e3e09fSBram Moolenaar semsg(_(e_dictkey), key);
42948c711458SBram Moolenaar if (item == NULL)
42958c711458SBram Moolenaar return FAIL;
42968c711458SBram Moolenaar
4297cc673e74SBram Moolenaar copy_tv(&item->di_tv, &tmp);
42988c711458SBram Moolenaar clear_tv(rettv);
4299cc673e74SBram Moolenaar *rettv = tmp;
43008c711458SBram Moolenaar }
43018c711458SBram Moolenaar break;
43028c711458SBram Moolenaar }
430349cd9579SBram Moolenaar return OK;
430449cd9579SBram Moolenaar }
430549cd9579SBram Moolenaar
430649cd9579SBram Moolenaar /*
43074c683750SBram Moolenaar * Return the function name of partial "pt".
4308437bafe4SBram Moolenaar */
4309437bafe4SBram Moolenaar char_u *
partial_name(partial_T * pt)4310437bafe4SBram Moolenaar partial_name(partial_T *pt)
4311437bafe4SBram Moolenaar {
4312fe8ebdbeSDominique Pelle if (pt != NULL)
4313fe8ebdbeSDominique Pelle {
4314437bafe4SBram Moolenaar if (pt->pt_name != NULL)
4315437bafe4SBram Moolenaar return pt->pt_name;
431692b83ccfSBram Moolenaar if (pt->pt_func != NULL)
4317437bafe4SBram Moolenaar return pt->pt_func->uf_name;
4318fe8ebdbeSDominique Pelle }
431992b83ccfSBram Moolenaar return (char_u *)"";
4320437bafe4SBram Moolenaar }
4321437bafe4SBram Moolenaar
4322ddecc259SBram Moolenaar static void
partial_free(partial_T * pt)4323107e1eefSBram Moolenaar partial_free(partial_T *pt)
4324ddecc259SBram Moolenaar {
4325ddecc259SBram Moolenaar int i;
4326ddecc259SBram Moolenaar
4327ddecc259SBram Moolenaar for (i = 0; i < pt->pt_argc; ++i)
4328107e1eefSBram Moolenaar clear_tv(&pt->pt_argv[i]);
4329ddecc259SBram Moolenaar vim_free(pt->pt_argv);
4330ddecc259SBram Moolenaar dict_unref(pt->pt_dict);
4331437bafe4SBram Moolenaar if (pt->pt_name != NULL)
4332437bafe4SBram Moolenaar {
4333ddecc259SBram Moolenaar func_unref(pt->pt_name);
4334ddecc259SBram Moolenaar vim_free(pt->pt_name);
4335437bafe4SBram Moolenaar }
4336437bafe4SBram Moolenaar else
4337437bafe4SBram Moolenaar func_ptr_unref(pt->pt_func);
4338f7779c63SBram Moolenaar
433954656015SBram Moolenaar // "out_up" is no longer used, decrement refcount on partial that owns it.
434054656015SBram Moolenaar partial_unref(pt->pt_outer.out_up_partial);
434154656015SBram Moolenaar
434285d5e2b7SBram Moolenaar // Decrease the reference count for the context of a closure. If down
434385d5e2b7SBram Moolenaar // to the minimum it may be time to free it.
4344f7779c63SBram Moolenaar if (pt->pt_funcstack != NULL)
4345f7779c63SBram Moolenaar {
434685d5e2b7SBram Moolenaar --pt->pt_funcstack->fs_refcount;
434785d5e2b7SBram Moolenaar funcstack_check_refcount(pt->pt_funcstack);
4348f7779c63SBram Moolenaar }
4349f7779c63SBram Moolenaar
4350ddecc259SBram Moolenaar vim_free(pt);
4351ddecc259SBram Moolenaar }
4352ddecc259SBram Moolenaar
4353ddecc259SBram Moolenaar /*
4354ddecc259SBram Moolenaar * Unreference a closure: decrement the reference count and free it when it
4355ddecc259SBram Moolenaar * becomes zero.
4356ddecc259SBram Moolenaar */
4357ddecc259SBram Moolenaar void
partial_unref(partial_T * pt)4358ddecc259SBram Moolenaar partial_unref(partial_T *pt)
4359ddecc259SBram Moolenaar {
436085d5e2b7SBram Moolenaar if (pt != NULL)
436185d5e2b7SBram Moolenaar {
436285d5e2b7SBram Moolenaar if (--pt->pt_refcount <= 0)
4363107e1eefSBram Moolenaar partial_free(pt);
436485d5e2b7SBram Moolenaar
436585d5e2b7SBram Moolenaar // If the reference count goes down to one, the funcstack may be the
436685d5e2b7SBram Moolenaar // only reference and can be freed if no other partials reference it.
436785d5e2b7SBram Moolenaar else if (pt->pt_refcount == 1 && pt->pt_funcstack != NULL)
436885d5e2b7SBram Moolenaar funcstack_check_refcount(pt->pt_funcstack);
436985d5e2b7SBram Moolenaar }
4370ddecc259SBram Moolenaar }
4371ddecc259SBram Moolenaar
43728a283e50SBram Moolenaar /*
4373520e1e41SBram Moolenaar * Return the next (unique) copy ID.
4374520e1e41SBram Moolenaar * Used for serializing nested structures.
4375520e1e41SBram Moolenaar */
4376520e1e41SBram Moolenaar int
get_copyID(void)43777454a06eSBram Moolenaar get_copyID(void)
4378520e1e41SBram Moolenaar {
4379520e1e41SBram Moolenaar current_copyID += COPYID_INC;
4380520e1e41SBram Moolenaar return current_copyID;
4381520e1e41SBram Moolenaar }
4382520e1e41SBram Moolenaar
4383520e1e41SBram Moolenaar /*
43849a50b1bfSBram Moolenaar * Garbage collection for lists and dictionaries.
43859a50b1bfSBram Moolenaar *
43869a50b1bfSBram Moolenaar * We use reference counts to be able to free most items right away when they
43879a50b1bfSBram Moolenaar * are no longer used. But for composite items it's possible that it becomes
43889a50b1bfSBram Moolenaar * unused while the reference count is > 0: When there is a recursive
43899a50b1bfSBram Moolenaar * reference. Example:
43909a50b1bfSBram Moolenaar * :let l = [1, 2, 3]
43919a50b1bfSBram Moolenaar * :let d = {9: l}
43929a50b1bfSBram Moolenaar * :let l[1] = d
43939a50b1bfSBram Moolenaar *
43949a50b1bfSBram Moolenaar * Since this is quite unusual we handle this with garbage collection: every
43959a50b1bfSBram Moolenaar * once in a while find out which lists and dicts are not referenced from any
43969a50b1bfSBram Moolenaar * variable.
43979a50b1bfSBram Moolenaar *
43989a50b1bfSBram Moolenaar * Here is a good reference text about garbage collection (refers to Python
43999a50b1bfSBram Moolenaar * but it applies to all reference-counting mechanisms):
44009a50b1bfSBram Moolenaar * http://python.ca/nas/python/gc/
4401d9fba318SBram Moolenaar */
4402d9fba318SBram Moolenaar
4403d9fba318SBram Moolenaar /*
44049a50b1bfSBram Moolenaar * Do garbage collection for lists and dicts.
4405574860b5SBram Moolenaar * When "testing" is TRUE this is called from test_garbagecollect_now().
44069a50b1bfSBram Moolenaar * Return TRUE if some memory was freed.
4407d9fba318SBram Moolenaar */
44089a50b1bfSBram Moolenaar int
garbage_collect(int testing)4409ebf7dfa6SBram Moolenaar garbage_collect(int testing)
4410d9fba318SBram Moolenaar {
4411c0a6fac5SBram Moolenaar int copyID;
44122459a5ecSBram Moolenaar int abort = FALSE;
44139a50b1bfSBram Moolenaar buf_T *buf;
44149a50b1bfSBram Moolenaar win_T *wp;
4415934b1361SBram Moolenaar int did_free = FALSE;
4416910f66f9SBram Moolenaar tabpage_T *tp;
44179a50b1bfSBram Moolenaar
4418ebf7dfa6SBram Moolenaar if (!testing)
4419ebf7dfa6SBram Moolenaar {
44205d18efecSBram Moolenaar // Only do this once.
44219fecb460SBram Moolenaar want_garbage_collect = FALSE;
44229fecb460SBram Moolenaar may_garbage_collect = FALSE;
44239d2c8c1aSBram Moolenaar garbage_collect_at_exit = FALSE;
4424ebf7dfa6SBram Moolenaar }
44259fecb460SBram Moolenaar
44263fbcc128SBram Moolenaar // The execution stack can grow big, limit the size.
44273fbcc128SBram Moolenaar if (exestack.ga_maxlen - exestack.ga_len > 500)
44283fbcc128SBram Moolenaar {
44293fbcc128SBram Moolenaar size_t new_len;
44303fbcc128SBram Moolenaar char_u *pp;
44313fbcc128SBram Moolenaar int n;
44323fbcc128SBram Moolenaar
44333fbcc128SBram Moolenaar // Keep 150% of the current size, with a minimum of the growth size.
44343fbcc128SBram Moolenaar n = exestack.ga_len / 2;
44353fbcc128SBram Moolenaar if (n < exestack.ga_growsize)
44363fbcc128SBram Moolenaar n = exestack.ga_growsize;
44373fbcc128SBram Moolenaar
44383fbcc128SBram Moolenaar // Don't make it bigger though.
44393fbcc128SBram Moolenaar if (exestack.ga_len + n < exestack.ga_maxlen)
44403fbcc128SBram Moolenaar {
44413fbcc128SBram Moolenaar new_len = exestack.ga_itemsize * (exestack.ga_len + n);
44423fbcc128SBram Moolenaar pp = vim_realloc(exestack.ga_data, new_len);
44433fbcc128SBram Moolenaar if (pp == NULL)
44443fbcc128SBram Moolenaar return FAIL;
44453fbcc128SBram Moolenaar exestack.ga_maxlen = exestack.ga_len + n;
44463fbcc128SBram Moolenaar exestack.ga_data = pp;
44473fbcc128SBram Moolenaar }
44483fbcc128SBram Moolenaar }
44493fbcc128SBram Moolenaar
44505d18efecSBram Moolenaar // We advance by two because we add one for items referenced through
44515d18efecSBram Moolenaar // previous_funccal.
4452520e1e41SBram Moolenaar copyID = get_copyID();
4453c0a6fac5SBram Moolenaar
44549a50b1bfSBram Moolenaar /*
44559a50b1bfSBram Moolenaar * 1. Go through all accessible variables and mark all lists and dicts
44569a50b1bfSBram Moolenaar * with copyID.
44579a50b1bfSBram Moolenaar */
4458c0a6fac5SBram Moolenaar
44595d18efecSBram Moolenaar // Don't free variables in the previous_funccal list unless they are only
44605d18efecSBram Moolenaar // referenced through previous_funccal. This must be first, because if
44615d18efecSBram Moolenaar // the item is referenced elsewhere the funccal must not be freed.
4462a9b579f3SBram Moolenaar abort = abort || set_ref_in_previous_funccal(copyID);
4463c0a6fac5SBram Moolenaar
44645d18efecSBram Moolenaar // script-local variables
4465e5cdf153SBram Moolenaar abort = abort || garbage_collect_scriptvars(copyID);
44669a50b1bfSBram Moolenaar
44675d18efecSBram Moolenaar // buffer-local variables
446829323590SBram Moolenaar FOR_ALL_BUFFERS(buf)
44692459a5ecSBram Moolenaar abort = abort || set_ref_in_item(&buf->b_bufvar.di_tv, copyID,
44702459a5ecSBram Moolenaar NULL, NULL);
44719a50b1bfSBram Moolenaar
44725d18efecSBram Moolenaar // window-local variables
4473910f66f9SBram Moolenaar FOR_ALL_TAB_WINDOWS(tp, wp)
44742459a5ecSBram Moolenaar abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID,
44752459a5ecSBram Moolenaar NULL, NULL);
44763bb28557SBram Moolenaar if (aucmd_win != NULL)
44772459a5ecSBram Moolenaar abort = abort || set_ref_in_item(&aucmd_win->w_winvar.di_tv, copyID,
44782459a5ecSBram Moolenaar NULL, NULL);
447905ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
4480aeea7215SBram Moolenaar FOR_ALL_POPUPWINS(wp)
44814d784b21SBram Moolenaar abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID,
44824d784b21SBram Moolenaar NULL, NULL);
44834d784b21SBram Moolenaar FOR_ALL_TABPAGES(tp)
4484aeea7215SBram Moolenaar FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
44854d784b21SBram Moolenaar abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID,
44864d784b21SBram Moolenaar NULL, NULL);
44874d784b21SBram Moolenaar #endif
44889a50b1bfSBram Moolenaar
44895d18efecSBram Moolenaar // tabpage-local variables
449029323590SBram Moolenaar FOR_ALL_TABPAGES(tp)
44912459a5ecSBram Moolenaar abort = abort || set_ref_in_item(&tp->tp_winvar.di_tv, copyID,
44922459a5ecSBram Moolenaar NULL, NULL);
44935d18efecSBram Moolenaar // global variables
4494da6c0334SBram Moolenaar abort = abort || garbage_collect_globvars(copyID);
44959a50b1bfSBram Moolenaar
44965d18efecSBram Moolenaar // function-local variables
4497a9b579f3SBram Moolenaar abort = abort || set_ref_in_call_stack(copyID);
44989a50b1bfSBram Moolenaar
44995d18efecSBram Moolenaar // named functions (matters for closures)
4500bc7ce675SBram Moolenaar abort = abort || set_ref_in_functions(copyID);
4501bc7ce675SBram Moolenaar
45025d18efecSBram Moolenaar // function call arguments, if v:testing is set.
4503a9b579f3SBram Moolenaar abort = abort || set_ref_in_func_args(copyID);
4504ebf7dfa6SBram Moolenaar
45055d18efecSBram Moolenaar // v: vars
4506e5cdf153SBram Moolenaar abort = abort || garbage_collect_vimvars(copyID);
4507d812df63SBram Moolenaar
450875a1a941SBram Moolenaar // callbacks in buffers
450975a1a941SBram Moolenaar abort = abort || set_ref_in_buffers(copyID);
451075a1a941SBram Moolenaar
45111dced572SBram Moolenaar #ifdef FEAT_LUA
45122459a5ecSBram Moolenaar abort = abort || set_ref_in_lua(copyID);
45131dced572SBram Moolenaar #endif
45141dced572SBram Moolenaar
4515db913953SBram Moolenaar #ifdef FEAT_PYTHON
45162459a5ecSBram Moolenaar abort = abort || set_ref_in_python(copyID);
4517db913953SBram Moolenaar #endif
4518db913953SBram Moolenaar
4519db913953SBram Moolenaar #ifdef FEAT_PYTHON3
45202459a5ecSBram Moolenaar abort = abort || set_ref_in_python3(copyID);
4521db913953SBram Moolenaar #endif
4522db913953SBram Moolenaar
4523509ce2a5SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
45243780bb92SBram Moolenaar abort = abort || set_ref_in_channel(copyID);
4525b8d49055SBram Moolenaar abort = abort || set_ref_in_job(copyID);
45264b6a6dcbSBram Moolenaar #endif
45273266c85aSBram Moolenaar #ifdef FEAT_NETBEANS_INTG
45283266c85aSBram Moolenaar abort = abort || set_ref_in_nb_channel(copyID);
45293266c85aSBram Moolenaar #endif
45304b6a6dcbSBram Moolenaar
4531e3188e26SBram Moolenaar #ifdef FEAT_TIMERS
4532e3188e26SBram Moolenaar abort = abort || set_ref_in_timer(copyID);
4533e3188e26SBram Moolenaar #endif
4534e3188e26SBram Moolenaar
45358f77c5a4SBram Moolenaar #ifdef FEAT_QUICKFIX
45368f77c5a4SBram Moolenaar abort = abort || set_ref_in_quickfix(copyID);
45378f77c5a4SBram Moolenaar #endif
45388f77c5a4SBram Moolenaar
4539a2c45a17SBram Moolenaar #ifdef FEAT_TERMINAL
4540a2c45a17SBram Moolenaar abort = abort || set_ref_in_term(copyID);
4541a2c45a17SBram Moolenaar #endif
4542a2c45a17SBram Moolenaar
454305ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
454475a1a941SBram Moolenaar abort = abort || set_ref_in_popups(copyID);
454575a1a941SBram Moolenaar #endif
454675a1a941SBram Moolenaar
45472459a5ecSBram Moolenaar if (!abort)
45482459a5ecSBram Moolenaar {
45492c2398c0SBram Moolenaar /*
45502c2398c0SBram Moolenaar * 2. Free lists and dictionaries that are not referenced.
45512c2398c0SBram Moolenaar */
4552c0a6fac5SBram Moolenaar did_free = free_unref_items(copyID);
4553c0a6fac5SBram Moolenaar
45542c2398c0SBram Moolenaar /*
45552c2398c0SBram Moolenaar * 3. Check if any funccal can be freed now.
4556a9b579f3SBram Moolenaar * This may call us back recursively.
45572c2398c0SBram Moolenaar */
4558a9b579f3SBram Moolenaar free_unref_funccal(copyID, testing);
45592459a5ecSBram Moolenaar }
45602459a5ecSBram Moolenaar else if (p_verbose > 0)
45612459a5ecSBram Moolenaar {
456232526b3cSBram Moolenaar verb_msg(_("Not enough memory to set references, garbage collection aborted!"));
45632459a5ecSBram Moolenaar }
4564c0a6fac5SBram Moolenaar
4565c0a6fac5SBram Moolenaar return did_free;
4566c0a6fac5SBram Moolenaar }
4567c0a6fac5SBram Moolenaar
45689a50b1bfSBram Moolenaar /*
4569107e1eefSBram Moolenaar * Free lists, dictionaries, channels and jobs that are no longer referenced.
4570c0a6fac5SBram Moolenaar */
4571c0a6fac5SBram Moolenaar static int
free_unref_items(int copyID)45727454a06eSBram Moolenaar free_unref_items(int copyID)
4573c0a6fac5SBram Moolenaar {
4574c0a6fac5SBram Moolenaar int did_free = FALSE;
4575c0a6fac5SBram Moolenaar
45765d18efecSBram Moolenaar // Let all "free" functions know that we are here. This means no
45775d18efecSBram Moolenaar // dictionaries, lists, channels or jobs are to be freed, because we will
45785d18efecSBram Moolenaar // do that here.
4579107e1eefSBram Moolenaar in_free_unref_items = TRUE;
4580107e1eefSBram Moolenaar
4581107e1eefSBram Moolenaar /*
4582107e1eefSBram Moolenaar * PASS 1: free the contents of the items. We don't free the items
4583107e1eefSBram Moolenaar * themselves yet, so that it is possible to decrement refcount counters
4584107e1eefSBram Moolenaar */
4585107e1eefSBram Moolenaar
45865d18efecSBram Moolenaar // Go through the list of dicts and free items without the copyID.
4587cd52459cSBram Moolenaar did_free |= dict_free_nonref(copyID);
45889a50b1bfSBram Moolenaar
45895d18efecSBram Moolenaar // Go through the list of lists and free items without the copyID.
4590da861d63SBram Moolenaar did_free |= list_free_nonref(copyID);
4591107e1eefSBram Moolenaar
4592107e1eefSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
45935d18efecSBram Moolenaar // Go through the list of jobs and free items without the copyID. This
45945d18efecSBram Moolenaar // must happen before doing channels, because jobs refer to channels, but
45955d18efecSBram Moolenaar // the reference from the channel to the job isn't tracked.
4596107e1eefSBram Moolenaar did_free |= free_unused_jobs_contents(copyID, COPYID_MASK);
4597107e1eefSBram Moolenaar
45985d18efecSBram Moolenaar // Go through the list of channels and free items without the copyID.
4599107e1eefSBram Moolenaar did_free |= free_unused_channels_contents(copyID, COPYID_MASK);
4600107e1eefSBram Moolenaar #endif
4601107e1eefSBram Moolenaar
4602107e1eefSBram Moolenaar /*
4603107e1eefSBram Moolenaar * PASS 2: free the items themselves.
4604107e1eefSBram Moolenaar */
4605cd52459cSBram Moolenaar dict_free_items(copyID);
4606da861d63SBram Moolenaar list_free_items(copyID);
4607835dc636SBram Moolenaar
4608107e1eefSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
46095d18efecSBram Moolenaar // Go through the list of jobs and free items without the copyID. This
46105d18efecSBram Moolenaar // must happen before doing channels, because jobs refer to channels, but
46115d18efecSBram Moolenaar // the reference from the channel to the job isn't tracked.
4612107e1eefSBram Moolenaar free_unused_jobs(copyID, COPYID_MASK);
4613107e1eefSBram Moolenaar
46145d18efecSBram Moolenaar // Go through the list of channels and free items without the copyID.
4615107e1eefSBram Moolenaar free_unused_channels(copyID, COPYID_MASK);
4616107e1eefSBram Moolenaar #endif
4617107e1eefSBram Moolenaar
4618107e1eefSBram Moolenaar in_free_unref_items = FALSE;
4619107e1eefSBram Moolenaar
46209a50b1bfSBram Moolenaar return did_free;
46219a50b1bfSBram Moolenaar }
46229a50b1bfSBram Moolenaar
46239a50b1bfSBram Moolenaar /*
46249a50b1bfSBram Moolenaar * Mark all lists and dicts referenced through hashtab "ht" with "copyID".
46252459a5ecSBram Moolenaar * "list_stack" is used to add lists to be marked. Can be NULL.
46262459a5ecSBram Moolenaar *
46272459a5ecSBram Moolenaar * Returns TRUE if setting references failed somehow.
46289a50b1bfSBram Moolenaar */
46292459a5ecSBram Moolenaar int
set_ref_in_ht(hashtab_T * ht,int copyID,list_stack_T ** list_stack)46307454a06eSBram Moolenaar set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack)
46319a50b1bfSBram Moolenaar {
46329a50b1bfSBram Moolenaar int todo;
46332459a5ecSBram Moolenaar int abort = FALSE;
46349a50b1bfSBram Moolenaar hashitem_T *hi;
46352459a5ecSBram Moolenaar hashtab_T *cur_ht;
46362459a5ecSBram Moolenaar ht_stack_T *ht_stack = NULL;
46372459a5ecSBram Moolenaar ht_stack_T *tempitem;
46389a50b1bfSBram Moolenaar
46392459a5ecSBram Moolenaar cur_ht = ht;
46402459a5ecSBram Moolenaar for (;;)
46412459a5ecSBram Moolenaar {
46422459a5ecSBram Moolenaar if (!abort)
46432459a5ecSBram Moolenaar {
46445d18efecSBram Moolenaar // Mark each item in the hashtab. If the item contains a hashtab
46455d18efecSBram Moolenaar // it is added to ht_stack, if it contains a list it is added to
46465d18efecSBram Moolenaar // list_stack.
46472459a5ecSBram Moolenaar todo = (int)cur_ht->ht_used;
46482459a5ecSBram Moolenaar for (hi = cur_ht->ht_array; todo > 0; ++hi)
46499a50b1bfSBram Moolenaar if (!HASHITEM_EMPTY(hi))
46509a50b1bfSBram Moolenaar {
46519a50b1bfSBram Moolenaar --todo;
46522459a5ecSBram Moolenaar abort = abort || set_ref_in_item(&HI2DI(hi)->di_tv, copyID,
46532459a5ecSBram Moolenaar &ht_stack, list_stack);
46549a50b1bfSBram Moolenaar }
46559a50b1bfSBram Moolenaar }
46569a50b1bfSBram Moolenaar
46572459a5ecSBram Moolenaar if (ht_stack == NULL)
46582459a5ecSBram Moolenaar break;
46592459a5ecSBram Moolenaar
46605d18efecSBram Moolenaar // take an item from the stack
46612459a5ecSBram Moolenaar cur_ht = ht_stack->ht;
46622459a5ecSBram Moolenaar tempitem = ht_stack;
46632459a5ecSBram Moolenaar ht_stack = ht_stack->prev;
46642459a5ecSBram Moolenaar free(tempitem);
46652459a5ecSBram Moolenaar }
46662459a5ecSBram Moolenaar
46672459a5ecSBram Moolenaar return abort;
46682459a5ecSBram Moolenaar }
46692459a5ecSBram Moolenaar
46709a50b1bfSBram Moolenaar /*
46717be3ab25SBram Moolenaar * Mark a dict and its items with "copyID".
46727be3ab25SBram Moolenaar * Returns TRUE if setting references failed somehow.
46737be3ab25SBram Moolenaar */
46747be3ab25SBram Moolenaar int
set_ref_in_dict(dict_T * d,int copyID)46757be3ab25SBram Moolenaar set_ref_in_dict(dict_T *d, int copyID)
46767be3ab25SBram Moolenaar {
46777be3ab25SBram Moolenaar if (d != NULL && d->dv_copyID != copyID)
46787be3ab25SBram Moolenaar {
46797be3ab25SBram Moolenaar d->dv_copyID = copyID;
46807be3ab25SBram Moolenaar return set_ref_in_ht(&d->dv_hashtab, copyID, NULL);
46817be3ab25SBram Moolenaar }
46827be3ab25SBram Moolenaar return FALSE;
46837be3ab25SBram Moolenaar }
46847be3ab25SBram Moolenaar
46857be3ab25SBram Moolenaar /*
46867be3ab25SBram Moolenaar * Mark a list and its items with "copyID".
46877be3ab25SBram Moolenaar * Returns TRUE if setting references failed somehow.
46887be3ab25SBram Moolenaar */
46897be3ab25SBram Moolenaar int
set_ref_in_list(list_T * ll,int copyID)46907be3ab25SBram Moolenaar set_ref_in_list(list_T *ll, int copyID)
46917be3ab25SBram Moolenaar {
46927be3ab25SBram Moolenaar if (ll != NULL && ll->lv_copyID != copyID)
46937be3ab25SBram Moolenaar {
46947be3ab25SBram Moolenaar ll->lv_copyID = copyID;
46957be3ab25SBram Moolenaar return set_ref_in_list_items(ll, copyID, NULL);
46967be3ab25SBram Moolenaar }
46977be3ab25SBram Moolenaar return FALSE;
46987be3ab25SBram Moolenaar }
46997be3ab25SBram Moolenaar
47007be3ab25SBram Moolenaar /*
47019a50b1bfSBram Moolenaar * Mark all lists and dicts referenced through list "l" with "copyID".
47022459a5ecSBram Moolenaar * "ht_stack" is used to add hashtabs to be marked. Can be NULL.
47032459a5ecSBram Moolenaar *
47042459a5ecSBram Moolenaar * Returns TRUE if setting references failed somehow.
47059a50b1bfSBram Moolenaar */
47062459a5ecSBram Moolenaar int
set_ref_in_list_items(list_T * l,int copyID,ht_stack_T ** ht_stack)47077be3ab25SBram Moolenaar set_ref_in_list_items(list_T *l, int copyID, ht_stack_T **ht_stack)
47089a50b1bfSBram Moolenaar {
47099a50b1bfSBram Moolenaar listitem_T *li;
47102459a5ecSBram Moolenaar int abort = FALSE;
47112459a5ecSBram Moolenaar list_T *cur_l;
47122459a5ecSBram Moolenaar list_stack_T *list_stack = NULL;
47132459a5ecSBram Moolenaar list_stack_T *tempitem;
47149a50b1bfSBram Moolenaar
47152459a5ecSBram Moolenaar cur_l = l;
47162459a5ecSBram Moolenaar for (;;)
47172459a5ecSBram Moolenaar {
471850985eb1SBram Moolenaar if (!abort && cur_l->lv_first != &range_list_item)
47195d18efecSBram Moolenaar // Mark each item in the list. If the item contains a hashtab
47205d18efecSBram Moolenaar // it is added to ht_stack, if it contains a list it is added to
47215d18efecSBram Moolenaar // list_stack.
47222459a5ecSBram Moolenaar for (li = cur_l->lv_first; !abort && li != NULL; li = li->li_next)
47232459a5ecSBram Moolenaar abort = abort || set_ref_in_item(&li->li_tv, copyID,
47242459a5ecSBram Moolenaar ht_stack, &list_stack);
47252459a5ecSBram Moolenaar if (list_stack == NULL)
47262459a5ecSBram Moolenaar break;
47272459a5ecSBram Moolenaar
47285d18efecSBram Moolenaar // take an item from the stack
47292459a5ecSBram Moolenaar cur_l = list_stack->list;
47302459a5ecSBram Moolenaar tempitem = list_stack;
47312459a5ecSBram Moolenaar list_stack = list_stack->prev;
47322459a5ecSBram Moolenaar free(tempitem);
47332459a5ecSBram Moolenaar }
47342459a5ecSBram Moolenaar
47352459a5ecSBram Moolenaar return abort;
47369a50b1bfSBram Moolenaar }
47379a50b1bfSBram Moolenaar
47389a50b1bfSBram Moolenaar /*
47399a50b1bfSBram Moolenaar * Mark all lists and dicts referenced through typval "tv" with "copyID".
47402459a5ecSBram Moolenaar * "list_stack" is used to add lists to be marked. Can be NULL.
47412459a5ecSBram Moolenaar * "ht_stack" is used to add hashtabs to be marked. Can be NULL.
47422459a5ecSBram Moolenaar *
47432459a5ecSBram Moolenaar * Returns TRUE if setting references failed somehow.
47449a50b1bfSBram Moolenaar */
47452459a5ecSBram Moolenaar int
set_ref_in_item(typval_T * tv,int copyID,ht_stack_T ** ht_stack,list_stack_T ** list_stack)47467454a06eSBram Moolenaar set_ref_in_item(
47477454a06eSBram Moolenaar typval_T *tv,
47487454a06eSBram Moolenaar int copyID,
47497454a06eSBram Moolenaar ht_stack_T **ht_stack,
47507454a06eSBram Moolenaar list_stack_T **list_stack)
47519a50b1bfSBram Moolenaar {
47522459a5ecSBram Moolenaar int abort = FALSE;
4753d9fba318SBram Moolenaar
47545f436fcfSBram Moolenaar if (tv->v_type == VAR_DICT)
4755107e1eefSBram Moolenaar {
4756107e1eefSBram Moolenaar dict_T *dd = tv->vval.v_dict;
4757107e1eefSBram Moolenaar
4758d812df63SBram Moolenaar if (dd != NULL && dd->dv_copyID != copyID)
4759d9fba318SBram Moolenaar {
47605d18efecSBram Moolenaar // Didn't see this dict yet.
47619a50b1bfSBram Moolenaar dd->dv_copyID = copyID;
47622459a5ecSBram Moolenaar if (ht_stack == NULL)
47632459a5ecSBram Moolenaar {
47642459a5ecSBram Moolenaar abort = set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack);
47652459a5ecSBram Moolenaar }
47662459a5ecSBram Moolenaar else
47672459a5ecSBram Moolenaar {
476851b6eb47SBram Moolenaar ht_stack_T *newitem = ALLOC_ONE(ht_stack_T);
476951b6eb47SBram Moolenaar
47702459a5ecSBram Moolenaar if (newitem == NULL)
47712459a5ecSBram Moolenaar abort = TRUE;
47722459a5ecSBram Moolenaar else
47732459a5ecSBram Moolenaar {
47742459a5ecSBram Moolenaar newitem->ht = &dd->dv_hashtab;
47752459a5ecSBram Moolenaar newitem->prev = *ht_stack;
47762459a5ecSBram Moolenaar *ht_stack = newitem;
47772459a5ecSBram Moolenaar }
47782459a5ecSBram Moolenaar }
4779d9fba318SBram Moolenaar }
4780a03f2335SBram Moolenaar }
4781a03f2335SBram Moolenaar else if (tv->v_type == VAR_LIST)
4782a03f2335SBram Moolenaar {
4783107e1eefSBram Moolenaar list_T *ll = tv->vval.v_list;
4784107e1eefSBram Moolenaar
4785d812df63SBram Moolenaar if (ll != NULL && ll->lv_copyID != copyID)
4786d9fba318SBram Moolenaar {
47875d18efecSBram Moolenaar // Didn't see this list yet.
47889a50b1bfSBram Moolenaar ll->lv_copyID = copyID;
47892459a5ecSBram Moolenaar if (list_stack == NULL)
47902459a5ecSBram Moolenaar {
47917be3ab25SBram Moolenaar abort = set_ref_in_list_items(ll, copyID, ht_stack);
47922459a5ecSBram Moolenaar }
47932459a5ecSBram Moolenaar else
47942459a5ecSBram Moolenaar {
479551b6eb47SBram Moolenaar list_stack_T *newitem = ALLOC_ONE(list_stack_T);
479651b6eb47SBram Moolenaar
47972459a5ecSBram Moolenaar if (newitem == NULL)
47982459a5ecSBram Moolenaar abort = TRUE;
47992459a5ecSBram Moolenaar else
48002459a5ecSBram Moolenaar {
48012459a5ecSBram Moolenaar newitem->list = ll;
48022459a5ecSBram Moolenaar newitem->prev = *list_stack;
48032459a5ecSBram Moolenaar *list_stack = newitem;
48042459a5ecSBram Moolenaar }
48052459a5ecSBram Moolenaar }
4806d9fba318SBram Moolenaar }
4807d9fba318SBram Moolenaar }
48081e96d9bfSBram Moolenaar else if (tv->v_type == VAR_FUNC)
48091e96d9bfSBram Moolenaar {
4810437bafe4SBram Moolenaar abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
48111e96d9bfSBram Moolenaar }
4812107e1eefSBram Moolenaar else if (tv->v_type == VAR_PARTIAL)
4813107e1eefSBram Moolenaar {
4814107e1eefSBram Moolenaar partial_T *pt = tv->vval.v_partial;
4815107e1eefSBram Moolenaar int i;
4816107e1eefSBram Moolenaar
4817b68b346eSBram Moolenaar if (pt != NULL && pt->pt_copyID != copyID)
4818107e1eefSBram Moolenaar {
4819b68b346eSBram Moolenaar // Didn't see this partial yet.
4820b68b346eSBram Moolenaar pt->pt_copyID = copyID;
4821b68b346eSBram Moolenaar
4822437bafe4SBram Moolenaar abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
48231e96d9bfSBram Moolenaar
4824107e1eefSBram Moolenaar if (pt->pt_dict != NULL)
4825107e1eefSBram Moolenaar {
4826107e1eefSBram Moolenaar typval_T dtv;
4827107e1eefSBram Moolenaar
4828107e1eefSBram Moolenaar dtv.v_type = VAR_DICT;
4829107e1eefSBram Moolenaar dtv.vval.v_dict = pt->pt_dict;
4830107e1eefSBram Moolenaar set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
4831107e1eefSBram Moolenaar }
4832107e1eefSBram Moolenaar
4833107e1eefSBram Moolenaar for (i = 0; i < pt->pt_argc; ++i)
4834107e1eefSBram Moolenaar abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID,
4835107e1eefSBram Moolenaar ht_stack, list_stack);
4836f7779c63SBram Moolenaar if (pt->pt_funcstack != NULL)
4837f7779c63SBram Moolenaar {
4838f7779c63SBram Moolenaar typval_T *stack = pt->pt_funcstack->fs_ga.ga_data;
4839f7779c63SBram Moolenaar
4840f7779c63SBram Moolenaar for (i = 0; i < pt->pt_funcstack->fs_ga.ga_len; ++i)
4841f7779c63SBram Moolenaar abort = abort || set_ref_in_item(stack + i, copyID,
4842f7779c63SBram Moolenaar ht_stack, list_stack);
4843f7779c63SBram Moolenaar }
4844f7779c63SBram Moolenaar
4845107e1eefSBram Moolenaar }
4846107e1eefSBram Moolenaar }
4847107e1eefSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
4848107e1eefSBram Moolenaar else if (tv->v_type == VAR_JOB)
4849107e1eefSBram Moolenaar {
4850107e1eefSBram Moolenaar job_T *job = tv->vval.v_job;
4851107e1eefSBram Moolenaar typval_T dtv;
4852107e1eefSBram Moolenaar
4853107e1eefSBram Moolenaar if (job != NULL && job->jv_copyID != copyID)
4854107e1eefSBram Moolenaar {
48550239acb1SBram Moolenaar job->jv_copyID = copyID;
4856107e1eefSBram Moolenaar if (job->jv_channel != NULL)
4857107e1eefSBram Moolenaar {
4858107e1eefSBram Moolenaar dtv.v_type = VAR_CHANNEL;
4859107e1eefSBram Moolenaar dtv.vval.v_channel = job->jv_channel;
4860107e1eefSBram Moolenaar set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
4861107e1eefSBram Moolenaar }
48623a97bb3fSBram Moolenaar if (job->jv_exit_cb.cb_partial != NULL)
4863107e1eefSBram Moolenaar {
4864107e1eefSBram Moolenaar dtv.v_type = VAR_PARTIAL;
48653a97bb3fSBram Moolenaar dtv.vval.v_partial = job->jv_exit_cb.cb_partial;
4866107e1eefSBram Moolenaar set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
4867107e1eefSBram Moolenaar }
4868107e1eefSBram Moolenaar }
4869107e1eefSBram Moolenaar }
4870107e1eefSBram Moolenaar else if (tv->v_type == VAR_CHANNEL)
4871107e1eefSBram Moolenaar {
4872107e1eefSBram Moolenaar channel_T *ch =tv->vval.v_channel;
4873dc0ccaeeSBram Moolenaar ch_part_T part;
4874107e1eefSBram Moolenaar typval_T dtv;
4875107e1eefSBram Moolenaar jsonq_T *jq;
4876107e1eefSBram Moolenaar cbq_T *cq;
4877107e1eefSBram Moolenaar
4878107e1eefSBram Moolenaar if (ch != NULL && ch->ch_copyID != copyID)
4879107e1eefSBram Moolenaar {
48800239acb1SBram Moolenaar ch->ch_copyID = copyID;
4881dc0ccaeeSBram Moolenaar for (part = PART_SOCK; part < PART_COUNT; ++part)
4882107e1eefSBram Moolenaar {
4883107e1eefSBram Moolenaar for (jq = ch->ch_part[part].ch_json_head.jq_next; jq != NULL;
4884107e1eefSBram Moolenaar jq = jq->jq_next)
4885107e1eefSBram Moolenaar set_ref_in_item(jq->jq_value, copyID, ht_stack, list_stack);
4886107e1eefSBram Moolenaar for (cq = ch->ch_part[part].ch_cb_head.cq_next; cq != NULL;
4887107e1eefSBram Moolenaar cq = cq->cq_next)
48883a97bb3fSBram Moolenaar if (cq->cq_callback.cb_partial != NULL)
4889107e1eefSBram Moolenaar {
4890107e1eefSBram Moolenaar dtv.v_type = VAR_PARTIAL;
48913a97bb3fSBram Moolenaar dtv.vval.v_partial = cq->cq_callback.cb_partial;
4892107e1eefSBram Moolenaar set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
4893107e1eefSBram Moolenaar }
48943a97bb3fSBram Moolenaar if (ch->ch_part[part].ch_callback.cb_partial != NULL)
4895107e1eefSBram Moolenaar {
4896107e1eefSBram Moolenaar dtv.v_type = VAR_PARTIAL;
48973a97bb3fSBram Moolenaar dtv.vval.v_partial =
48983a97bb3fSBram Moolenaar ch->ch_part[part].ch_callback.cb_partial;
4899107e1eefSBram Moolenaar set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
4900107e1eefSBram Moolenaar }
4901107e1eefSBram Moolenaar }
49023a97bb3fSBram Moolenaar if (ch->ch_callback.cb_partial != NULL)
4903107e1eefSBram Moolenaar {
4904107e1eefSBram Moolenaar dtv.v_type = VAR_PARTIAL;
49053a97bb3fSBram Moolenaar dtv.vval.v_partial = ch->ch_callback.cb_partial;
4906107e1eefSBram Moolenaar set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
4907107e1eefSBram Moolenaar }
49083a97bb3fSBram Moolenaar if (ch->ch_close_cb.cb_partial != NULL)
4909107e1eefSBram Moolenaar {
4910107e1eefSBram Moolenaar dtv.v_type = VAR_PARTIAL;
49113a97bb3fSBram Moolenaar dtv.vval.v_partial = ch->ch_close_cb.cb_partial;
4912107e1eefSBram Moolenaar set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
4913107e1eefSBram Moolenaar }
4914107e1eefSBram Moolenaar }
4915107e1eefSBram Moolenaar }
4916107e1eefSBram Moolenaar #endif
49172459a5ecSBram Moolenaar return abort;
4918d9fba318SBram Moolenaar }
4919d9fba318SBram Moolenaar
49208c711458SBram Moolenaar /*
492149cd9579SBram Moolenaar * Return a string with the string representation of a variable.
492249cd9579SBram Moolenaar * If the memory is allocated "tofree" is set to it, otherwise NULL.
49238a283e50SBram Moolenaar * "numbuf" is used for a number.
4924b71eaaeaSBram Moolenaar * When "copyID" is not NULL replace recursive lists and dicts with "...".
492535422f45SBram Moolenaar * When both "echo_style" and "composite_val" are FALSE, put quotes around
49268e7d6223SBram Moolenaar * strings as "string()", otherwise does not put quotes around strings, as
492735422f45SBram Moolenaar * ":echo" displays values.
492818dfb440SBram Moolenaar * When "restore_copyID" is FALSE, repeated items in dictionaries and lists
492918dfb440SBram Moolenaar * are replaced with "...".
493092c5aba9SBram Moolenaar * May return NULL.
493149cd9579SBram Moolenaar */
4932cd52459cSBram Moolenaar char_u *
echo_string_core(typval_T * tv,char_u ** tofree,char_u * numbuf,int copyID,int echo_style,int restore_copyID,int composite_val)493318dfb440SBram Moolenaar echo_string_core(
49347454a06eSBram Moolenaar typval_T *tv,
49357454a06eSBram Moolenaar char_u **tofree,
49367454a06eSBram Moolenaar char_u *numbuf,
493718dfb440SBram Moolenaar int copyID,
493818dfb440SBram Moolenaar int echo_style,
493918dfb440SBram Moolenaar int restore_copyID,
494035422f45SBram Moolenaar int composite_val)
494149cd9579SBram Moolenaar {
4942e9a41264SBram Moolenaar static int recurse = 0;
4943e9a41264SBram Moolenaar char_u *r = NULL;
4944e9a41264SBram Moolenaar
494533570924SBram Moolenaar if (recurse >= DICT_MAXNEST)
4946e9a41264SBram Moolenaar {
49478502c704SBram Moolenaar if (!did_echo_string_emsg)
49488502c704SBram Moolenaar {
49495d18efecSBram Moolenaar // Only give this message once for a recursive call to avoid
49505d18efecSBram Moolenaar // flooding the user with errors. And stop iterating over lists
49515d18efecSBram Moolenaar // and dicts.
49528502c704SBram Moolenaar did_echo_string_emsg = TRUE;
4953f9e3e09fSBram Moolenaar emsg(_("E724: variable nested too deep for displaying"));
49548502c704SBram Moolenaar }
4955e9a41264SBram Moolenaar *tofree = NULL;
49568502c704SBram Moolenaar return (char_u *)"{E724}";
4957e9a41264SBram Moolenaar }
4958e9a41264SBram Moolenaar ++recurse;
4959e9a41264SBram Moolenaar
496049cd9579SBram Moolenaar switch (tv->v_type)
496149cd9579SBram Moolenaar {
496218dfb440SBram Moolenaar case VAR_STRING:
496335422f45SBram Moolenaar if (echo_style && !composite_val)
496418dfb440SBram Moolenaar {
496518dfb440SBram Moolenaar *tofree = NULL;
496635422f45SBram Moolenaar r = tv->vval.v_string;
496735422f45SBram Moolenaar if (r == NULL)
496835422f45SBram Moolenaar r = (char_u *)"";
496918dfb440SBram Moolenaar }
497018dfb440SBram Moolenaar else
497118dfb440SBram Moolenaar {
497218dfb440SBram Moolenaar *tofree = string_quote(tv->vval.v_string, FALSE);
497318dfb440SBram Moolenaar r = *tofree;
497418dfb440SBram Moolenaar }
497518dfb440SBram Moolenaar break;
497618dfb440SBram Moolenaar
497749cd9579SBram Moolenaar case VAR_FUNC:
497818dfb440SBram Moolenaar if (echo_style)
497918dfb440SBram Moolenaar {
498049cd9579SBram Moolenaar *tofree = NULL;
4981e9a41264SBram Moolenaar r = tv->vval.v_string;
498218dfb440SBram Moolenaar }
498318dfb440SBram Moolenaar else
498418dfb440SBram Moolenaar {
498518dfb440SBram Moolenaar *tofree = string_quote(tv->vval.v_string, TRUE);
498618dfb440SBram Moolenaar r = *tofree;
498718dfb440SBram Moolenaar }
4988e9a41264SBram Moolenaar break;
4989b71eaaeaSBram Moolenaar
49901735bc98SBram Moolenaar case VAR_PARTIAL:
499124c77a1eSBram Moolenaar {
499224c77a1eSBram Moolenaar partial_T *pt = tv->vval.v_partial;
499324c77a1eSBram Moolenaar char_u *fname = string_quote(pt == NULL ? NULL
4994437bafe4SBram Moolenaar : partial_name(pt), FALSE);
499524c77a1eSBram Moolenaar garray_T ga;
499624c77a1eSBram Moolenaar int i;
499724c77a1eSBram Moolenaar char_u *tf;
499824c77a1eSBram Moolenaar
499924c77a1eSBram Moolenaar ga_init2(&ga, 1, 100);
500024c77a1eSBram Moolenaar ga_concat(&ga, (char_u *)"function(");
500124c77a1eSBram Moolenaar if (fname != NULL)
500224c77a1eSBram Moolenaar {
500324c77a1eSBram Moolenaar ga_concat(&ga, fname);
500424c77a1eSBram Moolenaar vim_free(fname);
500524c77a1eSBram Moolenaar }
500624c77a1eSBram Moolenaar if (pt != NULL && pt->pt_argc > 0)
500724c77a1eSBram Moolenaar {
500824c77a1eSBram Moolenaar ga_concat(&ga, (char_u *)", [");
500924c77a1eSBram Moolenaar for (i = 0; i < pt->pt_argc; ++i)
501024c77a1eSBram Moolenaar {
501124c77a1eSBram Moolenaar if (i > 0)
501224c77a1eSBram Moolenaar ga_concat(&ga, (char_u *)", ");
501324c77a1eSBram Moolenaar ga_concat(&ga,
501424c77a1eSBram Moolenaar tv2string(&pt->pt_argv[i], &tf, numbuf, copyID));
501524c77a1eSBram Moolenaar vim_free(tf);
501624c77a1eSBram Moolenaar }
501724c77a1eSBram Moolenaar ga_concat(&ga, (char_u *)"]");
501824c77a1eSBram Moolenaar }
501924c77a1eSBram Moolenaar if (pt != NULL && pt->pt_dict != NULL)
502024c77a1eSBram Moolenaar {
502124c77a1eSBram Moolenaar typval_T dtv;
502224c77a1eSBram Moolenaar
502324c77a1eSBram Moolenaar ga_concat(&ga, (char_u *)", ");
502424c77a1eSBram Moolenaar dtv.v_type = VAR_DICT;
502524c77a1eSBram Moolenaar dtv.vval.v_dict = pt->pt_dict;
502624c77a1eSBram Moolenaar ga_concat(&ga, tv2string(&dtv, &tf, numbuf, copyID));
502724c77a1eSBram Moolenaar vim_free(tf);
502824c77a1eSBram Moolenaar }
502924c77a1eSBram Moolenaar ga_concat(&ga, (char_u *)")");
503024c77a1eSBram Moolenaar
503124c77a1eSBram Moolenaar *tofree = ga.ga_data;
503224c77a1eSBram Moolenaar r = *tofree;
50331735bc98SBram Moolenaar break;
503424c77a1eSBram Moolenaar }
50351735bc98SBram Moolenaar
50366e5ea8d2SBram Moolenaar case VAR_BLOB:
50378c8b8bb5SBram Moolenaar r = blob2string(tv->vval.v_blob, tofree, numbuf);
50386e5ea8d2SBram Moolenaar break;
50396e5ea8d2SBram Moolenaar
504049cd9579SBram Moolenaar case VAR_LIST:
5041b71eaaeaSBram Moolenaar if (tv->vval.v_list == NULL)
5042b71eaaeaSBram Moolenaar {
5043db950e4cSBram Moolenaar // NULL list is equivalent to empty list.
5044b71eaaeaSBram Moolenaar *tofree = NULL;
5045db950e4cSBram Moolenaar r = (char_u *)"[]";
5046b71eaaeaSBram Moolenaar }
504718dfb440SBram Moolenaar else if (copyID != 0 && tv->vval.v_list->lv_copyID == copyID
504818dfb440SBram Moolenaar && tv->vval.v_list->lv_len > 0)
5049b71eaaeaSBram Moolenaar {
5050b71eaaeaSBram Moolenaar *tofree = NULL;
5051b71eaaeaSBram Moolenaar r = (char_u *)"[...]";
5052b71eaaeaSBram Moolenaar }
5053b71eaaeaSBram Moolenaar else
5054b71eaaeaSBram Moolenaar {
505518dfb440SBram Moolenaar int old_copyID = tv->vval.v_list->lv_copyID;
505618dfb440SBram Moolenaar
5057b71eaaeaSBram Moolenaar tv->vval.v_list->lv_copyID = copyID;
505818dfb440SBram Moolenaar *tofree = list2string(tv, copyID, restore_copyID);
505918dfb440SBram Moolenaar if (restore_copyID)
506018dfb440SBram Moolenaar tv->vval.v_list->lv_copyID = old_copyID;
5061e9a41264SBram Moolenaar r = *tofree;
5062b71eaaeaSBram Moolenaar }
5063e9a41264SBram Moolenaar break;
5064b71eaaeaSBram Moolenaar
50658c711458SBram Moolenaar case VAR_DICT:
5066b71eaaeaSBram Moolenaar if (tv->vval.v_dict == NULL)
5067b71eaaeaSBram Moolenaar {
5068ea04a6e8SBram Moolenaar // NULL dict is equivalent to empty dict.
5069b71eaaeaSBram Moolenaar *tofree = NULL;
5070ea04a6e8SBram Moolenaar r = (char_u *)"{}";
5071b71eaaeaSBram Moolenaar }
507218dfb440SBram Moolenaar else if (copyID != 0 && tv->vval.v_dict->dv_copyID == copyID
507318dfb440SBram Moolenaar && tv->vval.v_dict->dv_hashtab.ht_used != 0)
5074b71eaaeaSBram Moolenaar {
5075b71eaaeaSBram Moolenaar *tofree = NULL;
5076b71eaaeaSBram Moolenaar r = (char_u *)"{...}";
5077b71eaaeaSBram Moolenaar }
5078b71eaaeaSBram Moolenaar else
5079b71eaaeaSBram Moolenaar {
508018dfb440SBram Moolenaar int old_copyID = tv->vval.v_dict->dv_copyID;
5081ea04a6e8SBram Moolenaar
5082b71eaaeaSBram Moolenaar tv->vval.v_dict->dv_copyID = copyID;
508318dfb440SBram Moolenaar *tofree = dict2string(tv, copyID, restore_copyID);
508418dfb440SBram Moolenaar if (restore_copyID)
508518dfb440SBram Moolenaar tv->vval.v_dict->dv_copyID = old_copyID;
5086e9a41264SBram Moolenaar r = *tofree;
5087b71eaaeaSBram Moolenaar }
5088e9a41264SBram Moolenaar break;
5089b71eaaeaSBram Moolenaar
5090c70646c6SBram Moolenaar case VAR_NUMBER:
5091a03f2335SBram Moolenaar case VAR_UNKNOWN:
50924c683750SBram Moolenaar case VAR_ANY:
50938a7d6542SBram Moolenaar case VAR_VOID:
509435422f45SBram Moolenaar *tofree = NULL;
5095d155d7a8SBram Moolenaar r = tv_get_string_buf(tv, numbuf);
509635422f45SBram Moolenaar break;
509735422f45SBram Moolenaar
5098835dc636SBram Moolenaar case VAR_JOB:
50997707344dSBram Moolenaar case VAR_CHANNEL:
5100f5bfa8faSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
5101e9a41264SBram Moolenaar *tofree = NULL;
51021328bde9SBram Moolenaar r = tv->v_type == VAR_JOB ? job_to_string_buf(tv, numbuf)
51031328bde9SBram Moolenaar : channel_to_string_buf(tv, numbuf);
510435422f45SBram Moolenaar if (composite_val)
510535422f45SBram Moolenaar {
510635422f45SBram Moolenaar *tofree = string_quote(r, FALSE);
510735422f45SBram Moolenaar r = *tofree;
510835422f45SBram Moolenaar }
5109f5bfa8faSBram Moolenaar #endif
511049cd9579SBram Moolenaar break;
5111b71eaaeaSBram Moolenaar
5112f18332fbSBram Moolenaar case VAR_INSTR:
5113f18332fbSBram Moolenaar *tofree = NULL;
5114f18332fbSBram Moolenaar r = (char_u *)"instructions";
5115f18332fbSBram Moolenaar break;
5116f18332fbSBram Moolenaar
51178c8de839SBram Moolenaar case VAR_FLOAT:
5118835dc636SBram Moolenaar #ifdef FEAT_FLOAT
51198c8de839SBram Moolenaar *tofree = NULL;
51208c8de839SBram Moolenaar vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", tv->vval.v_float);
51218c8de839SBram Moolenaar r = numbuf;
51228c8de839SBram Moolenaar break;
51238c8de839SBram Moolenaar #endif
51248c8de839SBram Moolenaar
51259b4a15d5SBram Moolenaar case VAR_BOOL:
5126520e1e41SBram Moolenaar case VAR_SPECIAL:
5127520e1e41SBram Moolenaar *tofree = NULL;
512817a13437SBram Moolenaar r = (char_u *)get_var_special_name(tv->vval.v_number);
5129520e1e41SBram Moolenaar break;
5130e9a41264SBram Moolenaar }
5131e9a41264SBram Moolenaar
51328502c704SBram Moolenaar if (--recurse == 0)
51338502c704SBram Moolenaar did_echo_string_emsg = FALSE;
5134e9a41264SBram Moolenaar return r;
513531c67ef8SBram Moolenaar }
513631c67ef8SBram Moolenaar
513731c67ef8SBram Moolenaar /*
513831c67ef8SBram Moolenaar * Return a string with the string representation of a variable.
513931c67ef8SBram Moolenaar * If the memory is allocated "tofree" is set to it, otherwise NULL.
514031c67ef8SBram Moolenaar * "numbuf" is used for a number.
514118dfb440SBram Moolenaar * Does not put quotes around strings, as ":echo" displays values.
514218dfb440SBram Moolenaar * When "copyID" is not NULL replace recursive lists and dicts with "...".
514318dfb440SBram Moolenaar * May return NULL.
514418dfb440SBram Moolenaar */
5145a9b579f3SBram Moolenaar char_u *
echo_string(typval_T * tv,char_u ** tofree,char_u * numbuf,int copyID)514618dfb440SBram Moolenaar echo_string(
514718dfb440SBram Moolenaar typval_T *tv,
514818dfb440SBram Moolenaar char_u **tofree,
514918dfb440SBram Moolenaar char_u *numbuf,
515018dfb440SBram Moolenaar int copyID)
515118dfb440SBram Moolenaar {
515218dfb440SBram Moolenaar return echo_string_core(tv, tofree, numbuf, copyID, TRUE, FALSE, FALSE);
515318dfb440SBram Moolenaar }
515418dfb440SBram Moolenaar
515518dfb440SBram Moolenaar /*
51566f02b00bSBram Moolenaar * Convert the specified byte index of line 'lnum' in buffer 'buf' to a
51576f02b00bSBram Moolenaar * character index. Works only for loaded buffers. Returns -1 on failure.
51589145846bSBram Moolenaar * The index of the first byte and the first character is zero.
51596f02b00bSBram Moolenaar */
51606f02b00bSBram Moolenaar int
buf_byteidx_to_charidx(buf_T * buf,int lnum,int byteidx)51616f02b00bSBram Moolenaar buf_byteidx_to_charidx(buf_T *buf, int lnum, int byteidx)
51626f02b00bSBram Moolenaar {
51636f02b00bSBram Moolenaar char_u *str;
51649145846bSBram Moolenaar char_u *t;
51659145846bSBram Moolenaar int count;
51666f02b00bSBram Moolenaar
51676f02b00bSBram Moolenaar if (buf == NULL || buf->b_ml.ml_mfp == NULL)
51686f02b00bSBram Moolenaar return -1;
51696f02b00bSBram Moolenaar
51706f02b00bSBram Moolenaar if (lnum > buf->b_ml.ml_line_count)
51716f02b00bSBram Moolenaar lnum = buf->b_ml.ml_line_count;
51726f02b00bSBram Moolenaar
51736f02b00bSBram Moolenaar str = ml_get_buf(buf, lnum, FALSE);
51746f02b00bSBram Moolenaar if (str == NULL)
51756f02b00bSBram Moolenaar return -1;
51766f02b00bSBram Moolenaar
51776f02b00bSBram Moolenaar if (*str == NUL)
51789145846bSBram Moolenaar return 0;
51796f02b00bSBram Moolenaar
51809145846bSBram Moolenaar // count the number of characters
51819145846bSBram Moolenaar t = str;
51829145846bSBram Moolenaar for (count = 0; *t != NUL && t <= str + byteidx; count++)
51839145846bSBram Moolenaar t += mb_ptr2len(t);
51849145846bSBram Moolenaar
51859145846bSBram Moolenaar // In insert mode, when the cursor is at the end of a non-empty line,
51869145846bSBram Moolenaar // byteidx points to the NUL character immediately past the end of the
51879145846bSBram Moolenaar // string. In this case, add one to the character count.
51889145846bSBram Moolenaar if (*t == NUL && byteidx != 0 && t == str + byteidx)
51899145846bSBram Moolenaar count++;
51909145846bSBram Moolenaar
51919145846bSBram Moolenaar return count - 1;
51926f02b00bSBram Moolenaar }
51936f02b00bSBram Moolenaar
51946f02b00bSBram Moolenaar /*
51956f02b00bSBram Moolenaar * Convert the specified character index of line 'lnum' in buffer 'buf' to a
51969145846bSBram Moolenaar * byte index. Works only for loaded buffers. Returns -1 on failure.
51979145846bSBram Moolenaar * The index of the first byte and the first character is zero.
51986f02b00bSBram Moolenaar */
51996f02b00bSBram Moolenaar int
buf_charidx_to_byteidx(buf_T * buf,int lnum,int charidx)52006f02b00bSBram Moolenaar buf_charidx_to_byteidx(buf_T *buf, int lnum, int charidx)
52016f02b00bSBram Moolenaar {
52026f02b00bSBram Moolenaar char_u *str;
52036f02b00bSBram Moolenaar char_u *t;
52046f02b00bSBram Moolenaar
52056f02b00bSBram Moolenaar if (buf == NULL || buf->b_ml.ml_mfp == NULL)
52066f02b00bSBram Moolenaar return -1;
52076f02b00bSBram Moolenaar
52086f02b00bSBram Moolenaar if (lnum > buf->b_ml.ml_line_count)
52096f02b00bSBram Moolenaar lnum = buf->b_ml.ml_line_count;
52106f02b00bSBram Moolenaar
52116f02b00bSBram Moolenaar str = ml_get_buf(buf, lnum, FALSE);
52126f02b00bSBram Moolenaar if (str == NULL)
52136f02b00bSBram Moolenaar return -1;
52146f02b00bSBram Moolenaar
52156f02b00bSBram Moolenaar // Convert the character offset to a byte offset
52166f02b00bSBram Moolenaar t = str;
52176f02b00bSBram Moolenaar while (*t != NUL && --charidx > 0)
52186f02b00bSBram Moolenaar t += mb_ptr2len(t);
52196f02b00bSBram Moolenaar
52209145846bSBram Moolenaar return t - str;
52216f02b00bSBram Moolenaar }
52226f02b00bSBram Moolenaar
52236f02b00bSBram Moolenaar /*
5224071d4279SBram Moolenaar * Translate a String variable into a position.
522532466aa2SBram Moolenaar * Returns NULL when there is an error.
5226071d4279SBram Moolenaar */
522773dad1e6SBram Moolenaar pos_T *
var2fpos(typval_T * varp,int dollar_lnum,int * fnum,int charcol)52287454a06eSBram Moolenaar var2fpos(
52297454a06eSBram Moolenaar typval_T *varp,
52305d18efecSBram Moolenaar int dollar_lnum, // TRUE when $ is last line
52316f02b00bSBram Moolenaar int *fnum, // set to fnum for '0, 'A, etc.
52326f02b00bSBram Moolenaar int charcol) // return character column
5233071d4279SBram Moolenaar {
5234071d4279SBram Moolenaar char_u *name;
5235071d4279SBram Moolenaar static pos_T pos;
5236071d4279SBram Moolenaar pos_T *pp;
5237071d4279SBram Moolenaar
52385d18efecSBram Moolenaar // Argument can be [lnum, col, coladd].
523932466aa2SBram Moolenaar if (varp->v_type == VAR_LIST)
524032466aa2SBram Moolenaar {
524132466aa2SBram Moolenaar list_T *l;
524232466aa2SBram Moolenaar int len;
5243a5525208SBram Moolenaar int error = FALSE;
5244477933cdSBram Moolenaar listitem_T *li;
524532466aa2SBram Moolenaar
524632466aa2SBram Moolenaar l = varp->vval.v_list;
524732466aa2SBram Moolenaar if (l == NULL)
524832466aa2SBram Moolenaar return NULL;
524932466aa2SBram Moolenaar
52505d18efecSBram Moolenaar // Get the line number
5251a5525208SBram Moolenaar pos.lnum = list_find_nr(l, 0L, &error);
5252a5525208SBram Moolenaar if (error || pos.lnum <= 0 || pos.lnum > curbuf->b_ml.ml_line_count)
52535d18efecSBram Moolenaar return NULL; // invalid line number
52546f02b00bSBram Moolenaar if (charcol)
52556f02b00bSBram Moolenaar len = (long)mb_charlen(ml_get(pos.lnum));
52566f02b00bSBram Moolenaar else
525732466aa2SBram Moolenaar len = (long)STRLEN(ml_get(pos.lnum));
5258477933cdSBram Moolenaar
5259ec65d77fSBram Moolenaar // Get the column number
52605d18efecSBram Moolenaar // We accept "$" for the column number: last column.
5261477933cdSBram Moolenaar li = list_find(l, 1L);
5262477933cdSBram Moolenaar if (li != NULL && li->li_tv.v_type == VAR_STRING
5263477933cdSBram Moolenaar && li->li_tv.vval.v_string != NULL
5264477933cdSBram Moolenaar && STRCMP(li->li_tv.vval.v_string, "$") == 0)
5265ec65d77fSBram Moolenaar {
5266477933cdSBram Moolenaar pos.col = len + 1;
5267ec65d77fSBram Moolenaar }
5268ec65d77fSBram Moolenaar else
5269ec65d77fSBram Moolenaar {
5270ec65d77fSBram Moolenaar pos.col = list_find_nr(l, 1L, &error);
5271ec65d77fSBram Moolenaar if (error)
5272ec65d77fSBram Moolenaar return NULL;
5273ec65d77fSBram Moolenaar }
5274477933cdSBram Moolenaar
52755d18efecSBram Moolenaar // Accept a position up to the NUL after the line.
52764c3f536fSBram Moolenaar if (pos.col == 0 || (int)pos.col > len + 1)
52775d18efecSBram Moolenaar return NULL; // invalid column number
5278a5525208SBram Moolenaar --pos.col;
527932466aa2SBram Moolenaar
52805d18efecSBram Moolenaar // Get the virtual offset. Defaults to zero.
5281a5525208SBram Moolenaar pos.coladd = list_find_nr(l, 2L, &error);
5282a5525208SBram Moolenaar if (error)
5283a5525208SBram Moolenaar pos.coladd = 0;
5284a5525208SBram Moolenaar
528532466aa2SBram Moolenaar return &pos;
528632466aa2SBram Moolenaar }
528732466aa2SBram Moolenaar
5288c5809439SBram Moolenaar if (in_vim9script() && check_for_string_arg(varp, 0) == FAIL)
5289c5809439SBram Moolenaar return NULL;
5290c5809439SBram Moolenaar
5291d155d7a8SBram Moolenaar name = tv_get_string_chk(varp);
52929ba0eb85SBram Moolenaar if (name == NULL)
52939ba0eb85SBram Moolenaar return NULL;
52945d18efecSBram Moolenaar if (name[0] == '.') // cursor
52956f02b00bSBram Moolenaar {
52966f02b00bSBram Moolenaar pos = curwin->w_cursor;
52976f02b00bSBram Moolenaar if (charcol)
52989145846bSBram Moolenaar pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col);
52996f02b00bSBram Moolenaar return &pos;
53006f02b00bSBram Moolenaar }
53015d18efecSBram Moolenaar if (name[0] == 'v' && name[1] == NUL) // Visual start
53029ecd0232SBram Moolenaar {
53039ecd0232SBram Moolenaar if (VIsual_active)
53046f02b00bSBram Moolenaar pos = VIsual;
53056f02b00bSBram Moolenaar else
53066f02b00bSBram Moolenaar pos = curwin->w_cursor;
53076f02b00bSBram Moolenaar if (charcol)
53089145846bSBram Moolenaar pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col);
53096f02b00bSBram Moolenaar return &pos;
53109ecd0232SBram Moolenaar }
53115d18efecSBram Moolenaar if (name[0] == '\'') // mark
5312071d4279SBram Moolenaar {
53139d182dd0SBram Moolenaar pp = getmark_buf_fnum(curbuf, name[1], FALSE, fnum);
5314071d4279SBram Moolenaar if (pp == NULL || pp == (pos_T *)-1 || pp->lnum <= 0)
5315071d4279SBram Moolenaar return NULL;
53166f02b00bSBram Moolenaar if (charcol)
53179145846bSBram Moolenaar pp->col = buf_byteidx_to_charidx(curbuf, pp->lnum, pp->col);
5318071d4279SBram Moolenaar return pp;
5319071d4279SBram Moolenaar }
5320a5525208SBram Moolenaar
5321a5525208SBram Moolenaar pos.coladd = 0;
5322a5525208SBram Moolenaar
5323477933cdSBram Moolenaar if (name[0] == 'w' && dollar_lnum)
5324f52c725cSBram Moolenaar {
5325f52c725cSBram Moolenaar pos.col = 0;
53265d18efecSBram Moolenaar if (name[1] == '0') // "w0": first visible line
5327f52c725cSBram Moolenaar {
5328f740b29aSBram Moolenaar update_topline();
53295d18efecSBram Moolenaar // In silent Ex mode topline is zero, but that's not a valid line
53305d18efecSBram Moolenaar // number; use one instead.
5331a1d5fa65SBram Moolenaar pos.lnum = curwin->w_topline > 0 ? curwin->w_topline : 1;
5332f52c725cSBram Moolenaar return &pos;
5333f52c725cSBram Moolenaar }
53345d18efecSBram Moolenaar else if (name[1] == '$') // "w$": last visible line
5335f52c725cSBram Moolenaar {
5336f740b29aSBram Moolenaar validate_botline();
53375d18efecSBram Moolenaar // In silent Ex mode botline is zero, return zero then.
5338a1d5fa65SBram Moolenaar pos.lnum = curwin->w_botline > 0 ? curwin->w_botline - 1 : 0;
5339f52c725cSBram Moolenaar return &pos;
5340f52c725cSBram Moolenaar }
5341f52c725cSBram Moolenaar }
53425d18efecSBram Moolenaar else if (name[0] == '$') // last column or line
5343071d4279SBram Moolenaar {
5344477933cdSBram Moolenaar if (dollar_lnum)
5345071d4279SBram Moolenaar {
5346071d4279SBram Moolenaar pos.lnum = curbuf->b_ml.ml_line_count;
5347071d4279SBram Moolenaar pos.col = 0;
5348071d4279SBram Moolenaar }
5349071d4279SBram Moolenaar else
5350071d4279SBram Moolenaar {
5351071d4279SBram Moolenaar pos.lnum = curwin->w_cursor.lnum;
53526f02b00bSBram Moolenaar if (charcol)
53536f02b00bSBram Moolenaar pos.col = (colnr_T)mb_charlen(ml_get_curline());
53546f02b00bSBram Moolenaar else
5355071d4279SBram Moolenaar pos.col = (colnr_T)STRLEN(ml_get_curline());
5356071d4279SBram Moolenaar }
5357071d4279SBram Moolenaar return &pos;
5358071d4279SBram Moolenaar }
53590f1227f7SBram Moolenaar if (in_vim9script())
53600f1227f7SBram Moolenaar semsg(_(e_invalid_value_for_line_number_str), name);
5361071d4279SBram Moolenaar return NULL;
5362071d4279SBram Moolenaar }
5363071d4279SBram Moolenaar
5364071d4279SBram Moolenaar /*
53650e34f626SBram Moolenaar * Convert list in "arg" into a position and optional file number.
53660e34f626SBram Moolenaar * When "fnump" is NULL there is no file number, only 3 items.
53670e34f626SBram Moolenaar * Note that the column is passed on as-is, the caller may want to decrement
53680e34f626SBram Moolenaar * it to use 1 for the first column.
53690e34f626SBram Moolenaar * Return FAIL when conversion is not possible, doesn't check the position for
53700e34f626SBram Moolenaar * validity.
53710e34f626SBram Moolenaar */
537273dad1e6SBram Moolenaar int
list2fpos(typval_T * arg,pos_T * posp,int * fnump,colnr_T * curswantp,int charcol)53737454a06eSBram Moolenaar list2fpos(
53747454a06eSBram Moolenaar typval_T *arg,
53757454a06eSBram Moolenaar pos_T *posp,
53767454a06eSBram Moolenaar int *fnump,
53776f02b00bSBram Moolenaar colnr_T *curswantp,
53786f02b00bSBram Moolenaar int charcol)
53790e34f626SBram Moolenaar {
53800e34f626SBram Moolenaar list_T *l = arg->vval.v_list;
53810e34f626SBram Moolenaar long i = 0;
53820e34f626SBram Moolenaar long n;
53830e34f626SBram Moolenaar
53845d18efecSBram Moolenaar // List must be: [fnum, lnum, col, coladd, curswant], where "fnum" is only
53855d18efecSBram Moolenaar // there when "fnump" isn't NULL; "coladd" and "curswant" are optional.
5386bde35269SBram Moolenaar if (arg->v_type != VAR_LIST
5387bde35269SBram Moolenaar || l == NULL
5388bde35269SBram Moolenaar || l->lv_len < (fnump == NULL ? 2 : 3)
5389493c178aSBram Moolenaar || l->lv_len > (fnump == NULL ? 4 : 5))
53900e34f626SBram Moolenaar return FAIL;
53910e34f626SBram Moolenaar
53920e34f626SBram Moolenaar if (fnump != NULL)
53930e34f626SBram Moolenaar {
53945d18efecSBram Moolenaar n = list_find_nr(l, i++, NULL); // fnum
53950e34f626SBram Moolenaar if (n < 0)
53960e34f626SBram Moolenaar return FAIL;
53970e34f626SBram Moolenaar if (n == 0)
53985d18efecSBram Moolenaar n = curbuf->b_fnum; // current buffer
53990e34f626SBram Moolenaar *fnump = n;
54000e34f626SBram Moolenaar }
54010e34f626SBram Moolenaar
54025d18efecSBram Moolenaar n = list_find_nr(l, i++, NULL); // lnum
54030e34f626SBram Moolenaar if (n < 0)
54040e34f626SBram Moolenaar return FAIL;
54050e34f626SBram Moolenaar posp->lnum = n;
54060e34f626SBram Moolenaar
54075d18efecSBram Moolenaar n = list_find_nr(l, i++, NULL); // col
54080e34f626SBram Moolenaar if (n < 0)
54090e34f626SBram Moolenaar return FAIL;
54106f02b00bSBram Moolenaar // If character position is specified, then convert to byte position
54116f02b00bSBram Moolenaar if (charcol)
54126f02b00bSBram Moolenaar {
54136f02b00bSBram Moolenaar buf_T *buf;
54146f02b00bSBram Moolenaar
54156f02b00bSBram Moolenaar // Get the text for the specified line in a loaded buffer
54166f02b00bSBram Moolenaar buf = buflist_findnr(fnump == NULL ? curbuf->b_fnum : *fnump);
54176f02b00bSBram Moolenaar if (buf == NULL || buf->b_ml.ml_mfp == NULL)
54186f02b00bSBram Moolenaar return FAIL;
54196f02b00bSBram Moolenaar
54209145846bSBram Moolenaar n = buf_charidx_to_byteidx(buf, posp->lnum, n) + 1;
54216f02b00bSBram Moolenaar }
54220e34f626SBram Moolenaar posp->col = n;
54230e34f626SBram Moolenaar
54245d18efecSBram Moolenaar n = list_find_nr(l, i, NULL); // off
54250e34f626SBram Moolenaar if (n < 0)
5426bde35269SBram Moolenaar posp->coladd = 0;
5427bde35269SBram Moolenaar else
54280e34f626SBram Moolenaar posp->coladd = n;
54290e34f626SBram Moolenaar
5430493c178aSBram Moolenaar if (curswantp != NULL)
54315d18efecSBram Moolenaar *curswantp = list_find_nr(l, i + 1, NULL); // curswant
5432493c178aSBram Moolenaar
54330e34f626SBram Moolenaar return OK;
54340e34f626SBram Moolenaar }
54350e34f626SBram Moolenaar
54360e34f626SBram Moolenaar /*
5437071d4279SBram Moolenaar * Get the length of an environment variable name.
5438071d4279SBram Moolenaar * Advance "arg" to the first character after the name.
5439071d4279SBram Moolenaar * Return 0 for error.
5440071d4279SBram Moolenaar */
54410522ba03SBram Moolenaar int
get_env_len(char_u ** arg)54427454a06eSBram Moolenaar get_env_len(char_u **arg)
5443071d4279SBram Moolenaar {
5444071d4279SBram Moolenaar char_u *p;
5445071d4279SBram Moolenaar int len;
5446071d4279SBram Moolenaar
5447071d4279SBram Moolenaar for (p = *arg; vim_isIDc(*p); ++p)
5448071d4279SBram Moolenaar ;
54495d18efecSBram Moolenaar if (p == *arg) // no name found
5450071d4279SBram Moolenaar return 0;
5451071d4279SBram Moolenaar
5452071d4279SBram Moolenaar len = (int)(p - *arg);
5453071d4279SBram Moolenaar *arg = p;
5454071d4279SBram Moolenaar return len;
5455071d4279SBram Moolenaar }
5456071d4279SBram Moolenaar
5457071d4279SBram Moolenaar /*
5458071d4279SBram Moolenaar * Get the length of the name of a function or internal variable.
5459bb1b5e24SBram Moolenaar * "arg" is advanced to after the name.
5460071d4279SBram Moolenaar * Return 0 if something is wrong.
5461071d4279SBram Moolenaar */
5462a9b579f3SBram Moolenaar int
get_id_len(char_u ** arg)54637454a06eSBram Moolenaar get_id_len(char_u **arg)
5464071d4279SBram Moolenaar {
5465071d4279SBram Moolenaar char_u *p;
5466071d4279SBram Moolenaar int len;
5467071d4279SBram Moolenaar
54685d18efecSBram Moolenaar // Find the end of the name.
5469071d4279SBram Moolenaar for (p = *arg; eval_isnamec(*p); ++p)
54709bbf63dbSBram Moolenaar {
54719bbf63dbSBram Moolenaar if (*p == ':')
54729bbf63dbSBram Moolenaar {
54735d18efecSBram Moolenaar // "s:" is start of "s:var", but "n:" is not and can be used in
54745d18efecSBram Moolenaar // slice "[n:]". Also "xx:" is not a namespace.
54759bbf63dbSBram Moolenaar len = (int)(p - *arg);
54769bbf63dbSBram Moolenaar if ((len == 1 && vim_strchr(NAMESPACE_CHAR, **arg) == NULL)
54779bbf63dbSBram Moolenaar || len > 1)
54789bbf63dbSBram Moolenaar break;
54799bbf63dbSBram Moolenaar }
54809bbf63dbSBram Moolenaar }
54815d18efecSBram Moolenaar if (p == *arg) // no name found
5482071d4279SBram Moolenaar return 0;
5483071d4279SBram Moolenaar
5484071d4279SBram Moolenaar len = (int)(p - *arg);
5485bb1b5e24SBram Moolenaar *arg = p;
5486071d4279SBram Moolenaar
5487071d4279SBram Moolenaar return len;
5488071d4279SBram Moolenaar }
5489071d4279SBram Moolenaar
5490071d4279SBram Moolenaar /*
5491a7043832SBram Moolenaar * Get the length of the name of a variable or function.
5492a7043832SBram Moolenaar * Only the name is recognized, does not handle ".key" or "[idx]".
5493071d4279SBram Moolenaar * "arg" is advanced to the first non-white character after the name.
54942a8d1f87SBram Moolenaar * Return -1 if curly braces expansion failed.
54952a8d1f87SBram Moolenaar * Return 0 if something else is wrong.
5496071d4279SBram Moolenaar * If the name contains 'magic' {}'s, expand them and return the
5497071d4279SBram Moolenaar * expanded name in an allocated string via 'alias' - caller must free.
5498071d4279SBram Moolenaar */
54990522ba03SBram Moolenaar int
get_name_len(char_u ** arg,char_u ** alias,int evaluate,int verbose)55007454a06eSBram Moolenaar get_name_len(
55017454a06eSBram Moolenaar char_u **arg,
55027454a06eSBram Moolenaar char_u **alias,
55037454a06eSBram Moolenaar int evaluate,
55047454a06eSBram Moolenaar int verbose)
5505071d4279SBram Moolenaar {
5506071d4279SBram Moolenaar int len;
5507071d4279SBram Moolenaar char_u *p;
5508071d4279SBram Moolenaar char_u *expr_start;
5509071d4279SBram Moolenaar char_u *expr_end;
5510071d4279SBram Moolenaar
55115d18efecSBram Moolenaar *alias = NULL; // default to no alias
5512071d4279SBram Moolenaar
5513071d4279SBram Moolenaar if ((*arg)[0] == K_SPECIAL && (*arg)[1] == KS_EXTRA
5514071d4279SBram Moolenaar && (*arg)[2] == (int)KE_SNR)
5515071d4279SBram Moolenaar {
55165d18efecSBram Moolenaar // hard coded <SNR>, already translated
5517071d4279SBram Moolenaar *arg += 3;
5518071d4279SBram Moolenaar return get_id_len(arg) + 3;
5519071d4279SBram Moolenaar }
5520071d4279SBram Moolenaar len = eval_fname_script(*arg);
5521071d4279SBram Moolenaar if (len > 0)
5522071d4279SBram Moolenaar {
55235d18efecSBram Moolenaar // literal "<SID>", "s:" or "<SNR>"
5524071d4279SBram Moolenaar *arg += len;
5525071d4279SBram Moolenaar }
5526071d4279SBram Moolenaar
5527071d4279SBram Moolenaar /*
5528c70646c6SBram Moolenaar * Find the end of the name; check for {} construction.
5529071d4279SBram Moolenaar */
553034cdc3e3SBram Moolenaar p = find_name_end(*arg, &expr_start, &expr_end,
553134cdc3e3SBram Moolenaar len > 0 ? 0 : FNE_CHECK_START);
5532071d4279SBram Moolenaar if (expr_start != NULL)
5533071d4279SBram Moolenaar {
5534071d4279SBram Moolenaar char_u *temp_string;
5535071d4279SBram Moolenaar
5536071d4279SBram Moolenaar if (!evaluate)
5537071d4279SBram Moolenaar {
5538071d4279SBram Moolenaar len += (int)(p - *arg);
5539071d4279SBram Moolenaar *arg = skipwhite(p);
5540071d4279SBram Moolenaar return len;
5541071d4279SBram Moolenaar }
5542071d4279SBram Moolenaar
5543071d4279SBram Moolenaar /*
5544071d4279SBram Moolenaar * Include any <SID> etc in the expanded string:
5545071d4279SBram Moolenaar * Thus the -len here.
5546071d4279SBram Moolenaar */
5547071d4279SBram Moolenaar temp_string = make_expanded_name(*arg - len, expr_start, expr_end, p);
5548071d4279SBram Moolenaar if (temp_string == NULL)
55492a8d1f87SBram Moolenaar return -1;
5550071d4279SBram Moolenaar *alias = temp_string;
5551071d4279SBram Moolenaar *arg = skipwhite(p);
5552071d4279SBram Moolenaar return (int)STRLEN(temp_string);
5553071d4279SBram Moolenaar }
5554071d4279SBram Moolenaar
5555071d4279SBram Moolenaar len += get_id_len(arg);
55568309b055SBram Moolenaar // Only give an error when there is something, otherwise it will be
55578309b055SBram Moolenaar // reported at a higher level.
55588309b055SBram Moolenaar if (len == 0 && verbose && **arg != NUL)
5559108010aaSBram Moolenaar semsg(_(e_invalid_expression_str), *arg);
5560071d4279SBram Moolenaar
5561071d4279SBram Moolenaar return len;
5562071d4279SBram Moolenaar }
5563071d4279SBram Moolenaar
5564c70646c6SBram Moolenaar /*
5565c70646c6SBram Moolenaar * Find the end of a variable or function name, taking care of magic braces.
5566c70646c6SBram Moolenaar * If "expr_start" is not NULL then "expr_start" and "expr_end" are set to the
5567c70646c6SBram Moolenaar * start and end of the first magic braces item.
556834cdc3e3SBram Moolenaar * "flags" can have FNE_INCL_BR and FNE_CHECK_START.
5569c70646c6SBram Moolenaar * Return a pointer to just after the name. Equal to "arg" if there is no
5570c70646c6SBram Moolenaar * valid name.
5571c70646c6SBram Moolenaar */
5572a9b579f3SBram Moolenaar char_u *
find_name_end(char_u * arg,char_u ** expr_start,char_u ** expr_end,int flags)55737454a06eSBram Moolenaar find_name_end(
55747454a06eSBram Moolenaar char_u *arg,
55757454a06eSBram Moolenaar char_u **expr_start,
55767454a06eSBram Moolenaar char_u **expr_end,
55777454a06eSBram Moolenaar int flags)
5578071d4279SBram Moolenaar {
5579c70646c6SBram Moolenaar int mb_nest = 0;
5580c70646c6SBram Moolenaar int br_nest = 0;
5581071d4279SBram Moolenaar char_u *p;
55829bbf63dbSBram Moolenaar int len;
5583eb6880b6SBram Moolenaar int vim9script = in_vim9script();
5584071d4279SBram Moolenaar
5585c70646c6SBram Moolenaar if (expr_start != NULL)
5586c70646c6SBram Moolenaar {
5587071d4279SBram Moolenaar *expr_start = NULL;
5588071d4279SBram Moolenaar *expr_end = NULL;
5589c70646c6SBram Moolenaar }
5590071d4279SBram Moolenaar
55915d18efecSBram Moolenaar // Quick check for valid starting character.
5592d72c1bf0SBram Moolenaar if ((flags & FNE_CHECK_START) && !eval_isnamec1(*arg)
5593d72c1bf0SBram Moolenaar && (*arg != '{' || vim9script))
559434cdc3e3SBram Moolenaar return arg;
559534cdc3e3SBram Moolenaar
5596c70646c6SBram Moolenaar for (p = arg; *p != NUL
5597c70646c6SBram Moolenaar && (eval_isnamec(*p)
5598d72c1bf0SBram Moolenaar || (*p == '{' && !vim9script)
559963be3d4bSBram Moolenaar || ((flags & FNE_INCL_BR) && (*p == '['
5600b13ab999SBram Moolenaar || (*p == '.' && eval_isdictc(p[1]))))
5601c70646c6SBram Moolenaar || mb_nest != 0
560291acfffcSBram Moolenaar || br_nest != 0); MB_PTR_ADV(p))
5603071d4279SBram Moolenaar {
56048af24428SBram Moolenaar if (*p == '\'')
56058af24428SBram Moolenaar {
56065d18efecSBram Moolenaar // skip over 'string' to avoid counting [ and ] inside it.
560791acfffcSBram Moolenaar for (p = p + 1; *p != NUL && *p != '\''; MB_PTR_ADV(p))
56088af24428SBram Moolenaar ;
56098af24428SBram Moolenaar if (*p == NUL)
56108af24428SBram Moolenaar break;
56118af24428SBram Moolenaar }
56128af24428SBram Moolenaar else if (*p == '"')
56138af24428SBram Moolenaar {
56145d18efecSBram Moolenaar // skip over "str\"ing" to avoid counting [ and ] inside it.
561591acfffcSBram Moolenaar for (p = p + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p))
56168af24428SBram Moolenaar if (*p == '\\' && p[1] != NUL)
56178af24428SBram Moolenaar ++p;
56188af24428SBram Moolenaar if (*p == NUL)
56198af24428SBram Moolenaar break;
56208af24428SBram Moolenaar }
56219bbf63dbSBram Moolenaar else if (br_nest == 0 && mb_nest == 0 && *p == ':')
56229bbf63dbSBram Moolenaar {
56235d18efecSBram Moolenaar // "s:" is start of "s:var", but "n:" is not and can be used in
56245d18efecSBram Moolenaar // slice "[n:]". Also "xx:" is not a namespace. But {ns}: is.
56259bbf63dbSBram Moolenaar len = (int)(p - arg);
56269bbf63dbSBram Moolenaar if ((len == 1 && vim_strchr(NAMESPACE_CHAR, *arg) == NULL)
56274119cf80SBram Moolenaar || (len > 1 && p[-1] != '}'))
56289bbf63dbSBram Moolenaar break;
56299bbf63dbSBram Moolenaar }
56308af24428SBram Moolenaar
5631c70646c6SBram Moolenaar if (mb_nest == 0)
5632c70646c6SBram Moolenaar {
5633c70646c6SBram Moolenaar if (*p == '[')
5634c70646c6SBram Moolenaar ++br_nest;
5635c70646c6SBram Moolenaar else if (*p == ']')
5636c70646c6SBram Moolenaar --br_nest;
5637c70646c6SBram Moolenaar }
56388af24428SBram Moolenaar
5639d72c1bf0SBram Moolenaar if (br_nest == 0 && !vim9script)
5640c70646c6SBram Moolenaar {
5641071d4279SBram Moolenaar if (*p == '{')
5642071d4279SBram Moolenaar {
5643c70646c6SBram Moolenaar mb_nest++;
5644c70646c6SBram Moolenaar if (expr_start != NULL && *expr_start == NULL)
5645071d4279SBram Moolenaar *expr_start = p;
5646071d4279SBram Moolenaar }
5647071d4279SBram Moolenaar else if (*p == '}')
5648071d4279SBram Moolenaar {
5649c70646c6SBram Moolenaar mb_nest--;
5650c70646c6SBram Moolenaar if (expr_start != NULL && mb_nest == 0 && *expr_end == NULL)
5651071d4279SBram Moolenaar *expr_end = p;
5652071d4279SBram Moolenaar }
5653c70646c6SBram Moolenaar }
5654071d4279SBram Moolenaar }
5655071d4279SBram Moolenaar
5656071d4279SBram Moolenaar return p;
5657071d4279SBram Moolenaar }
5658071d4279SBram Moolenaar
5659071d4279SBram Moolenaar /*
56602a8d1f87SBram Moolenaar * Expands out the 'magic' {}'s in a variable/function name.
56612a8d1f87SBram Moolenaar * Note that this can call itself recursively, to deal with
56622a8d1f87SBram Moolenaar * constructs like foo{bar}{baz}{bam}
56632a8d1f87SBram Moolenaar * The four pointer arguments point to "foo{expre}ss{ion}bar"
56642a8d1f87SBram Moolenaar * "in_start" ^
56652a8d1f87SBram Moolenaar * "expr_start" ^
56662a8d1f87SBram Moolenaar * "expr_end" ^
56672a8d1f87SBram Moolenaar * "in_end" ^
56682a8d1f87SBram Moolenaar *
56692a8d1f87SBram Moolenaar * Returns a new allocated string, which the caller must free.
56702a8d1f87SBram Moolenaar * Returns NULL for failure.
56712a8d1f87SBram Moolenaar */
56722a8d1f87SBram Moolenaar static char_u *
make_expanded_name(char_u * in_start,char_u * expr_start,char_u * expr_end,char_u * in_end)56737454a06eSBram Moolenaar make_expanded_name(
56747454a06eSBram Moolenaar char_u *in_start,
56757454a06eSBram Moolenaar char_u *expr_start,
56767454a06eSBram Moolenaar char_u *expr_end,
56777454a06eSBram Moolenaar char_u *in_end)
56782a8d1f87SBram Moolenaar {
56792a8d1f87SBram Moolenaar char_u c1;
56802a8d1f87SBram Moolenaar char_u *retval = NULL;
56812a8d1f87SBram Moolenaar char_u *temp_result;
56822a8d1f87SBram Moolenaar
56832a8d1f87SBram Moolenaar if (expr_end == NULL || in_end == NULL)
56842a8d1f87SBram Moolenaar return NULL;
56852a8d1f87SBram Moolenaar *expr_start = NUL;
56862a8d1f87SBram Moolenaar *expr_end = NUL;
56872a8d1f87SBram Moolenaar c1 = *in_end;
56882a8d1f87SBram Moolenaar *in_end = NUL;
56892a8d1f87SBram Moolenaar
5690b171fb17SBram Moolenaar temp_result = eval_to_string(expr_start + 1, FALSE);
5691b171fb17SBram Moolenaar if (temp_result != NULL)
56922a8d1f87SBram Moolenaar {
5693964b3746SBram Moolenaar retval = alloc(STRLEN(temp_result) + (expr_start - in_start)
5694964b3746SBram Moolenaar + (in_end - expr_end) + 1);
56952a8d1f87SBram Moolenaar if (retval != NULL)
56962a8d1f87SBram Moolenaar {
56972a8d1f87SBram Moolenaar STRCPY(retval, in_start);
56982a8d1f87SBram Moolenaar STRCAT(retval, temp_result);
56992a8d1f87SBram Moolenaar STRCAT(retval, expr_end + 1);
57002a8d1f87SBram Moolenaar }
57012a8d1f87SBram Moolenaar }
57022a8d1f87SBram Moolenaar vim_free(temp_result);
57032a8d1f87SBram Moolenaar
57045d18efecSBram Moolenaar *in_end = c1; // put char back for error messages
57052a8d1f87SBram Moolenaar *expr_start = '{';
57062a8d1f87SBram Moolenaar *expr_end = '}';
57072a8d1f87SBram Moolenaar
57082a8d1f87SBram Moolenaar if (retval != NULL)
57092a8d1f87SBram Moolenaar {
571034cdc3e3SBram Moolenaar temp_result = find_name_end(retval, &expr_start, &expr_end, 0);
57112a8d1f87SBram Moolenaar if (expr_start != NULL)
57122a8d1f87SBram Moolenaar {
57135d18efecSBram Moolenaar // Further expansion!
57142a8d1f87SBram Moolenaar temp_result = make_expanded_name(retval, expr_start,
57152a8d1f87SBram Moolenaar expr_end, temp_result);
57162a8d1f87SBram Moolenaar vim_free(retval);
57172a8d1f87SBram Moolenaar retval = temp_result;
57182a8d1f87SBram Moolenaar }
57192a8d1f87SBram Moolenaar }
57202a8d1f87SBram Moolenaar
57212a8d1f87SBram Moolenaar return retval;
57222a8d1f87SBram Moolenaar }
57232a8d1f87SBram Moolenaar
57242a8d1f87SBram Moolenaar /*
5725071d4279SBram Moolenaar * Return TRUE if character "c" can be used in a variable or function name.
5726e9a41264SBram Moolenaar * Does not include '{' or '}' for magic braces.
5727071d4279SBram Moolenaar */
5728a9b579f3SBram Moolenaar int
eval_isnamec(int c)57297454a06eSBram Moolenaar eval_isnamec(int c)
5730071d4279SBram Moolenaar {
5731b13ab999SBram Moolenaar return ASCII_ISALNUM(c) || c == '_' || c == ':' || c == AUTOLOAD_CHAR;
573234cdc3e3SBram Moolenaar }
573334cdc3e3SBram Moolenaar
573434cdc3e3SBram Moolenaar /*
573534cdc3e3SBram Moolenaar * Return TRUE if character "c" can be used as the first character in a
573634cdc3e3SBram Moolenaar * variable or function name (excluding '{' and '}').
573734cdc3e3SBram Moolenaar */
5738a9b579f3SBram Moolenaar int
eval_isnamec1(int c)57397454a06eSBram Moolenaar eval_isnamec1(int c)
574034cdc3e3SBram Moolenaar {
5741b13ab999SBram Moolenaar return ASCII_ISALPHA(c) || c == '_';
5742b13ab999SBram Moolenaar }
5743b13ab999SBram Moolenaar
5744b13ab999SBram Moolenaar /*
5745b13ab999SBram Moolenaar * Return TRUE if character "c" can be used as the first character of a
5746b13ab999SBram Moolenaar * dictionary key.
5747b13ab999SBram Moolenaar */
5748b13ab999SBram Moolenaar int
eval_isdictc(int c)5749b13ab999SBram Moolenaar eval_isdictc(int c)
5750b13ab999SBram Moolenaar {
5751b13ab999SBram Moolenaar return ASCII_ISALNUM(c) || c == '_';
5752071d4279SBram Moolenaar }
5753071d4279SBram Moolenaar
5754071d4279SBram Moolenaar /*
5755ac92e25aSBram Moolenaar * Handle:
5756ac92e25aSBram Moolenaar * - expr[expr], expr[expr:expr] subscript
5757ac92e25aSBram Moolenaar * - ".name" lookup
5758ac92e25aSBram Moolenaar * - function call with Funcref variable: func(expr)
5759ac92e25aSBram Moolenaar * - method call: var->method()
5760ac92e25aSBram Moolenaar *
5761ac92e25aSBram Moolenaar * Can all be combined in any order: dict.func(expr)[idx]['func'](expr)->len()
57622a8d1f87SBram Moolenaar */
5763a9b579f3SBram Moolenaar int
handle_subscript(char_u ** arg,typval_T * rettv,evalarg_T * evalarg,int verbose)57647454a06eSBram Moolenaar handle_subscript(
57657454a06eSBram Moolenaar char_u **arg,
57667454a06eSBram Moolenaar typval_T *rettv,
5767e40fbc2cSBram Moolenaar evalarg_T *evalarg,
57680b1cd52fSBram Moolenaar int verbose) // give error messages
57692a8d1f87SBram Moolenaar {
5770e40fbc2cSBram Moolenaar int evaluate = evalarg != NULL
5771e40fbc2cSBram Moolenaar && (evalarg->eval_flags & EVAL_EVALUATE);
57722a8d1f87SBram Moolenaar int ret = OK;
57732a8d1f87SBram Moolenaar dict_T *selfdict = NULL;
5774442af2f8SBram Moolenaar int check_white = TRUE;
5775442af2f8SBram Moolenaar int getnext;
57767a4b8980SBram Moolenaar char_u *p;
5777442af2f8SBram Moolenaar
57787a4b8980SBram Moolenaar while (ret == OK)
57797a4b8980SBram Moolenaar {
57807a4b8980SBram Moolenaar // When at the end of the line and ".name" or "->{" or "->X" follows in
57817a4b8980SBram Moolenaar // the next line then consume the line break.
57827a4b8980SBram Moolenaar p = eval_next_non_blank(*arg, evalarg, &getnext);
57837a4b8980SBram Moolenaar if (getnext
5784b13ab999SBram Moolenaar && ((rettv->v_type == VAR_DICT && *p == '.' && eval_isdictc(p[1]))
5785a733042bSBram Moolenaar || (p[0] == '-' && p[1] == '>' && (p[2] == '{'
5786a733042bSBram Moolenaar || ASCII_ISALPHA(in_vim9script() ? *skipwhite(p + 2)
5787a733042bSBram Moolenaar : p[2])))))
5788442af2f8SBram Moolenaar {
5789442af2f8SBram Moolenaar *arg = eval_next_line(evalarg);
5790aeb2bdd0SBram Moolenaar p = *arg;
5791442af2f8SBram Moolenaar check_white = FALSE;
5792442af2f8SBram Moolenaar }
57932a8d1f87SBram Moolenaar
5794cb4e80faSBram Moolenaar if (rettv->v_type == VAR_ANY)
5795cb4e80faSBram Moolenaar {
5796cb4e80faSBram Moolenaar char_u *exp_name;
5797cb4e80faSBram Moolenaar int cc;
5798cb4e80faSBram Moolenaar int idx;
5799cb4e80faSBram Moolenaar ufunc_T *ufunc;
5800cb4e80faSBram Moolenaar type_T *type;
5801cb4e80faSBram Moolenaar
5802cb4e80faSBram Moolenaar // Found script from "import * as {name}", script item name must
5803cb4e80faSBram Moolenaar // follow.
5804cb4e80faSBram Moolenaar if (**arg != '.')
5805cb4e80faSBram Moolenaar {
5806cb4e80faSBram Moolenaar if (verbose)
5807cb4e80faSBram Moolenaar semsg(_(e_expected_str_but_got_str), "'.'", *arg);
5808cb4e80faSBram Moolenaar ret = FAIL;
5809cb4e80faSBram Moolenaar break;
5810cb4e80faSBram Moolenaar }
5811cb4e80faSBram Moolenaar ++*arg;
5812cb4e80faSBram Moolenaar if (IS_WHITE_OR_NUL(**arg))
5813cb4e80faSBram Moolenaar {
5814cb4e80faSBram Moolenaar if (verbose)
5815cb4e80faSBram Moolenaar emsg(_(e_no_white_space_allowed_after_dot));
5816cb4e80faSBram Moolenaar ret = FAIL;
5817cb4e80faSBram Moolenaar break;
5818cb4e80faSBram Moolenaar }
5819cb4e80faSBram Moolenaar
5820cb4e80faSBram Moolenaar // isolate the name
5821cb4e80faSBram Moolenaar exp_name = *arg;
5822cb4e80faSBram Moolenaar while (eval_isnamec(**arg))
5823cb4e80faSBram Moolenaar ++*arg;
5824cb4e80faSBram Moolenaar cc = **arg;
5825cb4e80faSBram Moolenaar **arg = NUL;
5826cb4e80faSBram Moolenaar
5827cb4e80faSBram Moolenaar idx = find_exported(rettv->vval.v_number, exp_name, &ufunc, &type,
5828cb4e80faSBram Moolenaar evalarg->eval_cctx, verbose);
5829cb4e80faSBram Moolenaar **arg = cc;
5830cb4e80faSBram Moolenaar *arg = skipwhite(*arg);
5831cb4e80faSBram Moolenaar
5832cb4e80faSBram Moolenaar if (idx < 0 && ufunc == NULL)
5833cb4e80faSBram Moolenaar {
5834cb4e80faSBram Moolenaar ret = FAIL;
5835cb4e80faSBram Moolenaar break;
5836cb4e80faSBram Moolenaar }
5837cb4e80faSBram Moolenaar if (idx >= 0)
5838cb4e80faSBram Moolenaar {
5839cb4e80faSBram Moolenaar scriptitem_T *si = SCRIPT_ITEM(rettv->vval.v_number);
5840cb4e80faSBram Moolenaar svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
5841cb4e80faSBram Moolenaar
5842cb4e80faSBram Moolenaar copy_tv(sv->sv_tv, rettv);
5843cb4e80faSBram Moolenaar }
5844cb4e80faSBram Moolenaar else
5845cb4e80faSBram Moolenaar {
5846cb4e80faSBram Moolenaar rettv->v_type = VAR_FUNC;
5847cb4e80faSBram Moolenaar rettv->vval.v_string = vim_strsave(ufunc->uf_name);
5848cb4e80faSBram Moolenaar }
5849cb4e80faSBram Moolenaar }
5850cb4e80faSBram Moolenaar
58517a4b8980SBram Moolenaar if ((**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
58527a4b8980SBram Moolenaar || rettv->v_type == VAR_PARTIAL))
5853442af2f8SBram Moolenaar && (!check_white || !VIM_ISWHITE(*(*arg - 1))))
58542a8d1f87SBram Moolenaar {
5855e6b5324eSBram Moolenaar ret = call_func_rettv(arg, evalarg, rettv, evaluate,
5856e6b5324eSBram Moolenaar selfdict, NULL);
58573f242a84SBram Moolenaar
585822a0c0c4SBram Moolenaar // Stop the expression evaluation when immediately aborting on
585922a0c0c4SBram Moolenaar // error, or when an interrupt occurred or an exception was thrown
586022a0c0c4SBram Moolenaar // but not caught.
58612a8d1f87SBram Moolenaar if (aborting())
58622a8d1f87SBram Moolenaar {
58632a8d1f87SBram Moolenaar if (ret == OK)
58642a8d1f87SBram Moolenaar clear_tv(rettv);
58652a8d1f87SBram Moolenaar ret = FAIL;
58662a8d1f87SBram Moolenaar }
58672a8d1f87SBram Moolenaar dict_unref(selfdict);
58682a8d1f87SBram Moolenaar selfdict = NULL;
58692a8d1f87SBram Moolenaar }
58709d489566SBram Moolenaar else if (p[0] == '-' && p[1] == '>')
5871ac92e25aSBram Moolenaar {
58720820f4deSBram Moolenaar if (in_vim9script())
58737cebe8baSBram Moolenaar *arg = skipwhite(p + 2);
58740820f4deSBram Moolenaar else
58750820f4deSBram Moolenaar *arg = p + 2;
58769cfe8f6eSBram Moolenaar if (ret == OK)
58779cfe8f6eSBram Moolenaar {
58780820f4deSBram Moolenaar if (VIM_ISWHITE(**arg))
58790820f4deSBram Moolenaar {
58800820f4deSBram Moolenaar emsg(_(e_nowhitespace));
58810820f4deSBram Moolenaar ret = FAIL;
58820820f4deSBram Moolenaar }
58830820f4deSBram Moolenaar else if ((**arg == '{' && !in_vim9script()) || **arg == '(')
58842949cfdbSBram Moolenaar // expr->{lambda}() or expr->(lambda)()
5885e40fbc2cSBram Moolenaar ret = eval_lambda(arg, rettv, evalarg, verbose);
588622a0c0c4SBram Moolenaar else
588722a0c0c4SBram Moolenaar // expr->name()
5888e6b5324eSBram Moolenaar ret = eval_method(arg, rettv, evalarg, verbose);
5889ac92e25aSBram Moolenaar }
58909cfe8f6eSBram Moolenaar }
58917a4b8980SBram Moolenaar // "." is ".name" lookup when we found a dict or when evaluating and
58927a4b8980SBram Moolenaar // scriptversion is at least 2, where string concatenation is "..".
58937a4b8980SBram Moolenaar else if (**arg == '['
58947a4b8980SBram Moolenaar || (**arg == '.' && (rettv->v_type == VAR_DICT
58957a4b8980SBram Moolenaar || (!evaluate
58967a4b8980SBram Moolenaar && (*arg)[1] != '.'
5897dd9de50fSBram Moolenaar && !in_old_script(2)))))
58982a8d1f87SBram Moolenaar {
58992a8d1f87SBram Moolenaar dict_unref(selfdict);
59002a8d1f87SBram Moolenaar if (rettv->v_type == VAR_DICT)
59012a8d1f87SBram Moolenaar {
59022a8d1f87SBram Moolenaar selfdict = rettv->vval.v_dict;
59032a8d1f87SBram Moolenaar if (selfdict != NULL)
59042a8d1f87SBram Moolenaar ++selfdict->dv_refcount;
59052a8d1f87SBram Moolenaar }
59062a8d1f87SBram Moolenaar else
59072a8d1f87SBram Moolenaar selfdict = NULL;
5908e40fbc2cSBram Moolenaar if (eval_index(arg, rettv, evalarg, verbose) == FAIL)
59092a8d1f87SBram Moolenaar {
59102a8d1f87SBram Moolenaar clear_tv(rettv);
59112a8d1f87SBram Moolenaar ret = FAIL;
59122a8d1f87SBram Moolenaar }
59132a8d1f87SBram Moolenaar }
59147a4b8980SBram Moolenaar else
59157a4b8980SBram Moolenaar break;
59162a8d1f87SBram Moolenaar }
5917ab1fa395SBram Moolenaar
59185d18efecSBram Moolenaar // Turn "dict.Func" into a partial for "Func" bound to "dict".
59195d18efecSBram Moolenaar // Don't do this when "Func" is already a partial that was bound
59205d18efecSBram Moolenaar // explicitly (pt_auto is FALSE).
59211d429610SBram Moolenaar if (selfdict != NULL
59221d429610SBram Moolenaar && (rettv->v_type == VAR_FUNC
59231d429610SBram Moolenaar || (rettv->v_type == VAR_PARTIAL
59241d429610SBram Moolenaar && (rettv->vval.v_partial->pt_auto
59251d429610SBram Moolenaar || rettv->vval.v_partial->pt_dict == NULL))))
5926a9b579f3SBram Moolenaar selfdict = make_partial(selfdict, rettv);
5927ab1fa395SBram Moolenaar
59282a8d1f87SBram Moolenaar dict_unref(selfdict);
59292a8d1f87SBram Moolenaar return ret;
59302a8d1f87SBram Moolenaar }
59312a8d1f87SBram Moolenaar
59322a8d1f87SBram Moolenaar /*
5933e9a41264SBram Moolenaar * Make a copy of an item.
5934e9a41264SBram Moolenaar * Lists and Dictionaries are also copied. A deep copy if "deep" is set.
593581bf7083SBram Moolenaar * For deepcopy() "copyID" is zero for a full copy or the ID for when a
593681bf7083SBram Moolenaar * reference to an already copied list/dict can be used.
593781bf7083SBram Moolenaar * Returns FAIL or OK.
5938e9a41264SBram Moolenaar */
5939cd52459cSBram Moolenaar int
item_copy(typval_T * from,typval_T * to,int deep,int copyID)59407454a06eSBram Moolenaar item_copy(
59417454a06eSBram Moolenaar typval_T *from,
59427454a06eSBram Moolenaar typval_T *to,
59437454a06eSBram Moolenaar int deep,
59447454a06eSBram Moolenaar int copyID)
5945e9a41264SBram Moolenaar {
5946e9a41264SBram Moolenaar static int recurse = 0;
594781bf7083SBram Moolenaar int ret = OK;
5948e9a41264SBram Moolenaar
594933570924SBram Moolenaar if (recurse >= DICT_MAXNEST)
5950e9a41264SBram Moolenaar {
5951f9e3e09fSBram Moolenaar emsg(_("E698: variable nested too deep for making a copy"));
595281bf7083SBram Moolenaar return FAIL;
5953e9a41264SBram Moolenaar }
5954e9a41264SBram Moolenaar ++recurse;
5955e9a41264SBram Moolenaar
5956e9a41264SBram Moolenaar switch (from->v_type)
5957e9a41264SBram Moolenaar {
5958e9a41264SBram Moolenaar case VAR_NUMBER:
59598c8de839SBram Moolenaar case VAR_FLOAT:
5960e9a41264SBram Moolenaar case VAR_STRING:
5961e9a41264SBram Moolenaar case VAR_FUNC:
59621735bc98SBram Moolenaar case VAR_PARTIAL:
59639b4a15d5SBram Moolenaar case VAR_BOOL:
596415550007SBram Moolenaar case VAR_SPECIAL:
5965835dc636SBram Moolenaar case VAR_JOB:
59667707344dSBram Moolenaar case VAR_CHANNEL:
5967f18332fbSBram Moolenaar case VAR_INSTR:
5968e9a41264SBram Moolenaar copy_tv(from, to);
5969e9a41264SBram Moolenaar break;
5970e9a41264SBram Moolenaar case VAR_LIST:
5971e9a41264SBram Moolenaar to->v_type = VAR_LIST;
59722e6aff38SBram Moolenaar to->v_lock = 0;
597381bf7083SBram Moolenaar if (from->vval.v_list == NULL)
597481bf7083SBram Moolenaar to->vval.v_list = NULL;
597581bf7083SBram Moolenaar else if (copyID != 0 && from->vval.v_list->lv_copyID == copyID)
597681bf7083SBram Moolenaar {
59775d18efecSBram Moolenaar // use the copy made earlier
597881bf7083SBram Moolenaar to->vval.v_list = from->vval.v_list->lv_copylist;
597981bf7083SBram Moolenaar ++to->vval.v_list->lv_refcount;
598081bf7083SBram Moolenaar }
598181bf7083SBram Moolenaar else
598281bf7083SBram Moolenaar to->vval.v_list = list_copy(from->vval.v_list, deep, copyID);
598381bf7083SBram Moolenaar if (to->vval.v_list == NULL)
598481bf7083SBram Moolenaar ret = FAIL;
5985e9a41264SBram Moolenaar break;
59863d28b58cSBram Moolenaar case VAR_BLOB:
59878a7d6542SBram Moolenaar ret = blob_copy(from->vval.v_blob, to);
59883d28b58cSBram Moolenaar break;
5989e9a41264SBram Moolenaar case VAR_DICT:
5990e9a41264SBram Moolenaar to->v_type = VAR_DICT;
59912e6aff38SBram Moolenaar to->v_lock = 0;
599281bf7083SBram Moolenaar if (from->vval.v_dict == NULL)
599381bf7083SBram Moolenaar to->vval.v_dict = NULL;
599481bf7083SBram Moolenaar else if (copyID != 0 && from->vval.v_dict->dv_copyID == copyID)
599581bf7083SBram Moolenaar {
59965d18efecSBram Moolenaar // use the copy made earlier
599781bf7083SBram Moolenaar to->vval.v_dict = from->vval.v_dict->dv_copydict;
599881bf7083SBram Moolenaar ++to->vval.v_dict->dv_refcount;
599981bf7083SBram Moolenaar }
600081bf7083SBram Moolenaar else
600181bf7083SBram Moolenaar to->vval.v_dict = dict_copy(from->vval.v_dict, deep, copyID);
600281bf7083SBram Moolenaar if (to->vval.v_dict == NULL)
600381bf7083SBram Moolenaar ret = FAIL;
6004e9a41264SBram Moolenaar break;
6005a03f2335SBram Moolenaar case VAR_UNKNOWN:
60064c683750SBram Moolenaar case VAR_ANY:
60078a7d6542SBram Moolenaar case VAR_VOID:
6008dd58923cSBram Moolenaar internal_error_no_abort("item_copy(UNKNOWN)");
600981bf7083SBram Moolenaar ret = FAIL;
6010e9a41264SBram Moolenaar }
6011e9a41264SBram Moolenaar --recurse;
601281bf7083SBram Moolenaar return ret;
6013e9a41264SBram Moolenaar }
6014e9a41264SBram Moolenaar
60158a7d6542SBram Moolenaar void
echo_one(typval_T * rettv,int with_space,int * atstart,int * needclr)60168a7d6542SBram Moolenaar echo_one(typval_T *rettv, int with_space, int *atstart, int *needclr)
60178a7d6542SBram Moolenaar {
60188a7d6542SBram Moolenaar char_u *tofree;
60198a7d6542SBram Moolenaar char_u numbuf[NUMBUFLEN];
60208a7d6542SBram Moolenaar char_u *p = echo_string(rettv, &tofree, numbuf, get_copyID());
60218a7d6542SBram Moolenaar
60228a7d6542SBram Moolenaar if (*atstart)
60238a7d6542SBram Moolenaar {
60248a7d6542SBram Moolenaar *atstart = FALSE;
60258a7d6542SBram Moolenaar // Call msg_start() after eval1(), evaluating the expression
60268a7d6542SBram Moolenaar // may cause a message to appear.
60278a7d6542SBram Moolenaar if (with_space)
60288a7d6542SBram Moolenaar {
60298a7d6542SBram Moolenaar // Mark the saved text as finishing the line, so that what
60308a7d6542SBram Moolenaar // follows is displayed on a new line when scrolling back
60318a7d6542SBram Moolenaar // at the more prompt.
60328a7d6542SBram Moolenaar msg_sb_eol();
60338a7d6542SBram Moolenaar msg_start();
60348a7d6542SBram Moolenaar }
60358a7d6542SBram Moolenaar }
60368a7d6542SBram Moolenaar else if (with_space)
60378a7d6542SBram Moolenaar msg_puts_attr(" ", echo_attr);
60388a7d6542SBram Moolenaar
60398a7d6542SBram Moolenaar if (p != NULL)
60408a7d6542SBram Moolenaar for ( ; *p != NUL && !got_int; ++p)
60418a7d6542SBram Moolenaar {
60428a7d6542SBram Moolenaar if (*p == '\n' || *p == '\r' || *p == TAB)
60438a7d6542SBram Moolenaar {
60448a7d6542SBram Moolenaar if (*p != TAB && *needclr)
60458a7d6542SBram Moolenaar {
60468a7d6542SBram Moolenaar // remove any text still there from the command
60478a7d6542SBram Moolenaar msg_clr_eos();
60488a7d6542SBram Moolenaar *needclr = FALSE;
60498a7d6542SBram Moolenaar }
60508a7d6542SBram Moolenaar msg_putchar_attr(*p, echo_attr);
60518a7d6542SBram Moolenaar }
60528a7d6542SBram Moolenaar else
60538a7d6542SBram Moolenaar {
60548a7d6542SBram Moolenaar if (has_mbyte)
60558a7d6542SBram Moolenaar {
60568a7d6542SBram Moolenaar int i = (*mb_ptr2len)(p);
60578a7d6542SBram Moolenaar
60588a7d6542SBram Moolenaar (void)msg_outtrans_len_attr(p, i, echo_attr);
60598a7d6542SBram Moolenaar p += i - 1;
60608a7d6542SBram Moolenaar }
60618a7d6542SBram Moolenaar else
60628a7d6542SBram Moolenaar (void)msg_outtrans_len_attr(p, 1, echo_attr);
60638a7d6542SBram Moolenaar }
60648a7d6542SBram Moolenaar }
60658a7d6542SBram Moolenaar vim_free(tofree);
60668a7d6542SBram Moolenaar }
60678a7d6542SBram Moolenaar
6068e9a41264SBram Moolenaar /*
6069071d4279SBram Moolenaar * ":echo expr1 ..." print each argument separated with a space, add a
6070071d4279SBram Moolenaar * newline at the end.
6071071d4279SBram Moolenaar * ":echon expr1 ..." print each argument plain.
6072071d4279SBram Moolenaar */
6073071d4279SBram Moolenaar void
ex_echo(exarg_T * eap)60747454a06eSBram Moolenaar ex_echo(exarg_T *eap)
6075071d4279SBram Moolenaar {
6076071d4279SBram Moolenaar char_u *arg = eap->arg;
607733570924SBram Moolenaar typval_T rettv;
607868db996bSBram Moolenaar char_u *arg_start;
6079071d4279SBram Moolenaar int needclr = TRUE;
6080071d4279SBram Moolenaar int atstart = TRUE;
608176a63454SBram Moolenaar int did_emsg_before = did_emsg;
6082c0f5a78cSBram Moolenaar int called_emsg_before = called_emsg;
60835409f5d8SBram Moolenaar evalarg_T evalarg;
60845409f5d8SBram Moolenaar
6085e707c882SBram Moolenaar fill_evalarg_from_eap(&evalarg, eap, eap->skip);
6086071d4279SBram Moolenaar
6087071d4279SBram Moolenaar if (eap->skip)
6088071d4279SBram Moolenaar ++emsg_skip;
60897a092245SBram Moolenaar while ((!ends_excmd2(eap->cmd, arg) || *arg == '"') && !got_int)
6090071d4279SBram Moolenaar {
60915d18efecSBram Moolenaar // If eval1() causes an error message the text from the command may
60925d18efecSBram Moolenaar // still need to be cleared. E.g., "echo 22,44".
60938c8de839SBram Moolenaar need_clr_eos = needclr;
60948c8de839SBram Moolenaar
609568db996bSBram Moolenaar arg_start = arg;
60965409f5d8SBram Moolenaar if (eval1(&arg, &rettv, &evalarg) == FAIL)
6097071d4279SBram Moolenaar {
6098071d4279SBram Moolenaar /*
6099071d4279SBram Moolenaar * Report the invalid expression unless the expression evaluation
6100071d4279SBram Moolenaar * has been cancelled due to an aborting error, an interrupt, or an
6101071d4279SBram Moolenaar * exception.
6102071d4279SBram Moolenaar */
6103c0f5a78cSBram Moolenaar if (!aborting() && did_emsg == did_emsg_before
6104c0f5a78cSBram Moolenaar && called_emsg == called_emsg_before)
6105108010aaSBram Moolenaar semsg(_(e_invalid_expression_str), arg_start);
61068c8de839SBram Moolenaar need_clr_eos = FALSE;
6107071d4279SBram Moolenaar break;
6108071d4279SBram Moolenaar }
61098c8de839SBram Moolenaar need_clr_eos = FALSE;
61108c8de839SBram Moolenaar
6111071d4279SBram Moolenaar if (!eap->skip)
611268db996bSBram Moolenaar {
611368db996bSBram Moolenaar if (rettv.v_type == VAR_VOID)
611468db996bSBram Moolenaar {
611568db996bSBram Moolenaar semsg(_(e_expression_does_not_result_in_value_str), arg_start);
611668db996bSBram Moolenaar break;
611768db996bSBram Moolenaar }
61188a7d6542SBram Moolenaar echo_one(&rettv, eap->cmdidx == CMD_echo, &atstart, &needclr);
611968db996bSBram Moolenaar }
6120071d4279SBram Moolenaar
6121c70646c6SBram Moolenaar clear_tv(&rettv);
6122071d4279SBram Moolenaar arg = skipwhite(arg);
6123071d4279SBram Moolenaar }
612463b91736SBram Moolenaar set_nextcmd(eap, arg);
6125faf8626bSBram Moolenaar clear_evalarg(&evalarg, eap);
6126071d4279SBram Moolenaar
6127071d4279SBram Moolenaar if (eap->skip)
6128071d4279SBram Moolenaar --emsg_skip;
6129071d4279SBram Moolenaar else
6130071d4279SBram Moolenaar {
61315d18efecSBram Moolenaar // remove text that may still be there from the command
6132071d4279SBram Moolenaar if (needclr)
6133071d4279SBram Moolenaar msg_clr_eos();
6134071d4279SBram Moolenaar if (eap->cmdidx == CMD_echo)
6135071d4279SBram Moolenaar msg_end();
6136071d4279SBram Moolenaar }
6137071d4279SBram Moolenaar }
6138071d4279SBram Moolenaar
6139071d4279SBram Moolenaar /*
6140071d4279SBram Moolenaar * ":echohl {name}".
6141071d4279SBram Moolenaar */
6142071d4279SBram Moolenaar void
ex_echohl(exarg_T * eap)61437454a06eSBram Moolenaar ex_echohl(exarg_T *eap)
6144071d4279SBram Moolenaar {
61451b9645deSBram Moolenaar echo_attr = syn_name2attr(eap->arg);
6146071d4279SBram Moolenaar }
6147071d4279SBram Moolenaar
6148071d4279SBram Moolenaar /*
6149da6c0334SBram Moolenaar * Returns the :echo attribute
6150da6c0334SBram Moolenaar */
6151da6c0334SBram Moolenaar int
get_echo_attr(void)6152da6c0334SBram Moolenaar get_echo_attr(void)
6153da6c0334SBram Moolenaar {
6154da6c0334SBram Moolenaar return echo_attr;
6155da6c0334SBram Moolenaar }
6156da6c0334SBram Moolenaar
6157da6c0334SBram Moolenaar /*
6158071d4279SBram Moolenaar * ":execute expr1 ..." execute the result of an expression.
6159071d4279SBram Moolenaar * ":echomsg expr1 ..." Print a message
6160071d4279SBram Moolenaar * ":echoerr expr1 ..." Print an error
61614c86830fSBram Moolenaar * ":echoconsole expr1 ..." Print a message on stdout
6162071d4279SBram Moolenaar * Each gets spaces around each argument and a newline at the end for
6163071d4279SBram Moolenaar * echo commands
6164071d4279SBram Moolenaar */
6165071d4279SBram Moolenaar void
ex_execute(exarg_T * eap)61667454a06eSBram Moolenaar ex_execute(exarg_T *eap)
6167071d4279SBram Moolenaar {
6168071d4279SBram Moolenaar char_u *arg = eap->arg;
616933570924SBram Moolenaar typval_T rettv;
6170071d4279SBram Moolenaar int ret = OK;
6171071d4279SBram Moolenaar char_u *p;
6172071d4279SBram Moolenaar garray_T ga;
6173071d4279SBram Moolenaar int len;
6174c03fe66aSBram Moolenaar long start_lnum = SOURCING_LNUM;
6175071d4279SBram Moolenaar
6176071d4279SBram Moolenaar ga_init2(&ga, 1, 80);
6177071d4279SBram Moolenaar
6178071d4279SBram Moolenaar if (eap->skip)
6179071d4279SBram Moolenaar ++emsg_skip;
61804a8d9f2eSBram Moolenaar while (!ends_excmd2(eap->cmd, arg) || *arg == '"')
6181071d4279SBram Moolenaar {
618247e880d6SBram Moolenaar ret = eval1_emsg(&arg, &rettv, eap);
6183ce9d50dfSBram Moolenaar if (ret == FAIL)
6184071d4279SBram Moolenaar break;
6185071d4279SBram Moolenaar
6186071d4279SBram Moolenaar if (!eap->skip)
6187071d4279SBram Moolenaar {
6188461a7fcfSBram Moolenaar char_u buf[NUMBUFLEN];
6189461a7fcfSBram Moolenaar
6190461a7fcfSBram Moolenaar if (eap->cmdidx == CMD_execute)
6191b662591eSBram Moolenaar {
6192b662591eSBram Moolenaar if (rettv.v_type == VAR_CHANNEL || rettv.v_type == VAR_JOB)
6193b662591eSBram Moolenaar {
619468db996bSBram Moolenaar semsg(_(e_using_invalid_value_as_string_str),
619568db996bSBram Moolenaar vartype_name(rettv.v_type));
6196b662591eSBram Moolenaar p = NULL;
6197b662591eSBram Moolenaar }
6198b662591eSBram Moolenaar else
6199461a7fcfSBram Moolenaar p = tv_get_string_buf(&rettv, buf);
6200b662591eSBram Moolenaar }
6201461a7fcfSBram Moolenaar else
6202461a7fcfSBram Moolenaar p = tv_stringify(&rettv, buf);
62039db2afe4SBram Moolenaar if (p == NULL)
62049db2afe4SBram Moolenaar {
62059db2afe4SBram Moolenaar clear_tv(&rettv);
62069db2afe4SBram Moolenaar ret = FAIL;
62079db2afe4SBram Moolenaar break;
62089db2afe4SBram Moolenaar }
6209071d4279SBram Moolenaar len = (int)STRLEN(p);
6210071d4279SBram Moolenaar if (ga_grow(&ga, len + 2) == FAIL)
6211071d4279SBram Moolenaar {
6212c70646c6SBram Moolenaar clear_tv(&rettv);
6213071d4279SBram Moolenaar ret = FAIL;
6214071d4279SBram Moolenaar break;
6215071d4279SBram Moolenaar }
6216071d4279SBram Moolenaar if (ga.ga_len)
6217071d4279SBram Moolenaar ((char_u *)(ga.ga_data))[ga.ga_len++] = ' ';
6218071d4279SBram Moolenaar STRCPY((char_u *)(ga.ga_data) + ga.ga_len, p);
6219071d4279SBram Moolenaar ga.ga_len += len;
6220071d4279SBram Moolenaar }
6221071d4279SBram Moolenaar
6222c70646c6SBram Moolenaar clear_tv(&rettv);
6223071d4279SBram Moolenaar arg = skipwhite(arg);
6224071d4279SBram Moolenaar }
6225071d4279SBram Moolenaar
6226071d4279SBram Moolenaar if (ret != FAIL && ga.ga_data != NULL)
6227071d4279SBram Moolenaar {
6228c03fe66aSBram Moolenaar // use the first line of continuation lines for messages
6229c03fe66aSBram Moolenaar SOURCING_LNUM = start_lnum;
6230c03fe66aSBram Moolenaar
623157002ad7SBram Moolenaar if (eap->cmdidx == CMD_echomsg || eap->cmdidx == CMD_echoerr)
623257002ad7SBram Moolenaar {
62335d18efecSBram Moolenaar // Mark the already saved text as finishing the line, so that what
62345d18efecSBram Moolenaar // follows is displayed on a new line when scrolling back at the
62355d18efecSBram Moolenaar // more prompt.
623657002ad7SBram Moolenaar msg_sb_eol();
623757002ad7SBram Moolenaar }
623857002ad7SBram Moolenaar
6239071d4279SBram Moolenaar if (eap->cmdidx == CMD_echomsg)
62404770d09aSBram Moolenaar {
624132526b3cSBram Moolenaar msg_attr(ga.ga_data, echo_attr);
62424770d09aSBram Moolenaar out_flush();
62434770d09aSBram Moolenaar }
62444c86830fSBram Moolenaar else if (eap->cmdidx == CMD_echoconsole)
62454c86830fSBram Moolenaar {
62464c86830fSBram Moolenaar ui_write(ga.ga_data, (int)STRLEN(ga.ga_data), TRUE);
62474c86830fSBram Moolenaar ui_write((char_u *)"\r\n", 2, TRUE);
62484c86830fSBram Moolenaar }
6249071d4279SBram Moolenaar else if (eap->cmdidx == CMD_echoerr)
6250071d4279SBram Moolenaar {
6251f93c7feaSBram Moolenaar int save_did_emsg = did_emsg;
6252f93c7feaSBram Moolenaar
62535d18efecSBram Moolenaar // We don't want to abort following commands, restore did_emsg.
6254f9e3e09fSBram Moolenaar emsg(ga.ga_data);
6255071d4279SBram Moolenaar if (!force_abort)
6256071d4279SBram Moolenaar did_emsg = save_did_emsg;
6257071d4279SBram Moolenaar }
6258071d4279SBram Moolenaar else if (eap->cmdidx == CMD_execute)
6259071d4279SBram Moolenaar do_cmdline((char_u *)ga.ga_data,
6260071d4279SBram Moolenaar eap->getline, eap->cookie, DOCMD_NOWAIT|DOCMD_VERBOSE);
6261071d4279SBram Moolenaar }
6262071d4279SBram Moolenaar
6263071d4279SBram Moolenaar ga_clear(&ga);
6264071d4279SBram Moolenaar
6265071d4279SBram Moolenaar if (eap->skip)
6266071d4279SBram Moolenaar --emsg_skip;
6267071d4279SBram Moolenaar
626863b91736SBram Moolenaar set_nextcmd(eap, arg);
6269071d4279SBram Moolenaar }
6270071d4279SBram Moolenaar
6271071d4279SBram Moolenaar /*
6272071d4279SBram Moolenaar * Skip over the name of an option: "&option", "&g:option" or "&l:option".
6273071d4279SBram Moolenaar * "arg" points to the "&" or '+' when called, to "option" when returning.
6274071d4279SBram Moolenaar * Returns NULL when no option name found. Otherwise pointer to the char
6275071d4279SBram Moolenaar * after the option name.
6276071d4279SBram Moolenaar */
62770522ba03SBram Moolenaar char_u *
find_option_end(char_u ** arg,int * opt_flags)62787454a06eSBram Moolenaar find_option_end(char_u **arg, int *opt_flags)
6279071d4279SBram Moolenaar {
6280071d4279SBram Moolenaar char_u *p = *arg;
6281071d4279SBram Moolenaar
6282071d4279SBram Moolenaar ++p;
6283071d4279SBram Moolenaar if (*p == 'g' && p[1] == ':')
6284071d4279SBram Moolenaar {
6285071d4279SBram Moolenaar *opt_flags = OPT_GLOBAL;
6286071d4279SBram Moolenaar p += 2;
6287071d4279SBram Moolenaar }
6288071d4279SBram Moolenaar else if (*p == 'l' && p[1] == ':')
6289071d4279SBram Moolenaar {
6290071d4279SBram Moolenaar *opt_flags = OPT_LOCAL;
6291071d4279SBram Moolenaar p += 2;
6292071d4279SBram Moolenaar }
6293071d4279SBram Moolenaar else
6294071d4279SBram Moolenaar *opt_flags = 0;
6295071d4279SBram Moolenaar
6296071d4279SBram Moolenaar if (!ASCII_ISALPHA(*p))
6297071d4279SBram Moolenaar return NULL;
6298071d4279SBram Moolenaar *arg = p;
6299071d4279SBram Moolenaar
6300071d4279SBram Moolenaar if (p[0] == 't' && p[1] == '_' && p[2] != NUL && p[3] != NUL)
63015d18efecSBram Moolenaar p += 4; // termcap option
6302071d4279SBram Moolenaar else
6303071d4279SBram Moolenaar while (ASCII_ISALPHA(*p))
6304071d4279SBram Moolenaar ++p;
6305071d4279SBram Moolenaar return p;
6306071d4279SBram Moolenaar }
6307071d4279SBram Moolenaar
6308071d4279SBram Moolenaar /*
6309661b1820SBram Moolenaar * Display script name where an item was last set.
6310661b1820SBram Moolenaar * Should only be invoked when 'verbose' is non-zero.
6311661b1820SBram Moolenaar */
6312661b1820SBram Moolenaar void
last_set_msg(sctx_T script_ctx)6313f29c1c6aSBram Moolenaar last_set_msg(sctx_T script_ctx)
6314661b1820SBram Moolenaar {
6315cafda4f8SBram Moolenaar char_u *p;
6316cafda4f8SBram Moolenaar
6317f29c1c6aSBram Moolenaar if (script_ctx.sc_sid != 0)
6318661b1820SBram Moolenaar {
6319f29c1c6aSBram Moolenaar p = home_replace_save(NULL, get_scriptname(script_ctx.sc_sid));
6320cafda4f8SBram Moolenaar if (p != NULL)
6321cafda4f8SBram Moolenaar {
6322661b1820SBram Moolenaar verbose_enter();
632332526b3cSBram Moolenaar msg_puts(_("\n\tLast set from "));
632432526b3cSBram Moolenaar msg_puts((char *)p);
6325f29c1c6aSBram Moolenaar if (script_ctx.sc_lnum > 0)
6326f29c1c6aSBram Moolenaar {
632764e74c9cSBram Moolenaar msg_puts(_(line_msg));
6328f29c1c6aSBram Moolenaar msg_outnum((long)script_ctx.sc_lnum);
6329f29c1c6aSBram Moolenaar }
6330661b1820SBram Moolenaar verbose_leave();
6331f29c1c6aSBram Moolenaar vim_free(p);
6332661b1820SBram Moolenaar }
6333661b1820SBram Moolenaar }
6334cafda4f8SBram Moolenaar }
6335661b1820SBram Moolenaar
6336b005cd80SBram Moolenaar #endif // FEAT_EVAL
6337071d4279SBram Moolenaar
6338071d4279SBram Moolenaar /*
6339071d4279SBram Moolenaar * Perform a substitution on "str" with pattern "pat" and substitute "sub".
634072ab729cSBram Moolenaar * When "sub" is NULL "expr" is used, must be a VAR_FUNC or VAR_PARTIAL.
6341071d4279SBram Moolenaar * "flags" can be "g" to do a global substitute.
6342071d4279SBram Moolenaar * Returns an allocated string, NULL for error.
6343071d4279SBram Moolenaar */
6344071d4279SBram Moolenaar char_u *
do_string_sub(char_u * str,char_u * pat,char_u * sub,typval_T * expr,char_u * flags)63457454a06eSBram Moolenaar do_string_sub(
63467454a06eSBram Moolenaar char_u *str,
63477454a06eSBram Moolenaar char_u *pat,
63487454a06eSBram Moolenaar char_u *sub,
634972ab729cSBram Moolenaar typval_T *expr,
63507454a06eSBram Moolenaar char_u *flags)
6351071d4279SBram Moolenaar {
6352071d4279SBram Moolenaar int sublen;
6353071d4279SBram Moolenaar regmatch_T regmatch;
6354071d4279SBram Moolenaar int i;
6355071d4279SBram Moolenaar int do_all;
6356071d4279SBram Moolenaar char_u *tail;
6357e90c853fSBram Moolenaar char_u *end;
6358071d4279SBram Moolenaar garray_T ga;
6359071d4279SBram Moolenaar char_u *ret;
6360071d4279SBram Moolenaar char_u *save_cpo;
63618af26918SBram Moolenaar char_u *zero_width = NULL;
6362071d4279SBram Moolenaar
63635d18efecSBram Moolenaar // Make 'cpoptions' empty, so that the 'l' flag doesn't work here
6364071d4279SBram Moolenaar save_cpo = p_cpo;
63659c24ccc7SBram Moolenaar p_cpo = empty_option;
6366071d4279SBram Moolenaar
6367071d4279SBram Moolenaar ga_init2(&ga, 1, 200);
6368071d4279SBram Moolenaar
6369071d4279SBram Moolenaar do_all = (flags[0] == 'g');
6370071d4279SBram Moolenaar
6371071d4279SBram Moolenaar regmatch.rm_ic = p_ic;
6372071d4279SBram Moolenaar regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6373071d4279SBram Moolenaar if (regmatch.regprog != NULL)
6374071d4279SBram Moolenaar {
6375071d4279SBram Moolenaar tail = str;
6376e90c853fSBram Moolenaar end = str + STRLEN(str);
6377071d4279SBram Moolenaar while (vim_regexec_nl(®match, str, (colnr_T)(tail - str)))
6378071d4279SBram Moolenaar {
63795d18efecSBram Moolenaar // Skip empty match except for first match.
63808af26918SBram Moolenaar if (regmatch.startp[0] == regmatch.endp[0])
63818af26918SBram Moolenaar {
63828af26918SBram Moolenaar if (zero_width == regmatch.startp[0])
63838af26918SBram Moolenaar {
63845d18efecSBram Moolenaar // avoid getting stuck on a match with an empty string
63851614a149SBram Moolenaar i = mb_ptr2len(tail);
63868e7048caSBram Moolenaar mch_memmove((char_u *)ga.ga_data + ga.ga_len, tail,
63878e7048caSBram Moolenaar (size_t)i);
63888e7048caSBram Moolenaar ga.ga_len += i;
63898e7048caSBram Moolenaar tail += i;
63908af26918SBram Moolenaar continue;
63918af26918SBram Moolenaar }
63928af26918SBram Moolenaar zero_width = regmatch.startp[0];
63938af26918SBram Moolenaar }
63948af26918SBram Moolenaar
6395071d4279SBram Moolenaar /*
6396071d4279SBram Moolenaar * Get some space for a temporary buffer to do the substitution
6397071d4279SBram Moolenaar * into. It will contain:
6398071d4279SBram Moolenaar * - The text up to where the match is.
6399071d4279SBram Moolenaar * - The substituted text.
6400071d4279SBram Moolenaar * - The text after the match.
6401071d4279SBram Moolenaar */
640272ab729cSBram Moolenaar sublen = vim_regsub(®match, sub, expr, tail, FALSE, TRUE, FALSE);
6403e90c853fSBram Moolenaar if (ga_grow(&ga, (int)((end - tail) + sublen -
6404071d4279SBram Moolenaar (regmatch.endp[0] - regmatch.startp[0]))) == FAIL)
6405071d4279SBram Moolenaar {
6406071d4279SBram Moolenaar ga_clear(&ga);
6407071d4279SBram Moolenaar break;
6408071d4279SBram Moolenaar }
6409071d4279SBram Moolenaar
64105d18efecSBram Moolenaar // copy the text up to where the match is
6411071d4279SBram Moolenaar i = (int)(regmatch.startp[0] - tail);
6412071d4279SBram Moolenaar mch_memmove((char_u *)ga.ga_data + ga.ga_len, tail, (size_t)i);
64135d18efecSBram Moolenaar // add the substituted text
641472ab729cSBram Moolenaar (void)vim_regsub(®match, sub, expr, (char_u *)ga.ga_data
6415071d4279SBram Moolenaar + ga.ga_len + i, TRUE, TRUE, FALSE);
6416071d4279SBram Moolenaar ga.ga_len += i + sublen - 1;
6417071d4279SBram Moolenaar tail = regmatch.endp[0];
6418071d4279SBram Moolenaar if (*tail == NUL)
6419071d4279SBram Moolenaar break;
6420071d4279SBram Moolenaar if (!do_all)
6421071d4279SBram Moolenaar break;
6422071d4279SBram Moolenaar }
6423071d4279SBram Moolenaar
6424071d4279SBram Moolenaar if (ga.ga_data != NULL)
6425071d4279SBram Moolenaar STRCPY((char *)ga.ga_data + ga.ga_len, tail);
6426071d4279SBram Moolenaar
6427473de61bSBram Moolenaar vim_regfree(regmatch.regprog);
6428071d4279SBram Moolenaar }
6429071d4279SBram Moolenaar
6430071d4279SBram Moolenaar ret = vim_strsave(ga.ga_data == NULL ? str : (char_u *)ga.ga_data);
6431071d4279SBram Moolenaar ga_clear(&ga);
64329c24ccc7SBram Moolenaar if (p_cpo == empty_option)
6433071d4279SBram Moolenaar p_cpo = save_cpo;
64349c24ccc7SBram Moolenaar else
6435e5a2dc87SBram Moolenaar {
64365d18efecSBram Moolenaar // Darn, evaluating {sub} expression or {expr} changed the value.
6437e5a2dc87SBram Moolenaar // If it's still empty it was changed and restored, need to restore in
6438e5a2dc87SBram Moolenaar // the complicated way.
6439e5a2dc87SBram Moolenaar if (*p_cpo == NUL)
6440e5a2dc87SBram Moolenaar set_option_value((char_u *)"cpo", 0L, save_cpo, 0);
64419c24ccc7SBram Moolenaar free_string_option(save_cpo);
6442e5a2dc87SBram Moolenaar }
6443071d4279SBram Moolenaar
6444071d4279SBram Moolenaar return ret;
6445071d4279SBram Moolenaar }
6446