Skip to content
Draft
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
1 change: 1 addition & 0 deletions apps/engine/mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"schematic": {:hex, :schematic, "0.2.1", "0b091df94146fd15a0a343d1bd179a6c5a58562527746dadd09477311698dbb1", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0b255d65921e38006138201cd4263fd8bb807d9dfc511074615cd264a571b3b1"},
"snowflake": {:hex, :snowflake, "1.0.4", "8433b4e04fbed19272c55e1b7de0f7a1ee1230b3ae31a813b616fd6ef279e87a", [:mix], [], "hexpm", "badb07ebb089a5cff737738297513db3962760b10fe2b158ae3bebf0b4d5be13"},
"sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"},
"spitfire": {:git, "https://github.com/doorgan/spitfire.git", "79b5b25b9ee5a15a3b5b3544252e069076cba6cf", [branch: "doorgan/expert-bugs"]},
"statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
"stream_data": {:hex, :stream_data, "1.2.0", "58dd3f9e88afe27dc38bef26fce0c84a9e7a96772b2925c7b32cd2435697a52b", [:mix], [], "hexpm", "eb5c546ee3466920314643edf68943a5b14b32d1da9fe01698dc92b73f89a9ed"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
Expand Down
1 change: 1 addition & 0 deletions apps/expert/mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"schematic": {:hex, :schematic, "0.2.1", "0b091df94146fd15a0a343d1bd179a6c5a58562527746dadd09477311698dbb1", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0b255d65921e38006138201cd4263fd8bb807d9dfc511074615cd264a571b3b1"},
"snowflake": {:hex, :snowflake, "1.0.4", "8433b4e04fbed19272c55e1b7de0f7a1ee1230b3ae31a813b616fd6ef279e87a", [:mix], [], "hexpm", "badb07ebb089a5cff737738297513db3962760b10fe2b158ae3bebf0b4d5be13"},
"sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"},
"spitfire": {:git, "https://github.com/doorgan/spitfire.git", "79b5b25b9ee5a15a3b5b3544252e069076cba6cf", [branch: "doorgan/expert-bugs"]},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
"typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"},
}
89 changes: 75 additions & 14 deletions apps/forge/lib/forge/ast.ex
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ defmodule Forge.Ast do
@typedoc "Return value from `Code.Fragment.surround_context/3`"
@type surround_context :: any()

@type parse_error ::
{location :: keyword(), String.t() | {String.t(), String.t()}, String.t()}
@type parse_error :: {location :: keyword(), String.t()}

@type patch :: %{
optional(:preserve_indentation) => boolean(),
Expand Down Expand Up @@ -486,21 +485,83 @@ defmodule Forge.Ast do
# private

defp do_string_to_quoted(string) when is_binary(string) do
Code.string_to_quoted_with_comments(string,
literal_encoder: &{:ok, {:__block__, &2, [&1]}},
token_metadata: true,
columns: true,
unescape: false
)
try do
Spitfire.parse_with_comments(string,
literal_encoder: &{:ok, {:__block__, &2, [&1]}},
token_metadata: true,
columns: true,
unescape: false
)
rescue
e in FunctionClauseError ->
{:error, {[line: 1, column: 1], "parser error: #{Exception.message(e)}"}, []}

e in MatchError ->
{:error, {[line: 1, column: 1], "parser error: #{Exception.message(e)}"}, []}

e in CaseClauseError ->
case e.term do
{:error, :no_fuel_remaining} ->
{:error, {[line: 1, column: 1], "parser exhausted fuel"}, []}

_ ->
reraise e, __STACKTRACE__
end
end
|> case do
{:ok, quoted, comments} ->
{:ok, quoted, comments}

{:error, _quoted, comments, errors} ->
first = hd(errors)
{:error, first, comments}

{:error, :no_fuel_remaining} ->
{:error, {[line: 1, column: 1], "parser exhausted fuel"}, []}

{:error, {_location, _message}, _comments} = error ->
error
end
end

defp do_container_cursor_to_quoted(fragment) when is_binary(fragment) do
Code.Fragment.container_cursor_to_quoted(fragment,
literal_encoder: &{:ok, {:__block__, &2, [&1]}},
token_metadata: true,
columns: true,
unescape: false
)
try do
Spitfire.container_cursor_to_quoted(fragment,
literal_encoder: &{:ok, {:__block__, &2, [&1]}},
token_metadata: true,
columns: true,
unescape: false
)
rescue
e in FunctionClauseError ->
{:error, {[line: 1, column: 1], "parser error: #{Exception.message(e)}"}}

e in MatchError ->
{:error, {[line: 1, column: 1], "parser error: #{Exception.message(e)}"}}

e in CaseClauseError ->
case e.term do
{:error, :no_fuel_remaining} ->
{:error, {[line: 1, column: 1], "parser exhausted fuel"}}

_ ->
reraise e, __STACKTRACE__
end
end
|> case do
{:ok, quoted} ->
{:ok, quoted}

{:error, _quoted, errors} ->
first = hd(errors)
{:error, first}

{:error, :no_fuel_remaining} ->
{:error, {[line: 1, column: 1], "parser exhausted fuel"}}

{:error, {_location, _message}} = error ->
error
end
end

defp do_cursor_context(fragment) when is_binary(fragment) do
Expand Down
12 changes: 6 additions & 6 deletions apps/forge/lib/test/detection_case.ex
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ defmodule Forge.Test.DetectionCase do
unquote_splicing(refutations)

def assert_detected(code) do
assert_detected @context, code
assert_detected(@context, code)
end

def refute_detected(code) do
refute_detected @context, code
refute_detected(@context, code)
end
end
end
Expand Down Expand Up @@ -132,7 +132,7 @@ defmodule Forge.Test.DetectionCase do

quote generated: true do
test unquote(test_name) do
assert_detected unquote(context), unquote(assertion_text)
assert_detected(unquote(context), unquote(assertion_text))
end
end
end
Expand Down Expand Up @@ -167,16 +167,16 @@ defmodule Forge.Test.DetectionCase do
end

defp build_refutation_variation(context, type, variation, test) do
{_range, refutation_text} =
{_ranges, refutation_text} =
variation
|> Variations.wrap_with(test)
|> pop_range()
|> pop_all_ranges()

test_name = type_to_name(type, variation)

quote generated: true do
test unquote(test_name) do
refute_detected unquote(context), unquote(refutation_text)
refute_detected(unquote(context), unquote(refutation_text))
end
end
end
Expand Down
1 change: 1 addition & 0 deletions apps/forge/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ defmodule Forge.MixProject do
{:gen_lsp, "~> 0.11"},
{:snowflake, "~> 1.0"},
{:sourceror, "~> 1.9"},
{:spitfire, github: "doorgan/spitfire", branch: "doorgan/expert-bugs"},
{:stream_data, "~> 1.1", only: [:test], runtime: false},
{:patch, "~> 0.15", only: [:test], optional: true, runtime: false}
]
Expand Down
1 change: 1 addition & 0 deletions apps/forge/mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"schematic": {:hex, :schematic, "0.2.1", "0b091df94146fd15a0a343d1bd179a6c5a58562527746dadd09477311698dbb1", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0b255d65921e38006138201cd4263fd8bb807d9dfc511074615cd264a571b3b1"},
"snowflake": {:hex, :snowflake, "1.0.4", "8433b4e04fbed19272c55e1b7de0f7a1ee1230b3ae31a813b616fd6ef279e87a", [:mix], [], "hexpm", "badb07ebb089a5cff737738297513db3962760b10fe2b158ae3bebf0b4d5be13"},
"sourceror": {:hex, :sourceror, "1.9.0", "3bf5fe2d017aaabe3866d8a6da097dd7c331e0d2d54e59e21c2b066d47f1e08e", [:mix], [], "hexpm", "d20a9dd5efe162f0d75a307146faa2e17b823ea4f134f662358d70f0332fed82"},
"spitfire": {:git, "https://github.com/doorgan/spitfire.git", "79b5b25b9ee5a15a3b5b3544252e069076cba6cf", [branch: "doorgan/expert-bugs"]},
"statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
"stream_data": {:hex, :stream_data, "1.1.3", "15fdb14c64e84437901258bb56fc7d80aaf6ceaf85b9324f359e219241353bfb", [:mix], [], "hexpm", "859eb2be72d74be26c1c4f272905667672a52e44f743839c57c7ee73a1a66420"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
Expand Down
13 changes: 8 additions & 5 deletions apps/forge/test/forge/ast_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,15 @@ defmodule Forge.AstTest do
assert path == [{:__cursor__, [closing: [line: 1, column: 12], line: 1, column: 1], []}]
end

test "returns [] when can't parse the AST" do
test "returns cursor path even for incomplete code" do
text = ~q[
foo(bar do baz, [bat|
]

path = cursor_path(text)
assert path == []
# Spitfire's fault-tolerant parsing produces a cursor path
assert length(path) > 0
assert Enum.any?(path, &match?({:__cursor__, _, _}, &1))
end
end

Expand Down Expand Up @@ -89,8 +91,9 @@ defmodule Forge.AstTest do
defmodule |Foo do
]

assert {:error, {metadata, "missing terminator: end" <> _, ""}} = path_at(code)
assert end_location(metadata) == {2, 1}
assert {:error, {metadata, message}, _comments} = path_at(code)
assert is_list(metadata)
assert message =~ "missing" and message =~ "end"
end

test "returns a path to the innermost leaf at position" do
Expand Down Expand Up @@ -309,7 +312,7 @@ defmodule Forge.AstTest do

assert %Analysis{} = analysis = analyze(code)
refute analysis.ast
assert {:error, _} = analysis.parse_error
assert {:error, {_location, _message}, _comments} = analysis.parse_error
end

test "creates an analysis from a document with incomplete `as` section" do
Expand Down
Loading