Patch 8.2.1110
Problem:    Vim9: line continuation does not work in function arguments.
Solution:   Pass "evalarg" to get_func_tv().  Fix seeing double quoted string
            as comment.
Files:      src/userfunc.c, src/proto/userfunc.pro, src/eval.c, src/ex_eval.c,
            src/list.c, src/dict.c, src/proto/eval.pro,
            src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_func.vim


*** ../vim-8.2.1109/src/userfunc.c      2020-06-29 20:20:28.047899632 +0200
--- src/userfunc.c      2020-07-01 16:17:08.795558275 +0200
***************
*** 601,616 ****
      int               len,            // length of "name" or -1 to use 
strlen()
      typval_T  *rettv,
      char_u    **arg,          // argument, pointing to the '('
      funcexe_T *funcexe)       // various values
  {
      char_u    *argp;
      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.
--- 601,613 ----
      int               len,            // length of "name" or -1 to use 
strlen()
      typval_T  *rettv,
      char_u    **arg,          // argument, pointing to the '('
+     evalarg_T *evalarg,       // for line continuation
      funcexe_T *funcexe)       // various values
  {
      char_u    *argp;
      int               ret = OK;
      typval_T  argvars[MAX_FUNC_ARGS + 1];     // vars for arguments
      int               argcount = 0;           // number of arguments found
  
      /*
       * Get the arguments.
***************
*** 619,628 ****
      while (argcount < MAX_FUNC_ARGS - (funcexe->partial == NULL ? 0
                                                  : funcexe->partial->pt_argc))
      {
!       argp = skipwhite(argp + 1);         // skip the '(' or ','
        if (*argp == ')' || *argp == ',' || *argp == NUL)
            break;
!       if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL)
        {
            ret = FAIL;
            break;
--- 616,627 ----
      while (argcount < MAX_FUNC_ARGS - (funcexe->partial == NULL ? 0
                                                  : funcexe->partial->pt_argc))
      {
!       // skip the '(' or ',' and possibly line breaks
!       argp = skipwhite_and_linebreak(argp + 1, evalarg);
! 
        if (*argp == ')' || *argp == ',' || *argp == NUL)
            break;
!       if (eval1(&argp, &argvars[argcount], evalarg) == FAIL)
        {
            ret = FAIL;
            break;
***************
*** 631,636 ****
--- 630,636 ----
        if (*argp != ',')
            break;
      }
+     argp = skipwhite_and_linebreak(argp, evalarg);
      if (*argp == ')')
        ++argp;
      else
***************
*** 3832,3847 ****
      int               failed = FALSE;
      funcdict_T        fudi;
      partial_T *partial = NULL;
  
      if (eap->skip)
      {
        // trans_function_name() doesn't work well when skipping, use eval0()
        // 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, NULL) != FAIL)
            clear_tv(&rettv);
        --emsg_skip;
        return;
      }
  
--- 3832,3850 ----
      int               failed = FALSE;
      funcdict_T        fudi;
      partial_T *partial = NULL;
+     evalarg_T evalarg;
  
+     fill_evalarg_from_eap(&evalarg, eap, eap->skip);
      if (eap->skip)
      {
        // trans_function_name() doesn't work well when skipping, use eval0()
        // 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, &evalarg) != FAIL)
            clear_tv(&rettv);
        --emsg_skip;
+       clear_evalarg(&evalarg, eap);
        return;
      }
  
***************
*** 3918,3924 ****
        funcexe.evaluate = !eap->skip;
        funcexe.partial = partial;
        funcexe.selfdict = fudi.fd_dict;
!       if (get_func_tv(name, -1, &rettv, &arg, &funcexe) == FAIL)
        {
            failed = TRUE;
            break;
--- 3921,3927 ----
        funcexe.evaluate = !eap->skip;
        funcexe.partial = partial;
        funcexe.selfdict = fudi.fd_dict;
!       if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL)
        {
            failed = TRUE;
            break;
***************
*** 3947,3952 ****
--- 3950,3956 ----
      }
      if (eap->skip)
        --emsg_skip;
+     clear_evalarg(&evalarg, eap);
  
      // When inside :try we need to check for following "| catch".
      if (!failed || eap->cstack->cs_trylevel > 0)
*** ../vim-8.2.1109/src/proto/userfunc.pro      2020-06-27 18:06:42.152575113 
+0200
--- src/proto/userfunc.pro      2020-07-01 16:15:05.368237127 +0200
***************
*** 7,13 ****
  int get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
  char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int 
no_autoload);
  void emsg_funcname(char *ermsg, char_u *name);
! int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, 
funcexe_T *funcexe);
  char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int 
*error);
  ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx);
  int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, 
typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
--- 7,13 ----
  int get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
  char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int 
no_autoload);
  void emsg_funcname(char *ermsg, char_u *name);
! int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, 
evalarg_T *evalarg, funcexe_T *funcexe);
  char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int 
*error);
  ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx);
  int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, 
typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
*** ../vim-8.2.1109/src/eval.c  2020-07-01 13:07:34.261146025 +0200
--- src/eval.c  2020-07-01 17:07:29.031461006 +0200
***************
*** 153,159 ****
  }
  #endif
  
!     static void
  fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip)
  {
      CLEAR_FIELD(*evalarg);
--- 153,159 ----
  }
  #endif
  
!     void
  fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip)
  {
      CLEAR_FIELD(*evalarg);
***************
*** 1804,1809 ****
--- 1804,1810 ----
      static int
  eval_func(
        char_u      **arg,      // points to "(", will be advanced
+       evalarg_T   *evalarg,
        char_u      *name,
        int         name_len,
        typval_T    *rettv,
***************
*** 1839,1845 ****
        funcexe.evaluate = evaluate;
        funcexe.partial = partial;
        funcexe.basetv = basetv;
!       ret = get_func_tv(s, len, rettv, arg, &funcexe);
      }
      vim_free(s);
  
--- 1840,1846 ----
        funcexe.evaluate = evaluate;
        funcexe.partial = partial;
        funcexe.basetv = basetv;
!       ret = get_func_tv(s, len, rettv, arg, evalarg, &funcexe);
      }
      vim_free(s);
  
***************
*** 1917,1922 ****
--- 1918,1926 ----
      return skipwhite(line);
  }
  
+ /*
+  * Call eval_next_non_blank() and get the next line if needed.
+  */
      char_u *
  skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg)
  {
***************
*** 1930,1935 ****
--- 1934,1953 ----
  }
  
  /*
+  * Call eval_next_non_blank() and get the next line if needed, but not when a
+  * double quote follows.  Used inside an expression.
+  */
+     char_u *
+ skipwhite_and_linebreak_keep_string(char_u *arg, evalarg_T *evalarg)
+ {
+     char_u  *p = skipwhite(arg);
+ 
+     if (*p == '"')
+       return p;
+     return skipwhite_and_linebreak(arg, evalarg);
+ }
+ 
+ /*
   * After using "evalarg" filled from "eap" free the memory.
   */
      void
***************
*** 2995,3001 ****
        else
        {
            if (**arg == '(')           // recursive!
!               ret = eval_func(arg, s, len, rettv, flags, NULL);
            else if (flags & EVAL_CONSTANT)
                ret = FAIL;
            else if (evaluate)
--- 3013,3019 ----
        else
        {
            if (**arg == '(')           // recursive!
!               ret = eval_func(arg, evalarg, s, len, rettv, flags, NULL);
            else if (flags & EVAL_CONSTANT)
                ret = FAIL;
            else if (evaluate)
***************
*** 3106,3111 ****
--- 3124,3130 ----
      static int
  call_func_rettv(
        char_u      **arg,
+       evalarg_T   *evalarg,
        typval_T    *rettv,
        int         evaluate,
        dict_T      *selfdict,
***************
*** 3142,3148 ****
      funcexe.partial = pt;
      funcexe.selfdict = selfdict;
      funcexe.basetv = basetv;
!     ret = get_func_tv(s, -1, rettv, arg, &funcexe);
  
      // Clear the funcref afterwards, so that deleting it while
      // evaluating the arguments is possible (see test55).
--- 3161,3167 ----
      funcexe.partial = pt;
      funcexe.selfdict = selfdict;
      funcexe.basetv = basetv;
!     ret = get_func_tv(s, -1, rettv, arg, evalarg, &funcexe);
  
      // Clear the funcref afterwards, so that deleting it while
      // evaluating the arguments is possible (see test55).
***************
*** 3189,3195 ****
        ret = FAIL;
      }
      else
!       ret = call_func_rettv(arg, rettv, evaluate, NULL, &base);
  
      // Clear the funcref afterwards, so that deleting it while
      // evaluating the arguments is possible (see test55).
--- 3208,3214 ----
        ret = FAIL;
      }
      else
!       ret = call_func_rettv(arg, evalarg, rettv, evaluate, NULL, &base);
  
      // Clear the funcref afterwards, so that deleting it while
      // evaluating the arguments is possible (see test55).
***************
*** 3208,3214 ****
  eval_method(
      char_u    **arg,
      typval_T  *rettv,
!     int               evaluate,
      int               verbose)        // give error messages
  {
      char_u    *name;
--- 3227,3233 ----
  eval_method(
      char_u    **arg,
      typval_T  *rettv,
!     evalarg_T *evalarg,
      int               verbose)        // give error messages
  {
      char_u    *name;
***************
*** 3216,3221 ****
--- 3235,3242 ----
      char_u    *alias;
      typval_T  base = *rettv;
      int               ret;
+     int               evaluate = evalarg != NULL
+                                     && (evalarg->eval_flags & EVAL_EVALUATE);
  
      // Skip over the ->.
      *arg += 2;
***************
*** 3247,3253 ****
            ret = FAIL;
        }
        else
!           ret = eval_func(arg, name, len, rettv,
                                          evaluate ? EVAL_EVALUATE : 0, &base);
      }
  
--- 3268,3274 ----
            ret = FAIL;
        }
        else
!           ret = eval_func(arg, evalarg, name, len, rettv,
                                          evaluate ? EVAL_EVALUATE : 0, &base);
      }
  
***************
*** 5035,5041 ****
      {
        if (**arg == '(')
        {
!           ret = call_func_rettv(arg, rettv, evaluate, selfdict, NULL);
  
            // Stop the expression evaluation when immediately aborting on
            // error, or when an interrupt occurred or an exception was thrown
--- 5056,5063 ----
      {
        if (**arg == '(')
        {
!           ret = call_func_rettv(arg, evalarg, rettv, evaluate,
!                                                              selfdict, NULL);
  
            // Stop the expression evaluation when immediately aborting on
            // error, or when an interrupt occurred or an exception was thrown
***************
*** 5058,5064 ****
                    ret = eval_lambda(arg, rettv, evalarg, verbose);
                else
                    // expr->name()
!                   ret = eval_method(arg, rettv, evaluate, verbose);
            }
        }
        else // **arg == '[' || **arg == '.'
--- 5080,5086 ----
                    ret = eval_lambda(arg, rettv, evalarg, verbose);
                else
                    // expr->name()
!                   ret = eval_method(arg, rettv, evalarg, verbose);
            }
        }
        else // **arg == '[' || **arg == '.'
*** ../vim-8.2.1109/src/ex_eval.c       2020-06-28 18:43:36.296992324 +0200
--- src/ex_eval.c       2020-07-01 16:37:14.715189132 +0200
***************
*** 897,909 ****
      typval_T  tv;
      evalarg_T evalarg;
  
!     CLEAR_FIELD(evalarg);
!     evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
!     if (getline_equal(eap->getline, eap->cookie, getsourceline))
!     {
!       evalarg.eval_getline = eap->getline;
!       evalarg.eval_cookie = eap->cookie;
!     }
  
      if (eval0(eap->arg, &tv, eap, &evalarg) == OK)
        clear_tv(&tv);
--- 897,903 ----
      typval_T  tv;
      evalarg_T evalarg;
  
!     fill_evalarg_from_eap(&evalarg, eap, eap->skip);
  
      if (eval0(eap->arg, &tv, eap, &evalarg) == OK)
        clear_tv(&tv);
*** ../vim-8.2.1109/src/list.c  2020-06-29 20:09:33.266762870 +0200
--- src/list.c  2020-07-01 17:19:20.750886757 +0200
***************
*** 1177,1183 ****
            return FAIL;
      }
  
!     *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
      while (**arg != ']' && **arg != NUL)
      {
        if (eval1(arg, &tv, evalarg) == FAIL)   // recursive!
--- 1177,1183 ----
            return FAIL;
      }
  
!     *arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg);
      while (**arg != ']' && **arg != NUL)
      {
        if (eval1(arg, &tv, evalarg) == FAIL)   // recursive!
***************
*** 1207,1214 ****
            *arg = skipwhite(*arg + 1);
        }
  
!       // the "]" can be on the next line
!       *arg = skipwhite_and_linebreak(*arg, evalarg);
        if (**arg == ']')
            break;
  
--- 1207,1215 ----
            *arg = skipwhite(*arg + 1);
        }
  
!       // The "]" can be on the next line.  But a double quoted string may
!       // follow, not a comment.
!       *arg = skipwhite_and_linebreak_keep_string(*arg, evalarg);
        if (**arg == ']')
            break;
  
***************
*** 2356,2362 ****
        }
        if (l != NULL)
        {
!           list_insert_tv(l, &argvars[1], item);
            copy_tv(&argvars[0], rettv);
        }
      }
--- 2357,2363 ----
        }
        if (l != NULL)
        {
!           (void)list_insert_tv(l, &argvars[1], item);
            copy_tv(&argvars[0], rettv);
        }
      }
*** ../vim-8.2.1109/src/dict.c  2020-06-27 21:17:55.359214424 +0200
--- src/dict.c  2020-07-01 17:21:16.610157312 +0200
***************
*** 830,836 ****
      tvkey.v_type = VAR_UNKNOWN;
      tv.v_type = VAR_UNKNOWN;
  
!     *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
      while (**arg != '}' && **arg != NUL)
      {
        if ((literal
--- 830,836 ----
      tvkey.v_type = VAR_UNKNOWN;
      tv.v_type = VAR_UNKNOWN;
  
!     *arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg);
      while (**arg != '}' && **arg != NUL)
      {
        if ((literal
***************
*** 862,868 ****
            goto failret;
        }
  
!       *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
        if (eval1(arg, &tv, evalarg) == FAIL)   // recursive!
        {
            if (evaluate)
--- 862,868 ----
            goto failret;
        }
  
!       *arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg);
        if (eval1(arg, &tv, evalarg) == FAIL)   // recursive!
        {
            if (evaluate)
***************
*** 904,910 ****
        }
  
        // the "}" can be on the next line
!       *arg = skipwhite_and_linebreak(*arg, evalarg);
        if (**arg == '}')
            break;
        if (!had_comma)
--- 904,910 ----
        }
  
        // the "}" can be on the next line
!       *arg = skipwhite_and_linebreak_keep_string(*arg, evalarg);
        if (**arg == '}')
            break;
        if (!had_comma)
*** ../vim-8.2.1109/src/proto/eval.pro  2020-06-28 18:43:36.296992324 +0200
--- src/proto/eval.pro  2020-07-01 17:12:53.277350109 +0200
***************
*** 3,8 ****
--- 3,9 ----
  varnumber_T num_modulus(varnumber_T n1, varnumber_T n2);
  void eval_init(void);
  void eval_clear(void);
+ void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip);
  int eval_to_bool(char_u *arg, int *error, exarg_T *eap, int skip);
  int eval_expr_valid_arg(typval_T *tv);
  int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T 
*rettv);
***************
*** 31,36 ****
--- 32,38 ----
  char_u *eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext);
  char_u *eval_next_line(evalarg_T *evalarg);
  char_u *skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg);
+ char_u *skipwhite_and_linebreak_keep_string(char_u *arg, evalarg_T *evalarg);
  void clear_evalarg(evalarg_T *evalarg, exarg_T *eap);
  int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg);
  int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
*** ../vim-8.2.1109/src/testdir/test_vim9_expr.vim      2020-06-27 
21:17:55.359214424 +0200
--- src/testdir/test_vim9_expr.vim      2020-07-01 17:11:54.829726236 +0200
***************
*** 1101,1106 ****
--- 1101,1113 ----
  
    lines =<< trim END
        vim9script
+       let d = { "one": "one", "two": "two", }
+       assert_equal({'one': 'one', 'two': 'two'}, d)
+   END
+   CheckScriptSuccess(lines)
+ 
+   lines =<< trim END
+       vim9script
        let d = #{one: 1,
                two: 2,
               }
*** ../vim-8.2.1109/src/testdir/test_vim9_func.vim      2020-06-30 
13:37:57.931017122 +0200
--- src/testdir/test_vim9_func.vim      2020-07-01 16:29:48.046272595 +0200
***************
*** 353,358 ****
--- 353,374 ----
      assert_equal('text', var)
      ("some")->MyFunc()
      assert_equal('some', var)
+ 
+     MyFunc(
+         'continued'
+         )
+     assert_equal('continued',
+             var
+             )
+ 
+     call MyFunc(
+         'more'
+           ..
+           'lines'
+         )
+     assert_equal(
+         'morelines',
+         var)
    END
    writefile(lines, 'Xcall.vim')
    source Xcall.vim
*** ../vim-8.2.1109/src/version.c       2020-07-01 16:00:39.936953109 +0200
--- src/version.c       2020-07-01 17:27:14.211918264 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1110,
  /**/

-- 
I used to wonder about the meaning of life.  But I looked it
up in the dictionary under "L" and there it was - the meaning
of life.  It was less than I expected.              - Dogbert

 /// Bram Moolenaar -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202007011529.061FT0141193405%40masaka.moolenaar.net.

Raspunde prin e-mail lui