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 -- 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 ///