Patch 8.2.1047

6 views
Skip to first unread message

Bram Moolenaar

unread,
Jun 24, 2020, 12:38:26 PM6/24/20
to vim...@googlegroups.com

Patch 8.2.1047
Problem: Vim9: script cannot use line continuation like in a :def function.
Solution: Pass the getline function pointer to the eval() functions. Use it
for addition and multiplication operators.
Files: src/vim.h, src/structs.h, src/globals.h, src/ex_eval.c,
src/eval.c, src/proto/eval.pro, src/dict.c, src/evalfunc.c,
src/evalvars.c, src/list.c, src/userfunc.c, src/scriptfile.c,
src/proto/scriptfile.pro, src/testdir/test_vim9_expr.vim


*** ../vim-8.2.1046/src/vim.h 2020-06-16 20:03:38.747351038 +0200
--- src/vim.h 2020-06-24 14:30:33.494935506 +0200
***************
*** 2665,2674 ****
#define REPTERM_SPECIAL 4
#define REPTERM_NO_SIMPLIFY 8

- // Flags for expression evaluation.
- #define EVAL_EVALUATE 1 // when missing don't actually evaluate
- #define EVAL_CONSTANT 2 // when not a constant return FAIL
-
// Flags for find_special_key()
#define FSK_KEYCODE 0x01 // prefer key code, e.g. K_DEL instead of DEL
#define FSK_KEEP_X_KEY 0x02 // don't translate xHome to Home key
--- 2665,2670 ----
*** ../vim-8.2.1046/src/structs.h 2020-06-20 22:50:44.171608245 +0200
--- src/structs.h 2020-06-24 15:30:16.345482478 +0200
***************
*** 1746,1751 ****
--- 1746,1764 ----
# endif
} scriptitem_T;

+ // Struct passed through eval() functions.
+ // See EVALARG_EVALUATE for a fixed value with eval_flags set to EVAL_EVALUATE.
+ typedef struct {
+ int eval_flags; // EVAL_ flag values below
+
+ // copied from exarg_T when "getline" is "getsourceline". Can be NULL.
+ void *eval_cookie; // argument for getline()
+ } evalarg_T;
+
+ // Flags for expression evaluation.
+ #define EVAL_EVALUATE 1 // when missing don't actually evaluate
+ #define EVAL_CONSTANT 2 // when not a constant return FAIL
+
# ifdef FEAT_PROFILE
/*
* Struct used in sn_prl_ga for every line of a script.
*** ../vim-8.2.1046/src/globals.h 2020-06-22 23:02:14.773942551 +0200
--- src/globals.h 2020-06-24 15:16:42.863873556 +0200
***************
*** 1880,1885 ****
--- 1880,1888 ----

// Used for lv_first in a non-materialized range() list.
EXTERN listitem_T range_list_item;
+
+ // Passed to an eval() function to enable evaluation.
+ EXTERN evalarg_T EVALARG_EVALUATE INIT2(EVAL_EVALUATE, NULL);
#endif

#ifdef MSWIN
*** ../vim-8.2.1046/src/ex_eval.c 2020-06-12 22:59:07.262097216 +0200
--- src/ex_eval.c 2020-06-24 17:47:15.224988598 +0200
***************
*** 895,903 ****
ex_eval(exarg_T *eap)
{
typval_T tv;

! if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE)
! == OK)
clear_tv(&tv);
}

--- 895,906 ----
ex_eval(exarg_T *eap)
{
typval_T tv;
+ evalarg_T evalarg;

! evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
! evalarg.eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL;
!
! if (eval0(eap->arg, &tv, &eap->nextcmd, &evalarg) == OK)
clear_tv(&tv);
}

*** ../vim-8.2.1046/src/eval.c 2020-06-20 18:19:05.920877872 +0200
--- src/eval.c 2020-06-24 18:26:27.453643950 +0200
***************
*** 45,56 ****
} forinfo_T;

static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op);
! static int eval2(char_u **arg, typval_T *rettv, int flags);
! static int eval3(char_u **arg, typval_T *rettv, int flags);
! static int eval4(char_u **arg, typval_T *rettv, int flags);
! static int eval5(char_u **arg, typval_T *rettv, int flags);
! static int eval6(char_u **arg, typval_T *rettv, int flags, int want_string);
! static int eval7(char_u **arg, typval_T *rettv, int flags, int want_string);
static int eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp);

static int free_unref_items(int copyID);
--- 45,56 ----
} forinfo_T;

static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op);
! static int eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
! static int eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
! static int eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
! static int eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
! static int eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
! static int eval7(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
static int eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp);

static int free_unref_items(int copyID);
***************
*** 169,175 ****

if (skip)
++emsg_skip;
! if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL)
*error = TRUE;
else
{
--- 169,175 ----

if (skip)
++emsg_skip;
! if (eval0(arg, &tv, nextcmd, skip ? NULL : &EVALARG_EVALUATE) == FAIL)
*error = TRUE;
else
{
***************
*** 197,203 ****
int did_emsg_before = did_emsg;
int called_emsg_before = called_emsg;

! ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0);
if (ret == FAIL)
{
// Report the invalid expression unless the expression evaluation has
--- 197,203 ----
int did_emsg_before = did_emsg;
int called_emsg_before = called_emsg;

! ret = eval1(arg, rettv, evaluate ? &EVALARG_EVALUATE : NULL);
if (ret == FAIL)
{
// Report the invalid expression unless the expression evaluation has
***************
*** 325,331 ****

if (skip)
++emsg_skip;
! if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip)
retval = NULL;
else
{
--- 325,332 ----

if (skip)
++emsg_skip;
! if (eval0(arg, &tv, nextcmd, skip ? NULL : &EVALARG_EVALUATE)
! == FAIL || skip)
retval = NULL;
else
{
***************
*** 348,354 ****
typval_T rettv;

*pp = skipwhite(*pp);
! return eval1(pp, &rettv, 0);
}

/*
--- 349,355 ----
typval_T rettv;

*pp = skipwhite(*pp);
! return eval1(pp, &rettv, NULL);
}

/*
***************
*** 370,376 ****
char_u numbuf[NUMBUFLEN];
#endif

! if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL)
retval = NULL;
else
{
--- 371,377 ----
char_u numbuf[NUMBUFLEN];
#endif

! if (eval0(arg, &tv, nextcmd, &EVALARG_EVALUATE) == FAIL)
retval = NULL;
else
{
***************
*** 440,446 ****

++emsg_off;

! if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL)
retval = -1;
else
{
--- 441,447 ----

++emsg_off;

! if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL)
retval = -1;
else
{
***************
*** 463,469 ****
typval_T *tv;

tv = ALLOC_ONE(typval_T);
! if (tv != NULL && eval0(arg, tv, nextcmd, EVAL_EVALUATE) == FAIL)
VIM_CLEAR(tv);

return tv;
--- 464,470 ----
typval_T *tv;

tv = ALLOC_ONE(typval_T);
! if (tv != NULL && eval0(arg, tv, nextcmd, &EVALARG_EVALUATE) == FAIL)
VIM_CLEAR(tv);

return tv;
***************
*** 588,594 ****
++sandbox;
++textwinlock;
*cp = NUL;
! if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL)
retval = 0;
else
{
--- 589,595 ----
++sandbox;
++textwinlock;
*cp = NUL;
! if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL)
retval = 0;
else
{
***************
*** 776,782 ****
else
{
empty1 = FALSE;
! if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) // recursive!
return NULL;
if (tv_get_string_chk(&var1) == NULL)
{
--- 777,783 ----
else
{
empty1 = FALSE;
! if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL) // recursive!
return NULL;
if (tv_get_string_chk(&var1) == NULL)
{
***************
*** 814,820 ****
{
lp->ll_empty2 = FALSE;
// recursive!
! if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL)
{
clear_tv(&var1);
return NULL;
--- 815,821 ----
{
lp->ll_empty2 = FALSE;
// recursive!
! if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL)
{
clear_tv(&var1);
return NULL;
***************
*** 1424,1430 ****
--- 1425,1434 ----
char_u *expr;
typval_T tv;
list_T *l;
+ evalarg_T evalarg;

+ CLEAR_FIELD(evalarg);
+ evalarg.eval_flags = skip ? 0 : EVAL_EVALUATE;
*errp = TRUE; // default: there is an error

fi = ALLOC_CLEAR_ONE(forinfo_T);
***************
*** 1444,1451 ****

if (skip)
++emsg_skip;
! if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE)
! == OK)
{
*errp = FALSE;
if (!skip)
--- 1448,1454 ----

if (skip)
++emsg_skip;
! if (eval0(skipwhite(expr + 2), &tv, nextcmdp, &evalarg) == OK)
{
*errp = FALSE;
if (!skip)
***************
*** 1764,1769 ****
--- 1767,1801 ----
}

/*
+ * If inside Vim9 script, "arg" points to the end of a line (ignoring comments)
+ * and there is a next line, return the next line (skipping blanks) and set
+ * "getnext".
+ * Otherwise just return "arg" unmodified and set "getnext" to FALSE.
+ * "arg" must point somewhere inside a line, not at the start.
+ */
+ static char_u *
+ eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext)
+ {
+ *getnext = FALSE;
+ if (current_sctx.sc_version == SCRIPT_VERSION_VIM9
+ && evalarg != NULL
+ && evalarg->eval_cookie != NULL
+ && (*arg == NUL || (VIM_ISWHITE(arg[-1])
+ && (*arg == '"' || *arg == '#')))
+ && source_nextline(evalarg->eval_cookie) != NULL)
+ {
+ char_u *p = source_nextline(evalarg->eval_cookie);
+
+ if (p != NULL)
+ {
+ *getnext = TRUE;
+ return skipwhite(p);
+ }
+ }
+ return arg;
+ }
+
+ /*
* The "evaluate" argument: When FALSE, the argument is only parsed but not
* executed. The function may return OK, but the rettv will be of type
* VAR_UNKNOWN. The function still returns FAIL for a syntax error.
***************
*** 1774,1780 ****
* This calls eval1() and handles error message and nextcmd.
* Put the result in "rettv" when returning OK and "evaluate" is TRUE.
* Note: "rettv.v_lock" is not set.
! * "flags" has EVAL_EVALUATE and similar flags.
* Return OK or FAIL.
*/
int
--- 1806,1812 ----
* This calls eval1() and handles error message and nextcmd.
* Put the result in "rettv" when returning OK and "evaluate" is TRUE.
* Note: "rettv.v_lock" is not set.
! * "evalarg" can be NULL, EVALARG_EVALUATE or a pointer.
* Return OK or FAIL.
*/
int
***************
*** 1782,1796 ****
char_u *arg,
typval_T *rettv,
char_u **nextcmd,
! int flags)
{
int ret;
char_u *p;
int did_emsg_before = did_emsg;
int called_emsg_before = called_emsg;

p = skipwhite(arg);
! ret = eval1(&p, rettv, flags);
if (ret == FAIL || !ends_excmd2(arg, p))
{
if (ret != FAIL)
--- 1814,1829 ----
char_u *arg,
typval_T *rettv,
char_u **nextcmd,
! evalarg_T *evalarg)
{
int ret;
char_u *p;
int did_emsg_before = did_emsg;
int called_emsg_before = called_emsg;
+ int flags = evalarg == NULL ? 0 : evalarg->eval_flags;

p = skipwhite(arg);
! ret = eval1(&p, rettv, evalarg);
if (ret == FAIL || !ends_excmd2(arg, p))
{
if (ret != FAIL)
***************
*** 1826,1848 ****
* Return OK or FAIL.
*/
int
! eval1(char_u **arg, typval_T *rettv, int flags)
{
- int result;
- typval_T var2;
-
/*
* Get the first variable.
*/
! if (eval2(arg, rettv, flags) == FAIL)
return FAIL;

if ((*arg)[0] == '?')
{
! int evaluate = flags & EVAL_EVALUATE;

result = FALSE;
! if (flags & EVAL_EVALUATE)
{
int error = FALSE;

--- 1859,1894 ----
* Return OK or FAIL.
*/
int
! eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
/*
* Get the first variable.
*/
! if (eval2(arg, rettv, evalarg) == FAIL)
return FAIL;

if ((*arg)[0] == '?')
{
! int result;
! typval_T var2;
! evalarg_T nested_evalarg;
! int orig_flags;
!
! if (evalarg == NULL)
! {
! CLEAR_FIELD(nested_evalarg);
! orig_flags = 0;
! }
! else
! {
! nested_evalarg = *evalarg;
! orig_flags = evalarg->eval_flags;
! }
!
! int evaluate = nested_evalarg.eval_flags & EVAL_EVALUATE;

result = FALSE;
! if (evaluate)
{
int error = FALSE;

***************
*** 1857,1863 ****
* Get the second variable. Recursive!
*/
*arg = skipwhite(*arg + 1);
! if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL)
return FAIL;

/*
--- 1903,1911 ----
* Get the second variable. Recursive!
*/
*arg = skipwhite(*arg + 1);
! nested_evalarg.eval_flags = result ? orig_flags
! : orig_flags & ~EVAL_EVALUATE;
! if (eval1(arg, rettv, &nested_evalarg) == FAIL)
return FAIL;

/*
***************
*** 1875,1881 ****
* Get the third variable. Recursive!
*/
*arg = skipwhite(*arg + 1);
! if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL)
{
if (evaluate && result)
clear_tv(rettv);
--- 1923,1931 ----
* Get the third variable. Recursive!
*/
*arg = skipwhite(*arg + 1);
! nested_evalarg.eval_flags = !result ? orig_flags
! : orig_flags & ~EVAL_EVALUATE;
! if (eval1(arg, &var2, &nested_evalarg) == FAIL)
{
if (evaluate && result)
clear_tv(rettv);
***************
*** 1898,1904 ****
* Return OK or FAIL.
*/
static int
! eval2(char_u **arg, typval_T *rettv, int flags)
{
typval_T var2;
long result;
--- 1948,1954 ----
* Return OK or FAIL.
*/
static int
! eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
typval_T var2;
long result;
***************
*** 1908,1914 ****
/*
* Get the first variable.
*/
! if (eval3(arg, rettv, flags) == FAIL)
return FAIL;

/*
--- 1958,1964 ----
/*
* Get the first variable.
*/
! if (eval3(arg, rettv, evalarg) == FAIL)
return FAIL;

/*
***************
*** 1918,1924 ****
result = FALSE;
while ((*arg)[0] == '|' && (*arg)[1] == '|')
{
! int evaluate = flags & EVAL_EVALUATE;

if (evaluate && first)
{
--- 1968,1989 ----
result = FALSE;
while ((*arg)[0] == '|' && (*arg)[1] == '|')
{
! evalarg_T nested_evalarg;
! int evaluate;
! int orig_flags;
!
! if (evalarg == NULL)
! {
! CLEAR_FIELD(nested_evalarg);
! orig_flags = 0;
! evaluate = FALSE;
! }
! else
! {
! nested_evalarg = *evalarg;
! orig_flags = evalarg->eval_flags;
! evaluate = orig_flags & EVAL_EVALUATE;
! }

if (evaluate && first)
{
***************
*** 1934,1941 ****
* Get the second variable.
*/
*arg = skipwhite(*arg + 2);
! if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE)
! == FAIL)
return FAIL;

/*
--- 1999,2007 ----
* Get the second variable.
*/
*arg = skipwhite(*arg + 2);
! nested_evalarg.eval_flags = !result ? orig_flags
! : orig_flags & ~EVAL_EVALUATE;
! if (eval3(arg, &var2, &nested_evalarg) == FAIL)
return FAIL;

/*
***************
*** 1969,1975 ****
* Return OK or FAIL.
*/
static int
! eval3(char_u **arg, typval_T *rettv, int flags)
{
typval_T var2;
long result;
--- 2035,2041 ----
* Return OK or FAIL.
*/
static int
! eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
typval_T var2;
long result;
***************
*** 1979,1985 ****
/*
* Get the first variable.
*/
! if (eval4(arg, rettv, flags) == FAIL)
return FAIL;

/*
--- 2045,2051 ----
/*
* Get the first variable.
*/
! if (eval4(arg, rettv, evalarg) == FAIL)
return FAIL;

/*
***************
*** 1989,1996 ****
result = TRUE;
while ((*arg)[0] == '&' && (*arg)[1] == '&')
{
! int evaluate = flags & EVAL_EVALUATE;
!
if (evaluate && first)
{
if (tv_get_number_chk(rettv, &error) == 0)
--- 2055,2076 ----
result = TRUE;
while ((*arg)[0] == '&' && (*arg)[1] == '&')
{
! evalarg_T nested_evalarg;
! int orig_flags;
! int evaluate;
!
! if (evalarg == NULL)
! {
! CLEAR_FIELD(nested_evalarg);
! orig_flags = 0;
! evaluate = FALSE;
! }
! else
! {
! nested_evalarg = *evalarg;
! orig_flags = evalarg->eval_flags;
! evaluate = orig_flags & EVAL_EVALUATE;
! }
if (evaluate && first)
{
if (tv_get_number_chk(rettv, &error) == 0)
***************
*** 2005,2011 ****
* Get the second variable.
*/
*arg = skipwhite(*arg + 2);
! if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL)
return FAIL;

/*
--- 2085,2093 ----
* Get the second variable.
*/
*arg = skipwhite(*arg + 2);
! nested_evalarg.eval_flags = result ? orig_flags
! : orig_flags & ~EVAL_EVALUATE;
! if (eval4(arg, &var2, &nested_evalarg) == FAIL)
return FAIL;

/*
***************
*** 2048,2054 ****
* Return OK or FAIL.
*/
static int
! eval4(char_u **arg, typval_T *rettv, int flags)
{
typval_T var2;
char_u *p;
--- 2130,2136 ----
* Return OK or FAIL.
*/
static int
! eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
typval_T var2;
char_u *p;
***************
*** 2060,2066 ****
/*
* Get the first variable.
*/
! if (eval5(arg, rettv, flags) == FAIL)
return FAIL;

p = *arg;
--- 2142,2148 ----
/*
* Get the first variable.
*/
! if (eval5(arg, rettv, evalarg) == FAIL)
return FAIL;

p = *arg;
***************
*** 2128,2139 ****
* Get the second variable.
*/
*arg = skipwhite(p + len);
! if (eval5(arg, &var2, flags) == FAIL)
{
clear_tv(rettv);
return FAIL;
}
! if (flags & EVAL_EVALUATE)
{
int ret = typval_compare(rettv, &var2, type, ic);

--- 2210,2221 ----
* Get the second variable.
*/
*arg = skipwhite(p + len);
! if (eval5(arg, &var2, evalarg) == FAIL)
{
clear_tv(rettv);
return FAIL;
}
! if (evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE))
{
int ret = typval_compare(rettv, &var2, type, ic);

***************
*** 2195,2217 ****
* Return OK or FAIL.
*/
static int
! eval5(char_u **arg, typval_T *rettv, int flags)
{
! typval_T var2;
! int op;
! varnumber_T n1, n2;
! #ifdef FEAT_FLOAT
! float_T f1 = 0, f2 = 0;
! #endif
! char_u *s1, *s2;
! char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
! char_u *p;
! int concat;

/*
* Get the first variable.
*/
! if (eval6(arg, rettv, flags, FALSE) == FAIL)
return FAIL;

/*
--- 2277,2290 ----
* Return OK or FAIL.
*/
static int
! eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
! int evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);

/*
* Get the first variable.
*/
! if (eval6(arg, rettv, evalarg, FALSE) == FAIL)
return FAIL;

/*
***************
*** 2219,2230 ****
*/
for (;;)
{
// "." is only string concatenation when scriptversion is 1
! op = **arg;
! concat = op == '.'
! && (*(*arg + 1) == '.' || current_sctx.sc_version < 2);
if (op != '+' && op != '-' && !concat)
break;

if ((op != '+' || (rettv->v_type != VAR_LIST
&& rettv->v_type != VAR_BLOB))
--- 2292,2311 ----
*/
for (;;)
{
+ int getnext;
+ char_u *p;
+ int op;
+ int concat;
+ typval_T var2;
+
// "." is only string concatenation when scriptversion is 1
! p = eval_next_non_blank(*arg, evalarg, &getnext);
! op = *p;
! concat = op == '.' && (*(p + 1) == '.' || current_sctx.sc_version < 2);
if (op != '+' && op != '-' && !concat)
break;
+ if (getnext)
+ *arg = skipwhite(getsourceline(0, evalarg->eval_cookie, 0, TRUE));

if ((op != '+' || (rettv->v_type != VAR_LIST
&& rettv->v_type != VAR_BLOB))
***************
*** 2240,2246 ****
// we know that the first operand needs to be a string or number
// without evaluating the 2nd operand. So check before to avoid
// side effects after an error.
! if ((flags & EVAL_EVALUATE) && tv_get_string_chk(rettv) == NULL)
{
clear_tv(rettv);
return FAIL;
--- 2321,2327 ----
// we know that the first operand needs to be a string or number
// without evaluating the 2nd operand. So check before to avoid
// side effects after an error.
! if (evaluate && tv_get_string_chk(rettv) == NULL)
{
clear_tv(rettv);
return FAIL;
***************
*** 2253,2273 ****
if (op == '.' && *(*arg + 1) == '.') // .. string concatenation
++*arg;
*arg = skipwhite(*arg + 1);
! if (eval6(arg, &var2, flags, op == '.') == FAIL)
{
clear_tv(rettv);
return FAIL;
}

! if (flags & EVAL_EVALUATE)
{
/*
* Compute the result.
*/
if (op == '.')
{
! s1 = tv_get_string_buf(rettv, buf1); // already checked
! s2 = tv_get_string_buf_chk(&var2, buf2);
if (s2 == NULL) // type error ?
{
clear_tv(rettv);
--- 2334,2356 ----
if (op == '.' && *(*arg + 1) == '.') // .. string concatenation
++*arg;
*arg = skipwhite(*arg + 1);
! if (eval6(arg, &var2, evalarg, op == '.') == FAIL)
{
clear_tv(rettv);
return FAIL;
}

! if (evaluate)
{
/*
* Compute the result.
*/
if (op == '.')
{
! char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
! char_u *s1 = tv_get_string_buf(rettv, buf1);
! char_u *s2 = tv_get_string_buf_chk(&var2, buf2);
!
if (s2 == NULL) // type error ?
{
clear_tv(rettv);
***************
*** 2290,2298 ****
}
else
{
! int error = FALSE;
!
#ifdef FEAT_FLOAT
if (rettv->v_type == VAR_FLOAT)
{
f1 = rettv->vval.v_float;
--- 2373,2383 ----
}
else
{
! int error = FALSE;
! varnumber_T n1, n2;
#ifdef FEAT_FLOAT
+ float_T f1 = 0, f2 = 0;
+
if (rettv->v_type == VAR_FLOAT)
{
f1 = rettv->vval.v_float;
***************
*** 2381,2387 ****
eval6(
char_u **arg,
typval_T *rettv,
! int flags,
int want_string) // after "." operator
{
typval_T var2;
--- 2466,2472 ----
eval6(
char_u **arg,
typval_T *rettv,
! evalarg_T *evalarg,
int want_string) // after "." operator
{
typval_T var2;
***************
*** 2396,2402 ****
/*
* Get the first variable.
*/
! if (eval7(arg, rettv, flags, want_string) == FAIL)
return FAIL;

/*
--- 2481,2487 ----
/*
* Get the first variable.
*/
! if (eval7(arg, rettv, evalarg, want_string) == FAIL)
return FAIL;

/*
***************
*** 2404,2414 ****
*/
for (;;)
{
! op = **arg;
if (op != '*' && op != '/' && op != '%')
break;

! if (flags & EVAL_EVALUATE)
{
#ifdef FEAT_FLOAT
if (rettv->v_type == VAR_FLOAT)
--- 2489,2505 ----
*/
for (;;)
{
! int evaluate = evalarg == NULL ? 0
! : (evalarg->eval_flags & EVAL_EVALUATE);
! int getnext;
!
! op = *eval_next_non_blank(*arg, evalarg, &getnext);
if (op != '*' && op != '/' && op != '%')
break;
+ if (getnext)
+ *arg = skipwhite(getsourceline(0, evalarg->eval_cookie, 0, TRUE));

! if (evaluate)
{
#ifdef FEAT_FLOAT
if (rettv->v_type == VAR_FLOAT)
***************
*** 2431,2440 ****
* Get the second variable.
*/
*arg = skipwhite(*arg + 1);
! if (eval7(arg, &var2, flags, FALSE) == FAIL)
return FAIL;

! if (flags & EVAL_EVALUATE)
{
#ifdef FEAT_FLOAT
if (var2.v_type == VAR_FLOAT)
--- 2522,2531 ----
* Get the second variable.
*/
*arg = skipwhite(*arg + 1);
! if (eval7(arg, &var2, evalarg, FALSE) == FAIL)
return FAIL;

! if (evaluate)
{
#ifdef FEAT_FLOAT
if (var2.v_type == VAR_FLOAT)
***************
*** 2551,2560 ****
eval7(
char_u **arg,
typval_T *rettv,
! int flags,
int want_string) // after "." operator
{
! int evaluate = flags & EVAL_EVALUATE;
int len;
char_u *s;
char_u *start_leader, *end_leader;
--- 2642,2653 ----
eval7(
char_u **arg,
typval_T *rettv,
! evalarg_T *evalarg,
int want_string) // after "." operator
{
! int flags = evalarg == NULL ? 0 : evalarg->eval_flags;
! int evaluate = evalarg != NULL
! && (evalarg->eval_flags & EVAL_EVALUATE);
int len;
char_u *s;
char_u *start_leader, *end_leader;
***************
*** 2672,2686 ****
/*
* nested expression: (expression).
*/
! case '(': *arg = skipwhite(*arg + 1);
! ret = eval1(arg, rettv, flags); // recursive!
! if (**arg == ')')
! ++*arg;
! else if (ret == OK)
! {
! emsg(_(e_missing_close));
! clear_tv(rettv);
! ret = FAIL;
}
break;

--- 2765,2781 ----
/*
* nested expression: (expression).
*/
! case '(': {
! *arg = skipwhite(*arg + 1);
! ret = eval1(arg, rettv, evalarg); // recursive!
! if (**arg == ')')
! ++*arg;
! else if (ret == OK)
! {
! emsg(_(e_missing_close));
! clear_tv(rettv);
! ret = FAIL;
! }
}
break;

***************
*** 3030,3035 ****
--- 3125,3135 ----
}
else
{
+ evalarg_T evalarg;
+
+ CLEAR_FIELD(evalarg);
+ evalarg.eval_flags = flags;
+
/*
* something[idx]
*
***************
*** 3038,3044 ****
*arg = skipwhite(*arg + 1);
if (**arg == ':')
empty1 = TRUE;
! else if (eval1(arg, &var1, flags) == FAIL) // recursive!
return FAIL;
else if (evaluate && tv_get_string_chk(&var1) == NULL)
{
--- 3138,3144 ----
*arg = skipwhite(*arg + 1);
if (**arg == ':')
empty1 = TRUE;
! else if (eval1(arg, &var1, &evalarg) == FAIL) // recursive!
return FAIL;
else if (evaluate && tv_get_string_chk(&var1) == NULL)
{
***************
*** 3056,3062 ****
*arg = skipwhite(*arg + 1);
if (**arg == ']')
empty2 = TRUE;
! else if (eval1(arg, &var2, flags) == FAIL) // recursive!
{
if (!empty1)
clear_tv(&var1);
--- 3156,3162 ----
*arg = skipwhite(*arg + 1);
if (**arg == ']')
empty2 = TRUE;
! else if (eval1(arg, &var2, &evalarg) == FAIL) // recursive!
{
if (!empty1)
clear_tv(&var1);
***************
*** 4947,4952 ****
--- 5047,5056 ----
int atstart = TRUE;
int did_emsg_before = did_emsg;
int called_emsg_before = called_emsg;
+ evalarg_T evalarg;
+
+ CLEAR_FIELD(evalarg);
+ evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;

if (eap->skip)
++emsg_skip;
***************
*** 4957,4963 ****
need_clr_eos = needclr;

p = arg;
! if (eval1(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE) == FAIL)
{
/*
* Report the invalid expression unless the expression evaluation
--- 5061,5067 ----
need_clr_eos = needclr;

p = arg;
! if (eval1(&arg, &rettv, &evalarg) == FAIL)
{
/*
* Report the invalid expression unless the expression evaluation
*** ../vim-8.2.1046/src/proto/eval.pro 2020-06-07 14:50:47.271846855 +0200
--- src/proto/eval.pro 2020-06-24 15:29:48.293576760 +0200
***************
*** 26,33 ****
void free_for_info(void *fi_void);
void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
int pattern_match(char_u *pat, char_u *text, int ic);
! int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int flags);
! int eval1(char_u **arg, typval_T *rettv, int flags);
void eval_addblob(typval_T *tv1, typval_T *tv2);
int eval_addlist(typval_T *tv1, typval_T *tv2);
char_u *partial_name(partial_T *pt);
--- 26,33 ----
void free_for_info(void *fi_void);
void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
int pattern_match(char_u *pat, char_u *text, int ic);
! int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, evalarg_T *evalarg);
! int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg_in);
void eval_addblob(typval_T *tv1, typval_T *tv2);
int eval_addlist(typval_T *tv1, typval_T *tv2);
char_u *partial_name(partial_T *pt);
*** ../vim-8.2.1046/src/dict.c 2020-06-07 20:49:02.073891895 +0200
--- src/dict.c 2020-06-24 15:17:09.663805921 +0200
***************
*** 788,799 ****
--- 788,801 ----
/*
* Allocate a variable for a Dictionary and fill it from "*arg".
* "literal" is TRUE for #{key: val}
+ * "flags" can have EVAL_EVALUATE and other EVAL_ flags.
* Return OK or FAIL. Returns NOTDONE for {expr}.
*/
int
eval_dict(char_u **arg, typval_T *rettv, int flags, int literal)
{
int evaluate = flags & EVAL_EVALUATE;
+ evalarg_T evalarg;
dict_T *d = NULL;
typval_T tvkey;
typval_T tv;
***************
*** 803,808 ****
--- 805,813 ----
char_u buf[NUMBUFLEN];
int vim9script = current_sctx.sc_version == SCRIPT_VERSION_VIM9;

+ CLEAR_FIELD(evalarg);
+ evalarg.eval_flags = flags;
+
/*
* First check if it's not a curly-braces thing: {expr}.
* Must do this without evaluating, otherwise a function may be called
***************
*** 812,818 ****
*/
if (!vim9script && *start != '}')
{
! if (eval1(&start, &tv, 0) == FAIL) // recursive!
return FAIL;
if (*start == '}')
return NOTDONE;
--- 817,823 ----
*/
if (!vim9script && *start != '}')
{
! if (eval1(&start, &tv, NULL) == FAIL) // recursive!
return FAIL;
if (*start == '}')
return NOTDONE;
***************
*** 832,838 ****
{
if ((literal
? get_literal_key(arg, &tvkey)
! : eval1(arg, &tvkey, flags)) == FAIL) // recursive!
goto failret;

if (**arg != ':')
--- 837,843 ----
{
if ((literal
? get_literal_key(arg, &tvkey)
! : eval1(arg, &tvkey, &evalarg)) == FAIL) // recursive!
goto failret;

if (**arg != ':')
***************
*** 854,860 ****
}

*arg = skipwhite(*arg + 1);
! if (eval1(arg, &tv, flags) == FAIL) // recursive!
{
if (evaluate)
clear_tv(&tvkey);
--- 859,865 ----
}

*arg = skipwhite(*arg + 1);
! if (eval1(arg, &tv, &evalarg) == FAIL) // recursive!
{
if (evaluate)
clear_tv(&tvkey);
*** ../vim-8.2.1046/src/evalfunc.c 2020-06-22 19:10:51.685755111 +0200
--- src/evalfunc.c 2020-06-24 15:10:58.576743921 +0200
***************
*** 2084,2090 ****
s = skipwhite(s);

p = s;
! if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL)
{
if (p != NULL && !aborting())
semsg(_(e_invexpr2), p);
--- 2084,2090 ----
s = skipwhite(s);

p = s;
! if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL)
{
if (p != NULL && !aborting())
semsg(_(e_invexpr2), p);
*** ../vim-8.2.1046/src/evalvars.c 2020-06-21 15:52:55.810451610 +0200
--- src/evalvars.c 2020-06-24 17:48:46.152783688 +0200
***************
*** 435,441 ****
if (p_verbose == 0)
++emsg_off;

! if (eval1(&p, &rettv, EVAL_EVALUATE) == OK)
{
if (rettv.v_type != VAR_LIST)
clear_tv(&rettv);
--- 435,441 ----
if (p_verbose == 0)
++emsg_off;

! if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK)
{
if (rettv.v_type != VAR_LIST)
clear_tv(&rettv);
***************
*** 774,780 ****
}
else
{
! int eval_flags;

rettv.v_type = VAR_UNKNOWN;
i = FAIL;
--- 774,780 ----
}
else
{
! evalarg_T evalarg;

rettv.v_type = VAR_UNKNOWN;
i = FAIL;
***************
*** 797,810 ****

if (eap->skip)
++emsg_skip;
! eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
! i = eval0(expr, &rettv, &eap->nextcmd, eval_flags);
}
if (eap->skip)
{
if (i != FAIL)
clear_tv(&rettv);
- --emsg_skip;
}
else if (i != FAIL)
{
--- 797,813 ----

if (eap->skip)
++emsg_skip;
! evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
! evalarg.eval_cookie = eap->getline == getsourceline
! ? eap->cookie : NULL;
! i = eval0(expr, &rettv, &eap->nextcmd, &evalarg);
! if (eap->skip)
! --emsg_skip;
}
if (eap->skip)
{
if (i != FAIL)
clear_tv(&rettv);
}
else if (i != FAIL)
{
*** ../vim-8.2.1046/src/list.c 2020-06-16 11:34:38.314223444 +0200
--- src/list.c 2020-06-24 15:12:29.432513898 +0200
***************
*** 1165,1170 ****
--- 1165,1174 ----
list_T *l = NULL;
typval_T tv;
listitem_T *item;
+ evalarg_T evalarg;
+
+ CLEAR_FIELD(evalarg);
+ evalarg.eval_flags = flags;

if (evaluate)
{
***************
*** 1176,1182 ****
*arg = skipwhite(*arg + 1);
while (**arg != ']' && **arg != NUL)
{
! if (eval1(arg, &tv, flags) == FAIL) // recursive!
goto failret;
if (evaluate)
{
--- 1180,1186 ----
*arg = skipwhite(*arg + 1);
while (**arg != ']' && **arg != NUL)
{
! if (eval1(arg, &tv, &evalarg) == FAIL) // recursive!
goto failret;
if (evaluate)
{
*** ../vim-8.2.1046/src/userfunc.c 2020-06-20 22:50:44.175608236 +0200
--- src/userfunc.c 2020-06-24 18:12:28.057560263 +0200
***************
*** 239,245 ****
whitep = p;
p = skipwhite(p);
expr = p;
! if (eval1(&p, &rettv, 0) != FAIL)
{
if (ga_grow(default_args, 1) == FAIL)
goto err_ret;
--- 239,245 ----
whitep = p;
p = skipwhite(p);
expr = p;
! if (eval1(&p, &rettv, NULL) != FAIL)
{
if (ga_grow(default_args, 1) == FAIL)
goto err_ret;
***************
*** 561,566 ****
--- 561,570 ----
int ret = OK;
typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments
int argcount = 0; // number of arguments found
+ evalarg_T evalarg;
+
+ CLEAR_FIELD(evalarg);
+ evalarg.eval_flags = funcexe->evaluate ? EVAL_EVALUATE : 0;

/*
* Get the arguments.
***************
*** 572,579 ****
argp = skipwhite(argp + 1); // skip the '(' or ','
if (*argp == ')' || *argp == ',' || *argp == NUL)
break;
! if (eval1(&argp, &argvars[argcount],
! funcexe->evaluate ? EVAL_EVALUATE : 0) == FAIL)
{
ret = FAIL;
break;
--- 576,582 ----
argp = skipwhite(argp + 1); // skip the '(' or ','
if (*argp == ')' || *argp == ',' || *argp == NUL)
break;
! if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL)
{
ret = FAIL;
break;
***************
*** 1249,1255 ****

default_expr = ((char_u **)(fp->uf_def_args.ga_data))
[ai + fp->uf_def_args.ga_len];
! if (eval1(&default_expr, &def_rettv, EVAL_EVALUATE) == FAIL)
{
default_arg_err = 1;
break;
--- 1252,1258 ----

default_expr = ((char_u **)(fp->uf_def_args.ga_data))
[ai + fp->uf_def_args.ga_len];
! if (eval1(&default_expr, &def_rettv, &EVALARG_EVALUATE) == FAIL)
{
default_arg_err = 1;
break;
***************
*** 1394,1400 ****
// A Lambda always has the command "return {expr}". It is much faster
// to evaluate {expr} directly.
++ex_nesting_level;
! (void)eval1(&p, rettv, EVAL_EVALUATE);
--ex_nesting_level;
}
else
--- 1397,1403 ----
// A Lambda always has the command "return {expr}". It is much faster
// to evaluate {expr} directly.
++ex_nesting_level;
! (void)eval1(&p, rettv, &EVALARG_EVALUATE);
--ex_nesting_level;
}
else
***************
*** 3697,3702 ****
--- 3700,3706 ----
char_u *arg = eap->arg;
typval_T rettv;
int returning = FALSE;
+ evalarg_T evalarg;

if (current_funccal == NULL)
{
***************
*** 3704,3716 ****
return;
}

if (eap->skip)
++emsg_skip;

eap->nextcmd = NULL;
if ((*arg != NUL && *arg != '|' && *arg != '\n')
! && eval0(arg, &rettv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE)
! != FAIL)
{
if (!eap->skip)
returning = do_return(eap, FALSE, TRUE, &rettv);
--- 3708,3722 ----
return;
}

+ CLEAR_FIELD(evalarg);
+ evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
+
if (eap->skip)
++emsg_skip;

eap->nextcmd = NULL;
if ((*arg != NUL && *arg != '|' && *arg != '\n')
! && eval0(arg, &rettv, &eap->nextcmd, &evalarg) != FAIL)
{
if (!eap->skip)
returning = do_return(eap, FALSE, TRUE, &rettv);
***************
*** 3767,3773 ****
// instead to skip to any following command, e.g. for:
// :if 0 | call dict.foo().bar() | endif
++emsg_skip;
! if (eval0(eap->arg, &rettv, &eap->nextcmd, 0) != FAIL)
clear_tv(&rettv);
--emsg_skip;
return;
--- 3773,3779 ----
// instead to skip to any following command, e.g. for:
// :if 0 | call dict.foo().bar() | endif
++emsg_skip;
! if (eval0(eap->arg, &rettv, &eap->nextcmd, NULL) != FAIL)
clear_tv(&rettv);
--emsg_skip;
return;
*** ../vim-8.2.1046/src/scriptfile.c 2020-06-20 22:50:44.175608236 +0200
--- src/scriptfile.c 2020-06-24 14:35:18.694204892 +0200
***************
*** 1050,1055 ****
--- 1050,1064 ----
{
return ((struct source_cookie *)cookie)->level;
}
+
+ /*
+ * Return the readahead line.
+ */
+ char_u *
+ source_nextline(void *cookie)
+ {
+ return ((struct source_cookie *)cookie)->nextline;
+ }
#endif

#if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
*** ../vim-8.2.1046/src/proto/scriptfile.pro 2020-05-25 22:36:46.629735032 +0200
--- src/proto/scriptfile.pro 2020-06-24 15:16:55.911840634 +0200
***************
*** 22,27 ****
--- 22,28 ----
linenr_T *source_breakpoint(void *cookie);
int *source_dbg_tick(void *cookie);
int source_level(void *cookie);
+ char_u *source_nextline(void *cookie);
int do_source(char_u *fname, int check_other, int is_vimrc, int *ret_sid);
void ex_scriptnames(exarg_T *eap);
void scriptnames_slash_adjust(void);
*** ../vim-8.2.1046/src/testdir/test_vim9_expr.vim 2020-06-23 22:26:01.893386768 +0200
--- src/testdir/test_vim9_expr.vim 2020-06-24 17:23:25.596076339 +0200
***************
*** 570,575 ****
--- 570,595 ----
assert_equal(0z01ab01ab, g:ablob + g:ablob)
enddef

+ def Test_expr5_vim9script()
+ " only checks line continuation
+ let lines =<< trim END
+ vim9script
+ let var = 11
+ + 77
+ - 22
+ assert_equal(66, var)
+ END
+ CheckScriptSuccess(lines)
+
+ lines =<< trim END
+ vim9script
+ let var = 'one'
+ .. 'two'
+ assert_equal('onetwo', var)
+ END
+ CheckScriptSuccess(lines)
+ enddef
+
def Test_expr5_float()
if !has('float')
MissingFeature 'float'
***************
*** 661,666 ****
--- 681,706 ----
call CheckDefFailure(["let x = 6 * xxx"], 'E1001')
enddef

+ def Test_expr6_vim9script()
+ " only checks line continuation
+ let lines =<< trim END
+ vim9script
+ let var = 11
+ * 22
+ / 3
+ assert_equal(80, var)
+ END
+ CheckScriptSuccess(lines)
+
+ lines =<< trim END
+ vim9script
+ let var = 25
+ % 10
+ assert_equal(5, var)
+ END
+ CheckScriptSuccess(lines)
+ enddef
+
def Test_expr6_float()
if !has('float')
MissingFeature 'float'
*** ../vim-8.2.1046/src/version.c 2020-06-24 13:37:03.162425194 +0200
--- src/version.c 2020-06-24 17:07:37.269316749 +0200
***************
*** 756,757 ****
--- 756,759 ----
{ /* Add new patch number below this line */
+ /**/
+ 1047,
/**/

--
Q: Why does /dev/null accept only integers?
A: You can't sink a float.

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages