defmodule Zig.Manifest do
# TODO: spec this better
@type t :: term
defmacro resolver(manifest, file \\ nil) do
# TODO: input the file as passed parameter in case we're putting it from a different place.
file =
if file do
file
else
__CALLER__.file
|> Path.dirname()
|> Path.absname()
|> Path.join(".#{__CALLER__.module}.zig")
end
quote do
@__zig_manifest unquote(manifest)
# note that this resolver has to be rebuilt here, so that zigler can be compile-time only.
defp __resolve(%{file_name: file, line: line}), do: __resolve(file, line)
defp __resolve(unquote(file), line),
do: __resolve(@__zig_manifest, [], line)
defp __resolve(file, line) when is_binary(file), do: {file, line}
defp __resolve([{anchor_line, _} = head | rest], stack, line) when anchor_line < line do
__resolve(rest, [head | stack], line)
end
defp __resolve([{anchor_line, {file, _}} | _], stack, line) when anchor_line >= line do
case List.first(stack) do
{anchor, {file, relative_line}} ->
{file, line - anchor + relative_line}
_ ->
{unquote(file), line}
end
end
defp __resolve([], stack, line) do
case List.first(stack) do
{anchor, {file, relative_line}} ->
{file, line - anchor + relative_line}
_ ->
{unquote(file), line}
end
end
end
end
def create(code) do
code
|> String.split("\n")
|> Enum.with_index(1)
|> Enum.flat_map(fn
{"// ref " <> rest, anchor} ->
[file, line] = String.split(rest, ":")
[{anchor, {Path.absname(file), String.to_integer(line)}}]
_ ->
[]
end)
end
def resolve(manifest, file, line) when is_integer(line) do
resolve(manifest, [], file, line)
end
defp resolve([{lesser_line, _} = head | rest], stack, file, line) when lesser_line < line do
resolve(rest, [head | stack], file, line)
end
defp resolve([{bigger_line, _} | _], stack, file, line) when bigger_line >= line do
case List.first(stack) do
{anchor, {new_file, relative_line}} ->
{Path.relative_to_cwd(new_file), line - anchor + relative_line}
_ ->
{file, line}
end
end
defp resolve([], stack, file, line) do
case List.first(stack) do
{anchor, {new_file, relative_line}} ->
{Path.relative_to_cwd(new_file), line - anchor + relative_line}
_ ->
{file, line}
end
end
end