Skip to content

Commit 41c96eb

Browse files
committed
fix: Fix crash in keyword parsing
Add test cases from #32
1 parent f937a7a commit 41c96eb

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

lib/spitfire.ex

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -574,10 +574,15 @@ defmodule Spitfire do
574574

575575
{kvs, parser} =
576576
while2 peek_token(parser) == :"," <- parser do
577-
parser = parser |> next_token() |> next_token()
578-
{pair, parser} = parse_kw_identifier(parser)
579-
580-
{pair, parser}
577+
if kw_identifier?(current_token(parser)) do
578+
parser = parser |> next_token() |> next_token()
579+
{pair, parser} = parse_kw_identifier(parser)
580+
{pair, parser}
581+
else
582+
parser = parser |> next_token() |> next_token()
583+
{item, parser} = parse_expression(parser, @kw_identifier, true, false, false)
584+
{item, parser}
585+
end
581586
end
582587

583588
{[{token, value} | kvs], parser}
@@ -601,16 +606,25 @@ defmodule Spitfire do
601606

602607
{kvs, parser} =
603608
while2 peek_token(parser) == :"," <- parser do
604-
parser = parser |> next_token() |> next_token()
605-
{pair, parser} = parse_kw_identifier(parser)
606-
607-
{pair, parser}
609+
if kw_identifier?(current_token(parser)) do
610+
parser = parser |> next_token() |> next_token()
611+
{pair, parser} = parse_kw_identifier(parser)
612+
{pair, parser}
613+
else
614+
parser = parser |> next_token() |> next_token()
615+
{item, parser} = parse_expression(parser, @kw_identifier, true, false, false)
616+
{item, parser}
617+
end
608618
end
609619

610620
{[{atom, value} | kvs], parser}
611621
end
612622
end
613623

624+
defp kw_identifier?({:kw_identifier, _, _}), do: true
625+
defp kw_identifier?({:kw_identifier_unsafe, _, _}), do: true
626+
defp kw_identifier?(_), do: false
627+
614628
defp parse_assoc_op(%{current_token: {:assoc_op, _, _token}} = parser, key) do
615629
trace "parse_assoc_op", trace_meta(parser) do
616630
assoc_meta = current_meta(parser)

test/spitfire_test.exs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,24 @@ defmodule SpitfireTest do
534534
end
535535
end
536536

537+
test "unfinished keyword list" do
538+
code = ~S'''
539+
defmodule MyModule do
540+
IO.inspect(
541+
:stderr,
542+
label: "label",
543+
(__cursor__())
544+
)
545+
end
546+
'''
547+
548+
assert Spitfire.parse(code) == s2q(code)
549+
550+
code = ~S'foo(a, "#{field}": value, (__cursor__()))'
551+
552+
assert Spitfire.parse(code) == s2q(code)
553+
end
554+
537555
test "another thing" do
538556
code = ~S'''
539557
case foo do
@@ -2909,6 +2927,31 @@ defmodule SpitfireTest do
29092927
]
29102928
}} = Spitfire.container_cursor_to_quoted(code)
29112929
end
2930+
2931+
test "incomplete keyword list" do
2932+
code = "[foo: ]"
2933+
2934+
assert Spitfire.parse(code) ==
2935+
{:error, [{:foo, {:__block__, [error: true, line: 1, column: 7], []}}],
2936+
[{[line: 1, column: 7], "unknown token: ]"}, {[line: 1, column: 1], "missing closing bracket for list"}]}
2937+
end
2938+
2939+
test "incomplete keyword list in module attr" do
2940+
code = """
2941+
@tag foo: bar,
2942+
foo
2943+
"""
2944+
2945+
assert Spitfire.parse(code) ==
2946+
{
2947+
:ok,
2948+
{:@, [end_of_expression: [newlines: 1, line: 2, column: 6], line: 1, column: 1],
2949+
[
2950+
{:tag, [line: 1, column: 2],
2951+
[[{:foo, {:bar, [line: 1, column: 11], nil}}, {:foo, [line: 2, column: 3], nil}]]}
2952+
]}
2953+
}
2954+
end
29122955
end
29132956

29142957
defp s2q(code, opts \\ []) do

0 commit comments

Comments
 (0)