Patch 8.2.2015
Problem:    Vim9: literal dict #{} is not like any other language.
Solution:   Support the JavaScript syntax.
Files:      runtime/doc/vim9.txt, src/vim9compile.c,
            src/proto/vim9compile.pro, src/errors.h,
            src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_builtin.vim,
            src/testdir/test_vim9_func.vim, src/testdir/test_vim9_script.vim


*** ../vim-8.2.2014/runtime/doc/vim9.txt        2020-10-04 16:06:00.509884351 
+0200
--- runtime/doc/vim9.txt        2020-11-19 18:50:44.916967440 +0100
***************
*** 112,119 ****
        101 number
  
  To improve readability there must be a space between a command and the #
! that starts a comment.  Note that #{ is the start of a dictionary, therefore
! it does not start a comment.
  
  
  Vim9 functions ~
--- 112,118 ----
        101 number
  
  To improve readability there must be a space between a command and the #
! that starts a comment.
  
  
  Vim9 functions ~
***************
*** 303,310 ****
        myList->add(123)
        g:myList->add(123)
        [1, 2, 3]->Process()
!       #{a: 1, b: 2}->Process()
!       {'a': 1, 'b': 2}->Process()
        "foobar"->Process()
        ("foobar")->Process()
        'foobar'->Process()
--- 302,308 ----
        myList->add(123)
        g:myList->add(123)
        [1, 2, 3]->Process()
!       {a: 1, b: 2}->Process()
        "foobar"->Process()
        ("foobar")->Process()
        'foobar'->Process()
***************
*** 346,352 ****
                'two',
                ]
  And when a dict spans multiple lines: >
!       var mydict = #{
                one: 1,
                two: 2,
                }
--- 344,350 ----
                'two',
                ]
  And when a dict spans multiple lines: >
!       var mydict = {
                one: 1,
                two: 2,
                }
***************
*** 430,435 ****
--- 428,454 ----
  |curly-braces-names| cannot be used.
  
  
+ Dictionary literals ~
+ 
+ Traditionally Vim has supported dictionary literals with a {} syntax: >
+       let dict = {'key': value}
+ 
+ Later it became clear that using a simple key name is very common, thus
+ literally dictionaries were introduced in a backwards compatible way: >
+       let dict = #{key: value}
+ 
+ However, this #{} syntax is unlike any existing language.  As it appears that
+ using a literaly key is much more common than using an expression, and
+ considering that JavaScript uses this syntax, using the {} form for dictionary
+ literals was considered a much more useful syntax.  In Vim9 script the {} form
+ uses literal keys: >
+       let dict = {key: value}
+ 
+ In case an expression needs to be used for the key, square brackets can be
+ used, just like in JavaScript: >
+       let dict = {["key" .. nr]: value}
+ 
+ 
  No :xit, :t, :append, :change or :insert ~
  
  These commands are too easily confused with local variable names.
*** ../vim-8.2.2014/src/vim9compile.c   2020-11-18 17:38:59.349902386 +0100
--- src/vim9compile.c   2020-11-18 19:54:15.192042721 +0100
***************
*** 2771,2777 ****
   * Return a pointer to just after the name.  Equal to "arg" if there is no
   * valid name.
   */
!     static char_u *
  to_name_end(char_u *arg, int namespace)
  {
      char_u    *p;
--- 2771,2777 ----
   * Return a pointer to just after the name.  Equal to "arg" if there is no
   * valid name.
   */
!     char_u *
  to_name_end(char_u *arg, int namespace)
  {
      char_u    *p;
***************
*** 2988,2994 ****
      *arg = skipwhite(*arg + 1);
      for (;;)
      {
!       char_u *key = NULL;
  
        if (may_get_next_line(whitep, arg, cctx) == FAIL)
        {
--- 2988,2995 ----
      *arg = skipwhite(*arg + 1);
      for (;;)
      {
!       char_u      *key = NULL;
!       char_u      *end;
  
        if (may_get_next_line(whitep, arg, cctx) == FAIL)
        {
***************
*** 2999,3008 ****
        if (**arg == '}')
            break;
  
!       if (literal)
        {
-           char_u *end = to_name_end(*arg, !literal);
- 
            if (end == *arg)
            {
                semsg(_(e_invalid_key_str), *arg);
--- 3000,3013 ----
        if (**arg == '}')
            break;
  
!       // Eventually {name: value} will use "name" as a literal key and
!       // {[expr]: value} for an evaluated key.
!       // Temporarily: if "name" is indeed a valid key, or "[expr]" is
!       // used, use the new method, like JavaScript.  Otherwise fall back
!       // to the old method.
!       end = to_name_end(*arg, FALSE);
!       if (literal || *end == ':')
        {
            if (end == *arg)
            {
                semsg(_(e_invalid_key_str), *arg);
***************
*** 3015,3022 ****
        }
        else
        {
!           isn_T               *isn;
  
            if (compile_expr0(arg, cctx) == FAIL)
                return FAIL;
            isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
--- 3020,3030 ----
        }
        else
        {
!           isn_T       *isn;
!           int         has_bracket = **arg == '[';
  
+           if (has_bracket)
+               *arg = skipwhite(*arg + 1);
            if (compile_expr0(arg, cctx) == FAIL)
                return FAIL;
            isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
***************
*** 3025,3034 ****
            else
            {
                type_T *keytype = ((type_T **)stack->ga_data)
!                                                          [stack->ga_len - 1];
                if (need_type(keytype, &t_string, -1, cctx,
!                                                        FALSE, FALSE) == FAIL)
                    return FAIL;
            }
        }
  
--- 3033,3052 ----
            else
            {
                type_T *keytype = ((type_T **)stack->ga_data)
!                                                      [stack->ga_len - 1];
                if (need_type(keytype, &t_string, -1, cctx,
!                                                    FALSE, FALSE) == FAIL)
!                   return FAIL;
!           }
!           if (has_bracket)
!           {
!               *arg = skipwhite(*arg);
!               if (**arg != ']')
!               {
!                   emsg(_(e_missing_matching_bracket_after_dict_key));
                    return FAIL;
+               }
+               ++*arg;
            }
        }
  
*** ../vim-8.2.2014/src/proto/vim9compile.pro   2020-11-16 20:08:32.395713947 
+0100
--- src/proto/vim9compile.pro   2020-11-18 19:53:42.668140849 +0100
***************
*** 8,13 ****
--- 8,14 ----
  int vim9_comment_start(char_u *p);
  char_u *peek_next_line_from_context(cctx_T *cctx);
  char_u *next_line_from_context(cctx_T *cctx, int skip_comment);
+ char_u *to_name_end(char_u *arg, int namespace);
  char_u *to_name_const_end(char_u *arg);
  exptype_T get_compare_type(char_u *p, int *len, int *type_is);
  void error_white_both(char_u *op, int len);
*** ../vim-8.2.2014/src/errors.h        2020-11-18 17:17:11.961928659 +0100
--- src/errors.h        2020-11-18 19:38:17.834785012 +0100
***************
*** 303,305 ****
--- 303,307 ----
        INIT(= N_("E1137: <Cmd> mapping must not include %s key"));
  EXTERN char e_using_bool_as_number[]
        INIT(= N_("E1138: Using a Bool as a Number"));
+ EXTERN char e_missing_matching_bracket_after_dict_key[]
+       INIT(= N_("E1139: Missing matching bracket after dict key"));
*** ../vim-8.2.2014/src/testdir/test_vim9_expr.vim      2020-11-18 
17:38:59.349902386 +0100
--- src/testdir/test_vim9_expr.vim      2020-11-18 22:03:41.843894713 +0100
***************
*** 1883,1888 ****
--- 1883,1891 ----
    CheckDefAndScriptSuccess(lines)
  enddef
  
+ let g:test_space_dict = {'': 'empty', ' ': 'space'}
+ let g:test_hash_dict = #{one: 1, two: 2}
+ 
  def Test_expr7_dict()
    # dictionary
    var lines =<< trim END
***************
*** 1891,1907 ****
        assert_equal(g:dict_one, {'one': 1})
        var key = 'one'
        var val = 1
!       assert_equal(g:dict_one, {key: val})
  
!       var numbers: dict<number> = #{a: 1, b: 2, c: 3}
        numbers = #{a: 1}
        numbers = #{}
  
!       var strings: dict<string> = #{a: 'a', b: 'b', c: 'c'}
        strings = #{a: 'x'}
        strings = #{}
  
!       var mixed: dict<any> = #{a: 'a', b: 42}
        mixed = #{a: 'x'}
        mixed = #{a: 234}
        mixed = #{}
--- 1894,1910 ----
        assert_equal(g:dict_one, {'one': 1})
        var key = 'one'
        var val = 1
!       assert_equal(g:dict_one, {[key]: val})
  
!       var numbers: dict<number> = {a: 1, b: 2, c: 3}
        numbers = #{a: 1}
        numbers = #{}
  
!       var strings: dict<string> = {a: 'a', b: 'b', c: 'c'}
        strings = #{a: 'x'}
        strings = #{}
  
!       var mixed: dict<any> = {a: 'a', b: 42}
        mixed = #{a: 'x'}
        mixed = #{a: 234}
        mixed = #{}
***************
*** 1915,1920 ****
--- 1918,1926 ----
        dictdict = #{one: #{}, two: #{}}
  
        assert_equal({'': 0}, {matchstr('string', 'wont match'): 0})
+ 
+       assert_equal(g:test_space_dict, {['']: 'empty', [' ']: 'space'})
+       assert_equal(g:test_hash_dict, {one: 1, two: 2})
    END
    CheckDefAndScriptSuccess(lines)
   
***************
*** 1929,1935 ****
    CheckDefFailure(["var x = #{xxx: 1", "var y = 2"], 'E722:', 2)
    CheckDefFailure(["var x = #{xxx: 1,"], 'E723:', 2)
    CheckDefFailure(["var x = {'a': xxx}"], 'E1001:', 1)
!   CheckDefFailure(["var x = {xxx: 8}"], 'E1001:', 1)
    CheckDefFailure(["var x = #{a: 1, a: 2}"], 'E721:', 1)
    CheckDefFailure(["var x = #"], 'E1015:', 1)
    CheckDefExecFailure(["var x = g:anint.member"], 'E715:', 1)
--- 1935,1941 ----
    CheckDefFailure(["var x = #{xxx: 1", "var y = 2"], 'E722:', 2)
    CheckDefFailure(["var x = #{xxx: 1,"], 'E723:', 2)
    CheckDefFailure(["var x = {'a': xxx}"], 'E1001:', 1)
!   CheckDefFailure(["var x = {xx-x: 8}"], 'E1001:', 1)
    CheckDefFailure(["var x = #{a: 1, a: 2}"], 'E721:', 1)
    CheckDefFailure(["var x = #"], 'E1015:', 1)
    CheckDefExecFailure(["var x = g:anint.member"], 'E715:', 1)
*** ../vim-8.2.2014/src/testdir/test_vim9_builtin.vim   2020-11-16 
20:08:32.395713947 +0100
--- src/testdir/test_vim9_builtin.vim   2020-11-18 19:41:39.366247106 +0100
***************
*** 226,232 ****
  
  
  def Wrong_dict_key_type(items: list<number>): list<number>
!   return filter(items, {_, val -> get({val: 1}, 'x')})
  enddef
  
  def Test_filter_wrong_dict_key_type()
--- 226,232 ----
  
  
  def Wrong_dict_key_type(items: list<number>): list<number>
!   return filter(items, {_, val -> get({[val]: 1}, 'x')})
  enddef
  
  def Test_filter_wrong_dict_key_type()
*** ../vim-8.2.2014/src/testdir/test_vim9_func.vim      2020-11-17 
18:50:40.791592326 +0100
--- src/testdir/test_vim9_func.vim      2020-11-18 20:14:06.668096161 +0100
***************
*** 1569,1575 ****
  def TreeWalk(dir: string): list<any>
    return readdir(dir)->map({_, val ->
              fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
!                ? {val: TreeWalk(dir .. '/' .. val)}
                 : val
               })
  enddef
--- 1569,1575 ----
  def TreeWalk(dir: string): list<any>
    return readdir(dir)->map({_, val ->
              fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
!                ? {[val]: TreeWalk(dir .. '/' .. val)}
                 : val
               })
  enddef
*** ../vim-8.2.2014/src/testdir/test_vim9_script.vim    2020-11-04 
15:07:13.057780706 +0100
--- src/testdir/test_vim9_script.vim    2020-11-18 20:16:19.795564731 +0100
***************
*** 416,422 ****
  
    var nd: dict<any>
    try
!     nd = {g:anumber: 1}
    catch /E1012:/
      n = 266
    endtry
--- 416,422 ----
  
    var nd: dict<any>
    try
!     nd = {[g:anumber]: 1}
    catch /E1012:/
      n = 266
    endtry
***************
*** 459,465 ****
    assert_equal(322, n)
  
    try
!     d = {'text': 1, g:astring: 2}
    catch /E721:/
      n = 333
    endtry
--- 459,465 ----
    assert_equal(322, n)
  
    try
!     d = {text: 1, [g:astring]: 2}
    catch /E721:/
      n = 333
    endtry
*** ../vim-8.2.2014/src/version.c       2020-11-19 18:46:19.549796579 +0100
--- src/version.c       2020-11-19 18:51:01.764914357 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2015,
  /**/

-- 
Error:015 - Unable to exit Windows.  Try the door.

 /// Bram Moolenaar -- b...@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    ///

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202011191753.0AJHrn5v412896%40masaka.moolenaar.net.

Raspunde prin e-mail lui