Patch 8.2.1124
Problem:    Vim9: no line break allowed in :import command.
Solution:   Skip over line breaks.
Files:      src/vim9script.c, src/proto/vim9script.pro, src/vim9compile.c,
            src/testdir/test_vim9_script.vim


*** ../vim-8.2.1123/src/vim9script.c    2020-07-01 18:29:23.685143414 +0200
--- src/vim9script.c    2020-07-04 13:12:10.543506786 +0200
***************
*** 142,158 ****
      void
  ex_import(exarg_T *eap)
  {
!     char_u *cmd_end;
  
      if (!getline_equal(eap->getline, eap->cookie, getsourceline))
      {
        emsg(_("E1094: import can only be used in a script"));
        return;
      }
  
!     cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid, NULL);
      if (cmd_end != NULL)
        eap->nextcmd = check_nextcmd(cmd_end);
  }
  
  /*
--- 142,162 ----
      void
  ex_import(exarg_T *eap)
  {
!     char_u    *cmd_end;
!     evalarg_T evalarg;
  
      if (!getline_equal(eap->getline, eap->cookie, getsourceline))
      {
        emsg(_("E1094: import can only be used in a script"));
        return;
      }
+     fill_evalarg_from_eap(&evalarg, eap, eap->skip);
  
!     cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid,
!                                                              &evalarg, NULL);
      if (cmd_end != NULL)
        eap->nextcmd = check_nextcmd(cmd_end);
+     clear_evalarg(&evalarg, eap);
  }
  
  /*
***************
*** 164,190 ****
      int
  find_exported(
        int         sid,
!       char_u      **argp,
!       int         *name_len,
        ufunc_T     **ufunc,
        type_T      **type)
  {
-     char_u    *name = *argp;
-     char_u    *arg = *argp;
-     int               cc;
      int               idx = -1;
      svar_T    *sv;
      scriptitem_T *script = SCRIPT_ITEM(sid);
  
-     // isolate one name
-     while (eval_isnamec(*arg))
-       ++arg;
-     *name_len = (int)(arg - name);
- 
      // find name in "script"
      // TODO: also find script-local user function
-     cc = *arg;
-     *arg = NUL;
      idx = get_script_item_idx(sid, name, FALSE);
      if (idx >= 0)
      {
--- 168,183 ----
      int
  find_exported(
        int         sid,
!       char_u      *name,
        ufunc_T     **ufunc,
        type_T      **type)
  {
      int               idx = -1;
      svar_T    *sv;
      scriptitem_T *script = SCRIPT_ITEM(sid);
  
      // find name in "script"
      // TODO: also find script-local user function
      idx = get_script_item_idx(sid, name, FALSE);
      if (idx >= 0)
      {
***************
*** 192,198 ****
        if (!sv->sv_export)
        {
            semsg(_("E1049: Item not exported in script: %s"), name);
-           *arg = cc;
            return -1;
        }
        *type = sv->sv_type;
--- 185,190 ----
***************
*** 210,219 ****
        {
            funcname = alloc(STRLEN(name) + 10);
            if (funcname == NULL)
-           {
-               *arg = cc;
                return -1;
-           }
        }
        funcname[0] = K_SPECIAL;
        funcname[1] = KS_EXTRA;
--- 202,208 ----
***************
*** 226,238 ****
        if (*ufunc == NULL)
        {
            semsg(_("E1048: Item not found in script: %s"), name);
-           *arg = cc;
            return -1;
        }
      }
-     *arg = cc;
-     arg = skipwhite(arg);
-     *argp = arg;
  
      return idx;
  }
--- 215,223 ----
***************
*** 243,304 ****
   * Returns a pointer to after the command or NULL in case of failure
   */
      char_u *
! handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx)
  {
      char_u    *arg = arg_start;
!     char_u    *cmd_end;
!     char_u    *as_ptr = NULL;
!     char_u    *from_ptr;
!     int               as_len = 0;
      int               ret = FAIL;
      typval_T  tv;
      int               sid = -1;
      int               res;
  
      if (*arg == '{')
      {
!       // skip over {item} list
!       while (*arg != NUL && *arg != '}')
!           ++arg;
!       if (*arg == '}')
!           arg = skipwhite(arg + 1);
      }
      else
      {
!       if (*arg == '*')
!           arg = skipwhite(arg + 1);
        else if (eval_isnamec1(*arg))
        {
            while (eval_isnamec(*arg))
                ++arg;
!           arg = skipwhite(arg);
        }
!       if (STRNCMP("as", arg, 2) == 0 && VIM_ISWHITE(arg[2]))
        {
!           // skip over "as Name "
            arg = skipwhite(arg + 2);
!           as_ptr = arg;
            if (eval_isnamec1(*arg))
                while (eval_isnamec(*arg))
                    ++arg;
!           as_len = (int)(arg - as_ptr);
!           arg = skipwhite(arg);
!           if (check_defined(as_ptr, as_len, cctx) == FAIL)
!               return NULL;
        }
        else if (*arg_start == '*')
        {
            emsg(_("E1045: Missing \"as\" after *"));
!           return NULL;
        }
      }
!     if (STRNCMP("from", arg, 4) != 0 || !VIM_ISWHITE(arg[4]))
      {
        emsg(_("E1070: Missing \"from\""));
!       return NULL;
      }
!     from_ptr = arg;
!     arg = skipwhite(arg + 4);
      tv.v_type = VAR_UNKNOWN;
      // TODO: should we accept any expression?
      if (*arg == '\'')
--- 228,348 ----
   * Returns a pointer to after the command or NULL in case of failure
   */
      char_u *
! handle_import(
!       char_u      *arg_start,
!       garray_T    *gap,
!       int         import_sid,
!       evalarg_T   *evalarg,
!       void        *cctx)
  {
      char_u    *arg = arg_start;
!     char_u    *cmd_end = NULL;
!     char_u    *as_name = NULL;
      int               ret = FAIL;
      typval_T  tv;
      int               sid = -1;
      int               res;
+     garray_T  names;
+     static char e_import_syntax[] = N_("E1047: syntax error in import");
  
+     ga_init2(&names, sizeof(char_u *), 10);
      if (*arg == '{')
      {
!       // "import {item, item} from ..."
!       arg = skipwhite_and_linebreak(arg + 1, evalarg);
!       for (;;)
!       {
!           char_u  *p = arg;
!           int     had_comma = FALSE;
! 
!           while (eval_isnamec(*arg))
!               ++arg;
!           if (p == arg)
!               break;
!           if (ga_grow(&names, 1) == FAIL)
!               goto erret;
!           ((char_u **)names.ga_data)[names.ga_len] =
!                                                     vim_strnsave(p, arg - p);
!           ++names.ga_len;
!           if (*arg == ',')
!           {
!               had_comma = TRUE;
!               ++arg;
!           }
!           arg = skipwhite_and_linebreak(arg, evalarg);
!           if (*arg == '}')
!           {
!               arg = skipwhite_and_linebreak(arg + 1, evalarg);
!               break;
!           }
!           if (!had_comma)
!           {
!               emsg(_("E1046: Missing comma in import"));
!               goto erret;
!           }
!       }
!       if (names.ga_len == 0)
!       {
!           emsg(_(e_import_syntax));
!           goto erret;
!       }
      }
      else
      {
!       // "import Name from ..."
!       // "import * as Name from ..."
!       // "import item [as Name] from ..."
!       arg = skipwhite_and_linebreak(arg, evalarg);
!       if (arg[0] == '*' && IS_WHITE_OR_NUL(arg[1]))
!           arg = skipwhite_and_linebreak(arg + 1, evalarg);
        else if (eval_isnamec1(*arg))
        {
+           char_u  *p = arg;
+ 
            while (eval_isnamec(*arg))
                ++arg;
!           if (ga_grow(&names, 1) == FAIL)
!               goto erret;
!           ((char_u **)names.ga_data)[names.ga_len] =
!                                                     vim_strnsave(p, arg - p);
!           ++names.ga_len;
!           arg = skipwhite_and_linebreak(arg, evalarg);
!       }
!       else
!       {
!           emsg(_(e_import_syntax));
!           goto erret;
        }
! 
!       if (STRNCMP("as", arg, 2) == 0 && IS_WHITE_OR_NUL(arg[2]))
        {
!           char_u *p;
! 
!           // skip over "as Name "; no line break allowed after "as"
            arg = skipwhite(arg + 2);
!           p = arg;
            if (eval_isnamec1(*arg))
                while (eval_isnamec(*arg))
                    ++arg;
!           if (check_defined(p, (int)(arg - p), cctx) == FAIL)
!               goto erret;
!           as_name = vim_strnsave(p, arg - p);
!           arg = skipwhite_and_linebreak(arg, evalarg);
        }
        else if (*arg_start == '*')
        {
            emsg(_("E1045: Missing \"as\" after *"));
!           goto erret;
        }
      }
! 
!     if (STRNCMP("from", arg, 4) != 0 || !IS_WHITE_OR_NUL(arg[4]))
      {
        emsg(_("E1070: Missing \"from\""));
!       goto erret;
      }
! 
!     arg = skipwhite_and_linebreak_keep_string(arg + 4, evalarg);
      tv.v_type = VAR_UNKNOWN;
      // TODO: should we accept any expression?
      if (*arg == '\'')
***************
*** 308,318 ****
      if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
      {
        emsg(_("E1071: Invalid string after \"from\""));
!       return NULL;
      }
      cmd_end = arg;
  
!     // find script tv.vval.v_string
      if (*tv.vval.v_string == '.')
      {
        size_t          len;
--- 352,364 ----
      if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
      {
        emsg(_("E1071: Invalid string after \"from\""));
!       goto erret;
      }
      cmd_end = arg;
  
!     /*
!      * find script file
!      */
      if (*tv.vval.v_string == '.')
      {
        size_t          len;
***************
*** 326,332 ****
        if (from_name == NULL)
        {
            clear_tv(&tv);
!           return NULL;
        }
        vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
        add_pathsep(from_name);
--- 372,378 ----
        if (from_name == NULL)
        {
            clear_tv(&tv);
!           goto erret;
        }
        vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
        add_pathsep(from_name);
***************
*** 351,357 ****
        if (from_name == NULL)
        {
            clear_tv(&tv);
!           return NULL;
        }
        vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
        res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
--- 397,403 ----
        if (from_name == NULL)
        {
            clear_tv(&tv);
!           goto erret;
        }
        vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
        res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
***************
*** 362,368 ****
      {
        semsg(_("E1053: Could not import \"%s\""), tv.vval.v_string);
        clear_tv(&tv);
!       return NULL;
      }
      clear_tv(&tv);
  
--- 408,414 ----
      {
        semsg(_("E1053: Could not import \"%s\""), tv.vval.v_string);
        clear_tv(&tv);
!       goto erret;
      }
      clear_tv(&tv);
  
***************
*** 372,412 ****
                                        : &SCRIPT_ITEM(import_sid)->sn_imports);
  
        if (imported == NULL)
!           return NULL;
!       imported->imp_name = vim_strnsave(as_ptr, as_len);
        imported->imp_sid = sid;
        imported->imp_all = TRUE;
      }
      else
      {
        arg = arg_start;
        if (*arg == '{')
            arg = skipwhite(arg + 1);
!       for (;;)
        {
!           char_u      *name = arg;
!           int         name_len;
            int         idx;
            imported_T  *imported;
            ufunc_T     *ufunc = NULL;
            type_T      *type;
  
!           idx = find_exported(sid, &arg, &name_len, &ufunc, &type);
  
            if (idx < 0 && ufunc == NULL)
!               return NULL;
  
!           if (check_defined(name, name_len, cctx) == FAIL)
!               return NULL;
  
            imported = new_imported(gap != NULL ? gap
                                       : &SCRIPT_ITEM(import_sid)->sn_imports);
            if (imported == NULL)
!               return NULL;
  
            // TODO: check for "as" following
!           // imported->imp_name = vim_strnsave(as_ptr, as_len);
!           imported->imp_name = vim_strnsave(name, name_len);
            imported->imp_sid = sid;
            if (idx >= 0)
            {
--- 418,461 ----
                                        : &SCRIPT_ITEM(import_sid)->sn_imports);
  
        if (imported == NULL)
!           goto erret;
!       imported->imp_name = as_name;
!       as_name = NULL;
        imported->imp_sid = sid;
        imported->imp_all = TRUE;
      }
      else
      {
+       int i;
+ 
        arg = arg_start;
        if (*arg == '{')
            arg = skipwhite(arg + 1);
!       for (i = 0; i < names.ga_len; ++i)
        {
!           char_u      *name = ((char_u **)names.ga_data)[i];
            int         idx;
            imported_T  *imported;
            ufunc_T     *ufunc = NULL;
            type_T      *type;
  
!           idx = find_exported(sid, name, &ufunc, &type);
  
            if (idx < 0 && ufunc == NULL)
!               goto erret;
  
!           if (check_defined(name, STRLEN(name), cctx) == FAIL)
!               goto erret;
  
            imported = new_imported(gap != NULL ? gap
                                       : &SCRIPT_ITEM(import_sid)->sn_imports);
            if (imported == NULL)
!               goto erret;
  
            // TODO: check for "as" following
!           // imported->imp_name = vim_strsave(as_name);
!           imported->imp_name = name;
!           ((char_u **)names.ga_data)[i] = NULL;
            imported->imp_sid = sid;
            if (idx >= 0)
            {
***************
*** 415,444 ****
            }
            else
                imported->imp_funcname = ufunc->uf_name;
- 
-           arg = skipwhite(arg);
-           if (*arg_start != '{')
-               break;
-           if (*arg == '}')
-           {
-               arg = skipwhite(arg + 1);
-               break;
-           }
- 
-           if (*arg != ',')
-           {
-               emsg(_("E1046: Missing comma in import"));
-               return NULL;
-           }
-           arg = skipwhite(arg + 1);
-       }
-       if (arg != from_ptr)
-       {
-           // cannot happen, just in case the above has a flaw
-           emsg(_("E1047: syntax error in import"));
-           return NULL;
        }
      }
      return cmd_end;
  }
  
--- 464,474 ----
            }
            else
                imported->imp_funcname = ufunc->uf_name;
        }
      }
+ erret:
+     ga_clear_strings(&names);
+     vim_free(as_name);
      return cmd_end;
  }
  
*** ../vim-8.2.1123/src/proto/vim9script.pro    2020-06-19 18:34:10.989945091 
+0200
--- src/proto/vim9script.pro    2020-07-03 22:57:15.354069062 +0200
***************
*** 4,11 ****
  void ex_export(exarg_T *eap);
  void free_imports(int sid);
  void ex_import(exarg_T *eap);
! int find_exported(int sid, char_u **argp, int *name_len, ufunc_T **ufunc, 
type_T **type);
! char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, void 
*cctx);
  char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg);
  int check_script_var_type(typval_T *dest, typval_T *value, char_u *name);
  /* vim: set ft=c : */
--- 4,11 ----
  void ex_export(exarg_T *eap);
  void free_imports(int sid);
  void ex_import(exarg_T *eap);
! int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type);
! char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, 
evalarg_T *evalarg, void *cctx);
  char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg);
  int check_script_var_type(typval_T *dest, typval_T *value, char_u *name);
  /* vim: set ft=c : */
*** ../vim-8.2.1123/src/vim9compile.c   2020-07-01 18:29:23.681143435 +0200
--- src/vim9compile.c   2020-07-03 22:55:56.290395603 +0200
***************
*** 2613,2619 ****
        if (import->imp_all)
        {
            char_u      *p = skipwhite(*end);
!           int         name_len;
            ufunc_T     *ufunc;
            type_T      *type;
  
--- 2613,2620 ----
        if (import->imp_all)
        {
            char_u      *p = skipwhite(*end);
!           char_u      *exp_name;
!           int         cc;
            ufunc_T     *ufunc;
            type_T      *type;
  
***************
*** 2630,2636 ****
                return FAIL;
            }
  
!           idx = find_exported(import->imp_sid, &p, &name_len, &ufunc, &type);
            // TODO: what if it is a function?
            if (idx < 0)
                return FAIL;
--- 2631,2647 ----
                return FAIL;
            }
  
!           // isolate one name
!           exp_name = p;
!           while (eval_isnamec(*p))
!               ++p;
!           cc = *p;
!           *p = NUL;
! 
!           idx = find_exported(import->imp_sid, exp_name, &ufunc, &type);
!           *p = cc;
!           p = skipwhite(p);
! 
            // TODO: what if it is a function?
            if (idx < 0)
                return FAIL;
***************
*** 2981,2986 ****
--- 2992,2998 ----
  
  /*
   * Like to_name_end() but also skip over a list or dict constant.
+  * This intentionally does not handle line continuation.
   */
      char_u *
  to_name_const_end(char_u *arg)
***************
*** 5632,5638 ****
      static char_u *
  compile_import(char_u *arg, cctx_T *cctx)
  {
!     return handle_import(arg, &cctx->ctx_imports, 0, cctx);
  }
  
  /*
--- 5644,5650 ----
      static char_u *
  compile_import(char_u *arg, cctx_T *cctx)
  {
!     return handle_import(arg, &cctx->ctx_imports, 0, NULL, cctx);
  }
  
  /*
*** ../vim-8.2.1123/src/testdir/test_vim9_script.vim    2020-07-01 
20:07:11.557328210 +0200
--- src/testdir/test_vim9_script.vim    2020-07-04 13:11:46.319570593 +0200
***************
*** 686,691 ****
--- 686,720 ----
    unlet g:imported_name g:imported_name_appended
    delete('Ximport.vim')
  
+   # similar, with line breaks
+   let import_line_break_script_lines =<< trim END
+     vim9script
+     import {
+         exported,
+         Exported,
+         }
+         from
+         './Xexport.vim'
+     g:imported = exported
+     exported += 5
+     g:imported_added = exported
+     g:imported_func = Exported()
+   END
+   writefile(import_line_break_script_lines, 'Ximport_lbr.vim')
+   source Ximport_lbr.vim
+ 
+   assert_equal(9876, g:imported)
+   assert_equal(9881, g:imported_added)
+   assert_equal('Exported', g:imported_func)
+ 
+   # exported script not sourced again
+   assert_false(exists('g:result'))
+   unlet g:imported
+   unlet g:imported_added
+   unlet g:imported_func
+   delete('Ximport_lbr.vim')
+ 
+   # import inside :def function
    let import_in_def_lines =<< trim END
      vim9script
      def ImportInDef()
***************
*** 751,756 ****
--- 780,800 ----
    writefile(import_star_as_lines_missing_name, 'Ximport.vim')
    assert_fails('source Ximport.vim', 'E1048:')
  
+   let import_star_as_lbr_lines =<< trim END
+     vim9script
+     import *
+         as Export
+         from
+         './Xexport.vim'
+     def UseExport()
+       g:imported = Export.exported
+     enddef
+     UseExport()
+   END
+   writefile(import_star_as_lbr_lines, 'Ximport.vim')
+   source Ximport.vim
+   assert_equal(9883, g:imported)
+ 
    let import_star_lines =<< trim END
      vim9script
      import * from './Xexport.vim'
*** ../vim-8.2.1123/src/version.c       2020-07-03 21:17:31.343914450 +0200
--- src/version.c       2020-07-04 13:13:32.219291562 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1124,
  /**/

-- 
"Beware of bugs in the above code; I have only proved
it correct, not tried it." -- Donald Knuth

 /// 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/202007041115.064BFtix291029%40masaka.moolenaar.net.

Raspunde prin e-mail lui