]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.1047: Vim9: script cannot use line continuation like :def function v8.2.1047
authorBram Moolenaar <Bram@vim.org>
Wed, 24 Jun 2020 16:37:35 +0000 (18:37 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 24 Jun 2020 16:37:35 +0000 (18:37 +0200)
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.

15 files changed:
src/dict.c
src/eval.c
src/evalfunc.c
src/evalvars.c
src/ex_eval.c
src/globals.h
src/list.c
src/proto/eval.pro
src/proto/scriptfile.pro
src/scriptfile.c
src/structs.h
src/testdir/test_vim9_expr.vim
src/userfunc.c
src/version.c
src/vim.h

index 9d942619864c10942b9fc7a9de0bd9601a94a87e..caa398deba9598df5c516a51b10961eb4b1c253f 100644 (file)
@@ -788,12 +788,14 @@ get_literal_key(char_u **arg, typval_T *tv)
 /*
  * 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,6 +805,9 @@ eval_dict(char_u **arg, typval_T *rettv, int flags, int literal)
     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,7 +817,7 @@ eval_dict(char_u **arg, typval_T *rettv, int flags, int literal)
      */
     if (!vim9script && *start != '}')
     {
-       if (eval1(&start, &tv, 0) == FAIL)      // recursive!
+       if (eval1(&start, &tv, NULL) == FAIL)   // recursive!
            return FAIL;
        if (*start == '}')
            return NOTDONE;
@@ -832,7 +837,7 @@ eval_dict(char_u **arg, typval_T *rettv, int flags, int literal)
     {
        if ((literal
                ? get_literal_key(arg, &tvkey)
-               : eval1(arg, &tvkey, flags)) == FAIL)   // recursive!
+               : eval1(arg, &tvkey, &evalarg)) == FAIL)        // recursive!
            goto failret;
 
        if (**arg != ':')
@@ -854,7 +859,7 @@ eval_dict(char_u **arg, typval_T *rettv, int flags, int literal)
        }
 
        *arg = skipwhite(*arg + 1);
-       if (eval1(arg, &tv, flags) == FAIL)     // recursive!
+       if (eval1(arg, &tv, &evalarg) == FAIL)  // recursive!
        {
            if (evaluate)
                clear_tv(&tvkey);
index 38afc248947f72f04ba54f6bc3ca40257227477c..ffb69de8d2180dfccf2050343c187d58048041c1 100644 (file)
@@ -45,12 +45,12 @@ typedef struct
 } 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 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,7 +169,7 @@ eval_to_bool(
 
     if (skip)
        ++emsg_skip;
-    if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL)
+    if (eval0(arg, &tv, nextcmd, skip ? NULL : &EVALARG_EVALUATE) == FAIL)
        *error = TRUE;
     else
     {
@@ -197,7 +197,7 @@ eval1_emsg(char_u **arg, typval_T *rettv, int evaluate)
     int                did_emsg_before = did_emsg;
     int                called_emsg_before = called_emsg;
 
-    ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0);
+    ret = eval1(arg, rettv, evaluate ? &EVALARG_EVALUATE : NULL);
     if (ret == FAIL)
     {
        // Report the invalid expression unless the expression evaluation has
@@ -325,7 +325,8 @@ eval_to_string_skip(
 
     if (skip)
        ++emsg_skip;
-    if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip)
+    if (eval0(arg, &tv, nextcmd, skip ? NULL : &EVALARG_EVALUATE)
+                                                              == FAIL || skip)
        retval = NULL;
     else
     {
@@ -348,7 +349,7 @@ skip_expr(char_u **pp)
     typval_T   rettv;
 
     *pp = skipwhite(*pp);
-    return eval1(pp, &rettv, 0);
+    return eval1(pp, &rettv, NULL);
 }
 
 /*
@@ -370,7 +371,7 @@ eval_to_string(
     char_u     numbuf[NUMBUFLEN];
 #endif
 
-    if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL)
+    if (eval0(arg, &tv, nextcmd, &EVALARG_EVALUATE) == FAIL)
        retval = NULL;
     else
     {
@@ -440,7 +441,7 @@ eval_to_number(char_u *expr)
 
     ++emsg_off;
 
-    if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL)
+    if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL)
        retval = -1;
     else
     {
@@ -463,7 +464,7 @@ eval_expr(char_u *arg, char_u **nextcmd)
     typval_T   *tv;
 
     tv = ALLOC_ONE(typval_T);
-    if (tv != NULL && eval0(arg, tv, nextcmd, EVAL_EVALUATE) == FAIL)
+    if (tv != NULL && eval0(arg, tv, nextcmd, &EVALARG_EVALUATE) == FAIL)
        VIM_CLEAR(tv);
 
     return tv;
@@ -588,7 +589,7 @@ eval_foldexpr(char_u *arg, int *cp)
        ++sandbox;
     ++textwinlock;
     *cp = NUL;
-    if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL)
+    if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL)
        retval = 0;
     else
     {
@@ -776,7 +777,7 @@ get_lval(
            else
            {
                empty1 = FALSE;
-               if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL)  // recursive!
+               if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL)  // recursive!
                    return NULL;
                if (tv_get_string_chk(&var1) == NULL)
                {
@@ -814,7 +815,7 @@ get_lval(
                {
                    lp->ll_empty2 = FALSE;
                    // recursive!
-                   if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL)
+                   if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL)
                    {
                        clear_tv(&var1);
                        return NULL;
@@ -1424,7 +1425,10 @@ eval_for_line(
     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,8 +1448,7 @@ eval_for_line(
 
     if (skip)
        ++emsg_skip;
-    if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE)
-                                                                        == OK)
+    if (eval0(skipwhite(expr + 2), &tv, nextcmdp, &evalarg) == OK)
     {
        *errp = FALSE;
        if (!skip)
@@ -1763,6 +1766,35 @@ eval_func(
     return ret;
 }
 
+/*
+ * 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
@@ -1774,7 +1806,7 @@ eval_func(
  * 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.
+ * "evalarg" can be NULL, EVALARG_EVALUATE or a pointer.
  * Return OK or FAIL.
  */
     int
@@ -1782,15 +1814,16 @@ eval0(
     char_u     *arg,
     typval_T   *rettv,
     char_u     **nextcmd,
-    int                flags)
+    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, flags);
+    ret = eval1(&p, rettv, evalarg);
     if (ret == FAIL || !ends_excmd2(arg, p))
     {
        if (ret != FAIL)
@@ -1826,23 +1859,36 @@ eval0(
  * Return OK or FAIL.
  */
     int
-eval1(char_u **arg, typval_T *rettv, int flags)
+eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
 {
-    int                result;
-    typval_T   var2;
-
     /*
      * Get the first variable.
      */
-    if (eval2(arg, rettv, flags) == FAIL)
+    if (eval2(arg, rettv, evalarg) == FAIL)
        return FAIL;
 
     if ((*arg)[0] == '?')
     {
-       int evaluate = flags & EVAL_EVALUATE;
+       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 (flags & EVAL_EVALUATE)
+       if (evaluate)
        {
            int         error = FALSE;
 
@@ -1857,7 +1903,9 @@ eval1(char_u **arg, typval_T *rettv, int flags)
         * Get the second variable.  Recursive!
         */
        *arg = skipwhite(*arg + 1);
-       if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL)
+       nested_evalarg.eval_flags = result ? orig_flags
+                                                : orig_flags & ~EVAL_EVALUATE;
+       if (eval1(arg, rettv, &nested_evalarg) == FAIL)
            return FAIL;
 
        /*
@@ -1875,7 +1923,9 @@ eval1(char_u **arg, typval_T *rettv, int flags)
         * Get the third variable.  Recursive!
         */
        *arg = skipwhite(*arg + 1);
-       if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL)
+       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,7 +1948,7 @@ eval1(char_u **arg, typval_T *rettv, int flags)
  * Return OK or FAIL.
  */
     static int
-eval2(char_u **arg, typval_T *rettv, int flags)
+eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
 {
     typval_T   var2;
     long       result;
@@ -1908,7 +1958,7 @@ eval2(char_u **arg, typval_T *rettv, int flags)
     /*
      * Get the first variable.
      */
-    if (eval3(arg, rettv, flags) == FAIL)
+    if (eval3(arg, rettv, evalarg) == FAIL)
        return FAIL;
 
     /*
@@ -1918,7 +1968,22 @@ eval2(char_u **arg, typval_T *rettv, int flags)
     result = FALSE;
     while ((*arg)[0] == '|' && (*arg)[1] == '|')
     {
-       int evaluate = flags & EVAL_EVALUATE;
+       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,8 +1999,9 @@ eval2(char_u **arg, typval_T *rettv, int flags)
         * Get the second variable.
         */
        *arg = skipwhite(*arg + 2);
-       if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE)
-                                                                      == FAIL)
+       nested_evalarg.eval_flags = !result ? orig_flags
+                                                : orig_flags & ~EVAL_EVALUATE;
+       if (eval3(arg, &var2, &nested_evalarg) == FAIL)
            return FAIL;
 
        /*
@@ -1969,7 +2035,7 @@ eval2(char_u **arg, typval_T *rettv, int flags)
  * Return OK or FAIL.
  */
     static int
-eval3(char_u **arg, typval_T *rettv, int flags)
+eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
 {
     typval_T   var2;
     long       result;
@@ -1979,7 +2045,7 @@ eval3(char_u **arg, typval_T *rettv, int flags)
     /*
      * Get the first variable.
      */
-    if (eval4(arg, rettv, flags) == FAIL)
+    if (eval4(arg, rettv, evalarg) == FAIL)
        return FAIL;
 
     /*
@@ -1989,8 +2055,22 @@ eval3(char_u **arg, typval_T *rettv, int flags)
     result = TRUE;
     while ((*arg)[0] == '&' && (*arg)[1] == '&')
     {
-       int evaluate = flags & EVAL_EVALUATE;
+       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,7 +2085,9 @@ eval3(char_u **arg, typval_T *rettv, int flags)
         * Get the second variable.
         */
        *arg = skipwhite(*arg + 2);
-       if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL)
+       nested_evalarg.eval_flags = result ? orig_flags
+                                                : orig_flags & ~EVAL_EVALUATE;
+       if (eval4(arg, &var2, &nested_evalarg) == FAIL)
            return FAIL;
 
        /*
@@ -2048,7 +2130,7 @@ eval3(char_u **arg, typval_T *rettv, int flags)
  * Return OK or FAIL.
  */
     static int
-eval4(char_u **arg, typval_T *rettv, int flags)
+eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
 {
     typval_T   var2;
     char_u     *p;
@@ -2060,7 +2142,7 @@ eval4(char_u **arg, typval_T *rettv, int flags)
     /*
      * Get the first variable.
      */
-    if (eval5(arg, rettv, flags) == FAIL)
+    if (eval5(arg, rettv, evalarg) == FAIL)
        return FAIL;
 
     p = *arg;
@@ -2128,12 +2210,12 @@ eval4(char_u **arg, typval_T *rettv, int flags)
         * Get the second variable.
         */
        *arg = skipwhite(p + len);
-       if (eval5(arg, &var2, flags) == FAIL)
+       if (eval5(arg, &var2, evalarg) == FAIL)
        {
            clear_tv(rettv);
            return FAIL;
        }
-       if (flags & EVAL_EVALUATE)
+       if (evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE))
        {
            int ret = typval_compare(rettv, &var2, type, ic);
 
@@ -2195,23 +2277,14 @@ eval_addlist(typval_T *tv1, typval_T *tv2)
  * Return OK or FAIL.
  */
     static int
-eval5(char_u **arg, typval_T *rettv, int flags)
+eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
 {
-    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;
+    int        evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
 
     /*
      * Get the first variable.
      */
-    if (eval6(arg, rettv, flags, FALSE) == FAIL)
+    if (eval6(arg, rettv, evalarg, FALSE) == FAIL)
        return FAIL;
 
     /*
@@ -2219,12 +2292,20 @@ eval5(char_u **arg, typval_T *rettv, int flags)
      */
     for (;;)
     {
+       int         getnext;
+       char_u      *p;
+       int         op;
+       int         concat;
+       typval_T    var2;
+
        // "." is only string concatenation when scriptversion is 1
-       op = **arg;
-       concat = op == '.'
-                       && (*(*arg + 1) == '.' || current_sctx.sc_version < 2);
+       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,7 +2321,7 @@ eval5(char_u **arg, typval_T *rettv, int flags)
            // 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)
+           if (evaluate && tv_get_string_chk(rettv) == NULL)
            {
                clear_tv(rettv);
                return FAIL;
@@ -2253,21 +2334,23 @@ eval5(char_u **arg, typval_T *rettv, int flags)
        if (op == '.' && *(*arg + 1) == '.')  // .. string concatenation
            ++*arg;
        *arg = skipwhite(*arg + 1);
-       if (eval6(arg, &var2, flags, op == '.') == FAIL)
+       if (eval6(arg, &var2, evalarg, op == '.') == FAIL)
        {
            clear_tv(rettv);
            return FAIL;
        }
 
-       if (flags & EVAL_EVALUATE)
+       if (evaluate)
        {
            /*
             * Compute the result.
             */
            if (op == '.')
            {
-               s1 = tv_get_string_buf(rettv, buf1);    // already checked
-               s2 = tv_get_string_buf_chk(&var2, buf2);
+               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,9 +2373,11 @@ eval5(char_u **arg, typval_T *rettv, int flags)
            }
            else
            {
-               int         error = FALSE;
-
+               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,7 +2466,7 @@ eval5(char_u **arg, typval_T *rettv, int flags)
 eval6(
     char_u     **arg,
     typval_T   *rettv,
-    int                flags,
+    evalarg_T  *evalarg,
     int                want_string)  // after "." operator
 {
     typval_T   var2;
@@ -2396,7 +2481,7 @@ eval6(
     /*
      * Get the first variable.
      */
-    if (eval7(arg, rettv, flags, want_string) == FAIL)
+    if (eval7(arg, rettv, evalarg, want_string) == FAIL)
        return FAIL;
 
     /*
@@ -2404,11 +2489,17 @@ eval6(
      */
     for (;;)
     {
-       op = **arg;
+       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 (flags & EVAL_EVALUATE)
+       if (evaluate)
        {
 #ifdef FEAT_FLOAT
            if (rettv->v_type == VAR_FLOAT)
@@ -2431,10 +2522,10 @@ eval6(
         * Get the second variable.
         */
        *arg = skipwhite(*arg + 1);
-       if (eval7(arg, &var2, flags, FALSE) == FAIL)
+       if (eval7(arg, &var2, evalarg, FALSE) == FAIL)
            return FAIL;
 
-       if (flags & EVAL_EVALUATE)
+       if (evaluate)
        {
 #ifdef FEAT_FLOAT
            if (var2.v_type == VAR_FLOAT)
@@ -2551,10 +2642,12 @@ eval6(
 eval7(
     char_u     **arg,
     typval_T   *rettv,
-    int                flags,
+    evalarg_T  *evalarg,
     int                want_string)    // after "." operator
 {
-    int                evaluate = flags & EVAL_EVALUATE;
+    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,15 +2765,17 @@ eval7(
     /*
      * 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;
+    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,6 +3125,11 @@ eval_index(
     }
     else
     {
+       evalarg_T       evalarg;
+
+       CLEAR_FIELD(evalarg);
+       evalarg.eval_flags = flags;
+
        /*
         * something[idx]
         *
@@ -3038,7 +3138,7 @@ eval_index(
        *arg = skipwhite(*arg + 1);
        if (**arg == ':')
            empty1 = TRUE;
-       else if (eval1(arg, &var1, flags) == FAIL)      // recursive!
+       else if (eval1(arg, &var1, &evalarg) == FAIL)   // recursive!
            return FAIL;
        else if (evaluate && tv_get_string_chk(&var1) == NULL)
        {
@@ -3056,7 +3156,7 @@ eval_index(
            *arg = skipwhite(*arg + 1);
            if (**arg == ']')
                empty2 = TRUE;
-           else if (eval1(arg, &var2, flags) == FAIL)  // recursive!
+           else if (eval1(arg, &var2, &evalarg) == FAIL)       // recursive!
            {
                if (!empty1)
                    clear_tv(&var1);
@@ -4947,6 +5047,10 @@ ex_echo(exarg_T *eap)
     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,7 +5061,7 @@ ex_echo(exarg_T *eap)
        need_clr_eos = needclr;
 
        p = arg;
-       if (eval1(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE) == FAIL)
+       if (eval1(&arg, &rettv, &evalarg) == FAIL)
        {
            /*
             * Report the invalid expression unless the expression evaluation
index c4ae951b60932cdd555398ce882e3801421c21e8..53584dc46a257d6a667915ecbafdce3295a70ef0 100644 (file)
@@ -2084,7 +2084,7 @@ f_eval(typval_T *argvars, typval_T *rettv)
        s = skipwhite(s);
 
     p = s;
-    if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL)
+    if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL)
     {
        if (p != NULL && !aborting())
            semsg(_(e_invexpr2), p);
index b3e89150ad4eded84f0d06c19548705d191d68d2..35c9dcb73e6f6cd5e5df28b06a6373cbb2ccc663 100644 (file)
@@ -435,7 +435,7 @@ eval_spell_expr(char_u *badword, char_u *expr)
     if (p_verbose == 0)
        ++emsg_off;
 
-    if (eval1(&p, &rettv, EVAL_EVALUATE) == OK)
+    if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK)
     {
        if (rettv.v_type != VAR_LIST)
            clear_tv(&rettv);
@@ -774,7 +774,7 @@ ex_let(exarg_T *eap)
     }
     else
     {
-       int eval_flags;
+       evalarg_T   evalarg;
 
        rettv.v_type = VAR_UNKNOWN;
        i = FAIL;
@@ -797,14 +797,17 @@ ex_let(exarg_T *eap)
 
            if (eap->skip)
                ++emsg_skip;
-           eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
-           i = eval0(expr, &rettv, &eap->nextcmd, eval_flags);
+           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);
-           --emsg_skip;
        }
        else if (i != FAIL)
        {
index a13f844b1439335052d9483e5550da4691cb44e5..cb32bd0791ae1efd0559c6a5ce519179a061ec74 100644 (file)
@@ -895,9 +895,12 @@ report_discard_pending(int pending, void *value)
 ex_eval(exarg_T *eap)
 {
     typval_T   tv;
+    evalarg_T  evalarg;
 
-    if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE)
-                                                                        == OK)
+    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);
 }
 
index cd154911737610ba42af1d5252dabb4dd3d87d8d..8601e2b1e5345c687522d2b651cd97d909966ffd 100644 (file)
@@ -1880,6 +1880,9 @@ EXTERN char windowsVersion[20] INIT(= {0});
 
 // 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
index 130ab25251cc8daf9c45dee7183de6fbae3056e2..c624003a211c6aaf0447d8525e446d489c1802e1 100644 (file)
@@ -1165,6 +1165,10 @@ get_list_tv(char_u **arg, typval_T *rettv, int flags, int do_error)
     list_T     *l = NULL;
     typval_T   tv;
     listitem_T *item;
+    evalarg_T  evalarg;
+
+    CLEAR_FIELD(evalarg);
+    evalarg.eval_flags = flags;
 
     if (evaluate)
     {
@@ -1176,7 +1180,7 @@ get_list_tv(char_u **arg, typval_T *rettv, int flags, int do_error)
     *arg = skipwhite(*arg + 1);
     while (**arg != ']' && **arg != NUL)
     {
-       if (eval1(arg, &tv, flags) == FAIL)     // recursive!
+       if (eval1(arg, &tv, &evalarg) == FAIL)  // recursive!
            goto failret;
        if (evaluate)
        {
index 57dd8387cd258504571755e13df5c779dbca8e0f..4fb04eb1fcc5a13889ee6f4456548d1db889cea5 100644 (file)
@@ -26,8 +26,8 @@ int next_for_item(void *fi_void, char_u *arg);
 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);
+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);
index e2a267141adadf6b4ae85e00c43d7a9653d3dba7..b5b8aae936bea8867aa1d305e1307addfeca8b98 100644 (file)
@@ -22,6 +22,7 @@ void ex_options(exarg_T *eap);
 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);
index caeab192853cacc42cf90433a49ba4e1fdf97e93..9ffc66c1b11830a13da394b4f7c68e3d346e68fe 100644 (file)
@@ -1050,6 +1050,15 @@ source_level(void *cookie)
 {
     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)
index ce9dfbcbfd261e27d1f19748692237088855f96c..3a9bbd33c6057c2f23af99905bfd62d69ddfd8d3 100644 (file)
@@ -1746,6 +1746,19 @@ typedef struct
 # 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.
index 46034fb30a009577268f2b5e6b8c4bbfa98505ca..b37f92fb6a6340c633b1e7b81e15709ce42c255f 100644 (file)
@@ -570,6 +570,26 @@ def Test_expr5()
   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,6 +681,26 @@ def Test_expr6()
   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'
index 8a1b9edda8e339c1a793dd4c967b5362be1a1f94..a27c68d04128859bc3d1141e5492b590f786c0be 100644 (file)
@@ -239,7 +239,7 @@ get_function_args(
                whitep = p;
                p = skipwhite(p);
                expr = p;
-               if (eval1(&p, &rettv, 0) != FAIL)
+               if (eval1(&p, &rettv, NULL) != FAIL)
                {
                    if (ga_grow(default_args, 1) == FAIL)
                        goto err_ret;
@@ -561,6 +561,10 @@ get_func_tv(
     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,8 +576,7 @@ get_func_tv(
        argp = skipwhite(argp + 1);         // skip the '(' or ','
        if (*argp == ')' || *argp == ',' || *argp == NUL)
            break;
-       if (eval1(&argp, &argvars[argcount],
-                               funcexe->evaluate ? EVAL_EVALUATE : 0) == FAIL)
+       if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL)
        {
            ret = FAIL;
            break;
@@ -1249,7 +1252,7 @@ call_user_func(
 
                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)
+               if (eval1(&default_expr, &def_rettv, &EVALARG_EVALUATE) == FAIL)
                {
                    default_arg_err = 1;
                    break;
@@ -1394,7 +1397,7 @@ call_user_func(
        // 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);
+       (void)eval1(&p, rettv, &EVALARG_EVALUATE);
        --ex_nesting_level;
     }
     else
@@ -3697,6 +3700,7 @@ ex_return(exarg_T *eap)
     char_u     *arg = eap->arg;
     typval_T   rettv;
     int                returning = FALSE;
+    evalarg_T  evalarg;
 
     if (current_funccal == NULL)
     {
@@ -3704,13 +3708,15 @@ ex_return(exarg_T *eap)
        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, eap->skip ? 0 : EVAL_EVALUATE)
-                                                                      != FAIL)
+                       && eval0(arg, &rettv, &eap->nextcmd, &evalarg) != FAIL)
     {
        if (!eap->skip)
            returning = do_return(eap, FALSE, TRUE, &rettv);
@@ -3767,7 +3773,7 @@ ex_call(exarg_T *eap)
        // 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)
+       if (eval0(eap->arg, &rettv, &eap->nextcmd, NULL) != FAIL)
            clear_tv(&rettv);
        --emsg_skip;
        return;
index 1ee45307f389bd1f786e021578f3e500f912973a..e383c1843ebc7a8ec763f7698f1b4ea47b84bbe5 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1047,
 /**/
     1046,
 /**/
index 2c2848cc7cf76e574e5bc51523563e53e56fa119..a0fa629eac0aa541b65b5b9ccef91dfe8f1085c2 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -2665,10 +2665,6 @@ long elapsed(DWORD start_tick);
 #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