Skip to content

Commit df7732f

Browse files
authored
fix: don't encode errors directly into AST (#27)
1 parent 555b977 commit df7732f

File tree

2 files changed

+89
-21
lines changed

2 files changed

+89
-21
lines changed

lib/spitfire.ex

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,15 @@ defmodule Spitfire do
178178
{ast, parser} = parse_expression(parser, @lowest, false, false, true)
179179

180180
parser =
181-
if peek_token(parser) in [:eol, :eof] and parser.tokens != :eot do
182-
next_token(parser)
183-
else
184-
parser
181+
cond do
182+
match?({:__block__, [{:error, true} | _], _}, ast) ->
183+
next_token(parser)
184+
185+
peek_token(parser) in [:eol, :eof] and parser.tokens != :eot ->
186+
next_token(parser)
187+
188+
true ->
189+
parser
185190
end
186191

187192
ast = push_eoe(ast, current_eoe(parser))
@@ -272,7 +277,7 @@ defmodule Spitfire do
272277
_ -> next_token(parser)
273278
end
274279

275-
{{:__error__, meta, ["unknown token: #{ctype}"]}, parser}
280+
{{:__block__, [{:error, true} | meta], []}, parser}
276281
else
277282
{left, parser} = prefix.(parser)
278283

@@ -289,7 +294,6 @@ defmodule Spitfire do
289294
while is_nil(Map.get(parser, :stab_state)) and not MapSet.member?(terminals, peek_token(parser)) &&
290295
(current_token(parser) != :do and peek_token(parser) != :eol) &&
291296
calc_prec(parser, associativity, precedence) <- {left, parser} do
292-
# dbg(parser)
293297
parser = consume_fuel(parser)
294298
peek_token_type = peek_token_type(parser)
295299

@@ -476,8 +480,7 @@ defmodule Spitfire do
476480
|> put_error({meta, "missing closing parentheses"})
477481
|> Map.put(:nesting, old_nesting)
478482

479-
# FIXME: we shouldn't emit errors into the actual ast, just stickem in the parser
480-
{{:__error__, meta, ["missing closing parentheses"]}, next_token(parser)}
483+
{{:__block__, [{:error, true} | meta], []}, next_token(parser)}
481484
end
482485

483486
true ->
@@ -488,7 +491,7 @@ defmodule Spitfire do
488491
|> put_error({meta, "missing closing parentheses"})
489492
|> Map.put(:nesting, old_nesting)
490493

491-
{{:__error__, meta, ["missing closing parentheses"]}, next_token(parser)}
494+
{{:__block__, [{:error, true} | meta], []}, next_token(parser)}
492495
end
493496
end
494497
end
@@ -782,9 +785,9 @@ defmodule Spitfire do
782785

783786
{rhs, parser} =
784787
case rhs do
785-
{:__error__, _, ["unknown token:" <> _]} ->
788+
{:__block__, [{:error, true} | _], []} ->
786789
parser = put_error(pre_parser, {meta, "malformed right-hand side of #{token} operator"})
787-
{{:__error__, meta, ["malformed right-hand side of #{token} operator"]}, parser}
790+
{{:__block__, [{:error, true} | meta], []}, parser}
788791

789792
_ ->
790793
{rhs, parser}
@@ -1407,7 +1410,7 @@ defmodule Spitfire do
14071410

14081411
{pairs, parser} =
14091412
with [{potential_error, parser}, {item, parser_for_errors} | rest] <- all_pairs,
1410-
{:__error__, _, ["unknown token: " <> _]} <- potential_error do
1413+
{:__block__, [{:error, true} | _], []} <- potential_error do
14111414
{[{item, parser} | rest],
14121415
parser
14131416
|> put_in([:current_token], {:fake_closing_bracket, nil})
@@ -1518,7 +1521,7 @@ defmodule Spitfire do
15181521
_ -> next_token(parser)
15191522
end
15201523

1521-
{{:__error__, meta, ["unknown token: #{ctype}"]}, parser}
1524+
{{:__block__, [], []}, parser}
15221525
else
15231526
{left, parser} = prefix.(parser)
15241527

@@ -1653,7 +1656,7 @@ defmodule Spitfire do
16531656

16541657
{pairs, parser} =
16551658
with [{potential_error, parser}, {item, parser_for_errors} | rest] <- all_pairs,
1656-
{:__error__, _, ["unknown token: " <> _]} <- potential_error do
1659+
{:__block__, [{:error, true} | _], []} <- potential_error do
16571660
{[{item, parser} | rest],
16581661
parser
16591662
|> put_in([:current_token], {:fake_closing_brace, nil})
@@ -1745,7 +1748,7 @@ defmodule Spitfire do
17451748

17461749
{pairs, parser} =
17471750
with [{potential_error, parser}, {item, parser_for_errors} | rest] <- all_pairs,
1748-
{:__error__, _, ["unknown token: " <> _]} <- potential_error do
1751+
{:__block__, [{:error, true} | _meta], []} <- potential_error do
17491752
{[{item, parser} | rest],
17501753
parser
17511754
|> put_in([:current_token], {:fake_closing_bracket, nil})

test/spitfire_test.exs

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,7 +1927,7 @@ defmodule SpitfireTest do
19271927
code = "foo $bar, baz"
19281928

19291929
assert Spitfire.parse(code) ==
1930-
{:error, {:foo, [line: 1, column: 1], [{:__error__, [line: 1, column: 5], ["unknown token: %"]}]},
1930+
{:error, {:foo, [line: 1, column: 1], [{:__block__, [error: true, line: 1, column: 5], []}]},
19311931
[{[line: 1, column: 5], "unknown token: %"}]}
19321932
end
19331933

@@ -1949,9 +1949,15 @@ defmodule SpitfireTest do
19491949
code = "1 * (2 + 3"
19501950

19511951
assert Spitfire.parse(code) ==
1952-
{:error,
1953-
{:*, [line: 1, column: 3], [1, {:__error__, [line: 1, column: 10], ["missing closing parentheses"]}]},
1954-
[{[line: 1, column: 10], "missing closing parentheses"}]}
1952+
{
1953+
:error,
1954+
{{:*, [line: 1, column: 3], [1, {:__block__, [error: true, line: 1, column: 3], []}]},
1955+
[{:closing, [line: 1, column: 10]}, {:line, 1}, {:column, 3}], [{:+, [line: 1, column: 8], [2, 3]}]},
1956+
[
1957+
{[line: 1, column: 3], "malformed right-hand side of * operator"},
1958+
{[line: 1, column: 3], "missing closing parentheses for function invocation"}
1959+
]
1960+
}
19551961
end
19561962

19571963
test "missing closing list bracket" do
@@ -1968,6 +1974,13 @@ defmodule SpitfireTest do
19681974

19691975
assert Spitfire.parse(code) ==
19701976
{:error, {:__block__, [], [[1], :ok]}, [{[line: 1, column: 1], "missing closing bracket for list"}]}
1977+
1978+
code = """
1979+
[1, 2, 3,,
1980+
"""
1981+
1982+
assert Spitfire.parse(code) ==
1983+
{:error, [1, 2, 3], [{[line: 1, column: 1], "missing closing bracket for list"}]}
19711984
end
19721985

19731986
test "missing closing tuple brace" do
@@ -2149,8 +2162,7 @@ defmodule SpitfireTest do
21492162
column: 1
21502163
],
21512164
[
2152-
{:+, [line: 1, column: 7],
2153-
[1, {:__error__, [line: 1, column: 7], ["malformed right-hand side of + operator"]}]}
2165+
{:+, [line: 1, column: 7], [1, {:__block__, [error: true, line: 1, column: 7], []}]}
21542166
]},
21552167
{:bar,
21562168
[
@@ -2430,6 +2442,59 @@ defmodule SpitfireTest do
24302442
assert Spitfire.parse(code) == {:error, :no_fuel_remaining}
24312443
end
24322444

2445+
test "doesn't drop the cursor node" do
2446+
code =
2447+
~S'''
2448+
%{state |
2449+
foo: s
2450+
__cursor__()
2451+
,
2452+
bar: Foo.Bar.load(state.foo, state.baz)}
2453+
'''
2454+
2455+
assert Spitfire.parse(code) ==
2456+
{:error,
2457+
{:__block__, [],
2458+
[
2459+
{:%{}, [closing: [line: 2, column: 8], line: 1, column: 1],
2460+
[
2461+
{:|, [newlines: 1, line: 1, column: 9],
2462+
[
2463+
{:state, [line: 1, column: 3], nil},
2464+
[foo: {:s, [line: 2, column: 8], nil}]
2465+
]}
2466+
]},
2467+
{:s, [end_of_expression: [newlines: 1, line: 3, column: 13], line: 2, column: 8],
2468+
[{:__cursor__, [closing: [line: 3, column: 12], line: 3, column: 1], []}]},
2469+
{:__block__, [error: true, line: 4, column: 1], []},
2470+
{{:., [line: 5, column: 15],
2471+
[
2472+
{:__aliases__, [last: [line: 5, column: 12], line: 5, column: 8], [:Foo, :Bar]},
2473+
:load
2474+
]}, [closing: [line: 5, column: 41], line: 5, column: 16],
2475+
[
2476+
{{:., [line: 5, column: 26], [{:state, [line: 5, column: 21], nil}, :foo]},
2477+
[no_parens: true, line: 5, column: 27], []},
2478+
{{:., [line: 5, column: 37], [{:state, [line: 5, column: 32], nil}, :baz]},
2479+
[no_parens: true, line: 5, column: 38], []}
2480+
]},
2481+
{:__block__, [error: true, line: 5, column: 41], []},
2482+
{:__block__,
2483+
[
2484+
end_of_expression: [newlines: 1, line: 5, column: 43],
2485+
error: true,
2486+
line: 5,
2487+
column: 42
2488+
], []}
2489+
]},
2490+
[
2491+
{[line: 2, column: 8], "missing closing brace for map"},
2492+
{[line: 4, column: 1], "unknown token: ,"},
2493+
{[line: 5, column: 41], "unknown token: )"},
2494+
{[line: 5, column: 42], "unknown token: }"}
2495+
]}
2496+
end
2497+
24332498
test "example from github issue with list elements" do
24342499
code = ~S'''
24352500
defmodule Foo do

0 commit comments

Comments
 (0)