Skip to content

Commit f1f54df

Browse files
committed
Document tuples inside containers, closes #13681
1 parent 2eb85ea commit f1f54df

File tree

2 files changed

+20
-9
lines changed

2 files changed

+20
-9
lines changed

lib/elixir/pages/references/syntax-reference.md

+16-5
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Data structures such as lists, tuples, and binaries are marked respectively by t
7676
7777
Maps use the `%{...}` notation and each key-value is given by pairs marked with `=>`, such as `%{"hello" => 1, 2 => "world"}`.
7878
79-
Both keyword lists (list of two-element tuples where the first element is atom) and maps with atom keys support a keyword notation where the colon character `:` is moved to the end of the atom. `%{hello: "world"}` is equivalent to `%{:hello => "world"}` and `[foo: :bar]` is equivalent to `[{:foo, :bar}]`. This notation is a syntax sugar that emits the same AST representation. It will be explained in later sections.
79+
Both keyword lists (list of two-element tuples where the first element is atom) and maps with atom keys support a keyword notation where the colon character `:` is moved to the end of the atom. `%{hello: "world"}` is equivalent to `%{:hello => "world"}` and `[foo: :bar]` is equivalent to `[{:foo, :bar}]`. We discuss keywords in later sections.
8080
8181
### Structs
8282
@@ -460,15 +460,19 @@ However, Elixir introduces a syntax sugar where the keywords above may be writte
460460
[foo: 1, bar: 2]
461461
```
462462
463-
Atoms with foreign characters, such as whitespace, must be wrapped in quotes. This rule applies to keywords as well:
463+
In order to be valid keyword syntax, `:` cannot be preceded by any whitespace (`foo : 1` is invalid) and has to be followed by whitespace (`foo:1` is invalid). Atoms with foreign characters, such as whitespace, must be wrapped in quotes. This rule applies to keywords as well:
464464
465465
```elixir
466-
[{:"foo bar", 1}, {:"bar baz", 2}] == ["foo bar": 1, "bar baz": 2]
466+
["foo bar": 1, "bar baz": 2] == [{:"foo bar", 1}, {:"bar baz", 2}]
467467
```
468468
469-
Remember that, because lists and two-element tuples are quoted literals, by definition keywords are also literals (in fact, the only reason tuples with two elements are quoted literals is to support keywords as literals).
469+
You can also mix regular list elements with keywords, but keywords must come last:
470470
471-
In order to be valid keyword syntax, `:` cannot be preceded by any whitespace (`foo : 1` is invalid) and has to be followed by whitespace (`foo:1` is invalid).
471+
```elixir
472+
[:foo, :bar, baz: :bat] == [:foo, :bar, {:baz, :bat}]
473+
```
474+
475+
Finally, because lists and two-element tuples are quoted literals, by definition keywords are also literals.
472476
473477
### Keywords as last arguments
474478
@@ -490,6 +494,13 @@ which, as per the previous section, is the same as
490494
if(condition, [{:do, this}, {:else, that}])
491495
```
492496
497+
This same notation is available inside containers (such as `{...}`, `%{...}`, etc) as well:
498+
499+
```elixir
500+
{:foo, :bar, baz: :bat} == {:foo, :bar, {:baz, :bat}}
501+
%{:foo => :bar, baz: :bat} == %{:foo => :bar, :baz => :bat}}
502+
```
503+
493504
### `do`-`end` blocks
494505
495506
The last syntax convenience are `do`-`end` blocks. `do`-`end` blocks are equivalent to keywords as the last argument of a function call, where the block contents are wrapped in parentheses. For example:

lib/elixir/src/elixir_parser.yrl

+4-4
Original file line numberDiff line numberDiff line change
@@ -591,13 +591,13 @@ list -> open_bracket list_args close_bracket : build_list('$1', '$2', '$3').
591591
% Tuple
592592

593593
tuple -> open_curly '}' : build_tuple('$1', [], '$2').
594-
tuple -> open_curly kw_data '}' : bad_keyword('$1', tuple).
594+
tuple -> open_curly kw_data '}' : bad_keyword('$1', tuple, "'{'").
595595
tuple -> open_curly container_args close_curly : build_tuple('$1', '$2', '$3').
596596

597597
% Bitstrings
598598

599599
bitstring -> open_bit '>>' : build_bit('$1', [], '$2').
600-
bitstring -> open_bit kw_data '>>' : bad_keyword('$1', bitstring).
600+
bitstring -> open_bit kw_data '>>' : bad_keyword('$1', bitstring, "'<<'").
601601
bitstring -> open_bit container_args close_bit : build_bit('$1', '$2', '$3').
602602

603603
% Map and structs
@@ -1118,11 +1118,11 @@ error_bad_atom(Token) ->
11181118
"If the '.' was meant to be part of the atom's name, "
11191119
"the atom name must be quoted. Syntax error before: ", "'.'").
11201120

1121-
bad_keyword(Token, Context) ->
1121+
bad_keyword(Token, Context, StartString) ->
11221122
return_error(?location(Token),
11231123
"unexpected keyword list inside " ++ atom_to_list(Context) ++ ". "
11241124
"Did you mean to write a map (using %{...}) or a list (using [...]) instead? "
1125-
"Syntax error after: ", "'{'").
1125+
"Syntax error after: ", StartString).
11261126

11271127
maybe_bad_keyword_call_follow_up(_Token, KW, {'__cursor__', _, []} = Expr) ->
11281128
reverse([Expr | KW]);

0 commit comments

Comments
 (0)