Some initial reactions to this syntax:
-
the
=inside the brackets feels strange, but that may be because it makes me think of Ruby’s default argument syntax. -
having a
din the “pattern” but then not failing to match feels odd compared to matching the literal forms where those keys are required to match
A less vibes-based issue I encountered trying this out is that it fails if a default expression calls a function with two arguments:
iex(3)> opts = [a: 1, b: 2]
[a: 1, b: 2]
iex(4)> ~k{a, b, c: Integer.pow(2, 4) = opts}
** (DarkKernel.DarkKeywords.InvalidKeywordError) Invalid keyword: 4)
Keywords must be valid Elixir variable names and contain only ASCII characters.
They can be preceded by a bang (e.g. `!key`) or contain a default value (e.g. `key: default`).
(dark_kernel 0.1.0) lib/dark_kernel/dark_keywords.ex:116: anonymous fn/2 in DarkKernel.DarkKeywords.parse_keyword_match/1
(elixir 1.14.0) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(dark_kernel 0.1.0) lib/dark_kernel/dark_keywords.ex:103: DarkKernel.DarkKeywords.parse_keyword_match/1
(dark_kernel 0.1.0) lib/dark_kernel/dark_keywords.ex:193: DarkKernel.DarkKeywords.do_match_keywords/1
(dark_kernel 0.1.0) expanding macro: DarkKernel.sigil_k/2
iex:4: (file)
or if a default argument is a literal with a comma in it:
iex(4)> ~k{a, b, c: "Hello, world!" = opts}
** (DarkKernel.DarkKeywords.InvalidKeywordError) Invalid keyword: world!"
Keywords must be valid Elixir variable names and contain only ASCII characters.
They can be preceded by a bang (e.g. `!key`) or contain a default value (e.g. `key: default`).
(dark_kernel 0.1.0) lib/dark_kernel/dark_keywords.ex:116: anonymous fn/2 in DarkKernel.DarkKeywords.parse_keyword_match/1
(elixir 1.14.0) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(dark_kernel 0.1.0) lib/dark_kernel/dark_keywords.ex:103: DarkKernel.DarkKeywords.parse_keyword_match/1
(dark_kernel 0.1.0) lib/dark_kernel/dark_keywords.ex:193: DarkKernel.DarkKeywords.do_match_keywords/1
(dark_kernel 0.1.0) expanding macro: DarkKernel.sigil_k/2
iex:4: (file)
In at least these two cases, Code.string_to_quoted! could be helpful if you wrap the whole expression passed to ~k in [ ]:
iex(5)> Code.string_to_quoted!("[a, b, c: \"Hello, world!\" = opts]")
[
{:a, [line: 1], nil},
{:b, [line: 1], nil},
{:c, {:=, [line: 1], ["Hello, world!", {:opts, [line: 1], nil}]}}
]
iex(6)> Code.string_to_quoted!("[a, b, c: Integer.pow(2, 4) = opts]")
[
{:a, [line: 1], nil},
{:b, [line: 1], nil},
{:c,
{:=, [line: 1],
[
{{:., [line: 1], [{:__aliases__, [line: 1], [:Integer]}, :pow]},
[line: 1], [2, 4]},
{:opts, [line: 1], nil}
]}}
]
A little (ok, probably LOTS) of pattern matching should be able to split / transform these into the output AST. It could even support cases like two equals signs that currently raise an exception:
iex(8)> Code.string_to_quoted!("[!a, b: (_ = 1 + 2) = opts]")
[
{:!, [line: 1], [{:a, [line: 1], nil}]},
{:b,
{:=, [line: 1],
[
{:=, [line: 1], [{:_, [line: 1], nil}, {:+, [line: 1], [1, 2]}]},
{:opts, [line: 1], nil}
]}}
]


















