xref: /vim-8.2.3635/src/eval.c (revision 844fb64a)
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(&regmatch, 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(&regmatch, 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(&regmatch, 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(&regmatch, 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