Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 29 additions & 14 deletions lib/spitfire.ex
Original file line number Diff line number Diff line change
Expand Up @@ -625,13 +625,7 @@ defmodule Spitfire do

{value, parser} = parse_expression(parser, @kw_identifier, false, false, false)

{kvs, parser} =
while2 peek_token(parser) == :"," <- parser do
parser = parser |> next_token() |> next_token()
{pair, parser} = parse_kw_identifier(parser)

{pair, parser}
end
{kvs, parser} = parse_kw_list_continuation(parser)

{[{token, value} | kvs], parser}
end
Expand All @@ -652,18 +646,39 @@ defmodule Spitfire do

{value, parser} = parse_expression(parser, @kw_identifier, false, false, false)

{kvs, parser} =
while2 peek_token(parser) == :"," <- parser do
parser = parser |> next_token() |> next_token()
{pair, parser} = parse_kw_identifier(parser)

{pair, parser}
end
{kvs, parser} = parse_kw_list_continuation(parser)

{[{atom, value} | kvs], parser}
end
end

defp parse_kw_list_continuation(parser) do
while2 peek_token(parser) == :"," <- parser do
parser = parser |> next_token() |> next_token()

case current_token_type(parser) do
type when type in [:kw_identifier, :kw_identifier_unsafe] ->
parse_kw_identifier(parser)

_ ->
parser =
if match?({:paren_identifier, _, :__cursor__}, parser.current_token) do
parser
else
put_error(
parser,
{current_meta(parser),
"unexpected expression after keyword list. Keyword lists must always come as the last argument. " <>
"Therefore, this is not allowed:\n\n function_call(1, some: :option, 2)\n\n" <>
"Instead, wrap the keyword in brackets:\n\n function_call(1, [some: :option], 2)"}
)
end

parse_expression(parser, @kw_identifier, true, false, false)
end
end
end

defp parse_assoc_op(%{current_token: {:assoc_op, _, _token}} = parser, key) do
trace "parse_assoc_op", trace_meta(parser) do
assoc_meta = current_meta(parser)
Expand Down
25 changes: 25 additions & 0 deletions test/spitfire_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2805,6 +2805,31 @@ defmodule SpitfireTest do
}
end

test "unexpected expression after keyword list" do
assert {:error, _ast, errors} = Spitfire.parse(~S|foo(a: 1, b)|)

assert Enum.any?(errors, fn {_, msg} ->
String.contains?(msg, "unexpected expression after keyword list")
end)

assert {:error, _ast, errors} = Spitfire.parse(~S|foo(a: 1, :bar)|)

assert Enum.any?(errors, fn {_, msg} ->
String.contains?(msg, "unexpected expression after keyword list")
end)

assert {:error, _ast, errors} = Spitfire.parse(~S|@tag foo: bar, baz|)

assert Enum.any?(errors, fn {_, msg} ->
String.contains?(msg, "unexpected expression after keyword list")
end)
end

test "__cursor__ after keyword list does not crash" do
code = ~S|foo(a: 1, __cursor__())|
assert {:ok, {:foo, _, [[{:a, 1}, {:__cursor__, _, []}]]}} = Spitfire.parse(code)
end

test "weird characters" do
code = """
[«]
Expand Down
Loading