Skip to content

Instantly share code, notes, and snippets.

@ConnorRigby
Created September 7, 2022 23:59
Show Gist options
  • Save ConnorRigby/17eead211e46a42b9ce5ee52f9254223 to your computer and use it in GitHub Desktop.
Save ConnorRigby/17eead211e46a42b9ce5ee52f9254223 to your computer and use it in GitHub Desktop.
defmodule Test do
if __ENV__.file != "nofile" do
@original File.read!(__ENV__.file)
end
@doc false
def unquote(:"$handle_undefined_function")(function, args) do
arg_def = Enum.map(1..Enum.count(args)//1, fn i -> {:"_arg_#{i}", [], nil} end)
{:defmodule, meta, [aliases, [{:do, {:__block__, [], ast}}]]} = Code.string_to_quoted!(@original)
ast = Enum.reduce(ast, [], fn
{:def, meta, [{{:unquote, [line: line], [:"$handle_undefined_function"]}, [line: _], [{:function, [line: _], nil}, {:args, [line: _], nil}]}, body]}, acc ->
new = {:def, [line: line], [{function, [line: line], arg_def}, [do: :ok]]}
[{:def, meta, [{{:unquote, [line: line], [:"$handle_undefined_function"]}, [line: line], [{:function, [line: line], nil}, {:args, [line: line], nil}]}, body]}, new | acc]
{:if, meta, [{:!=, [line: line], [{{:., [line: line], [{:__ENV__, [line: line], nil}, :file]}, [no_parens: true, line: line], []}, "nofile"]}, [do: {:@, _, [{:original, _, [{{:., _, [{:__aliases__, _, [:File]}, :read!]}, _, [{{:., _, [{:__ENV__, _, nil}, :file]}, [no_parens: true, line: 3], []}]}]}]}]]}, acc ->
[{:@, meta, [{:original, meta, [@original]}]} | acc]
{name, meta, ast}, acc ->
[{name, meta, ast} | acc]
end)
|> Enum.reverse
{:defmodule, meta, [aliases, [{:do, {:__block__, [], ast}}]]}
|> Code.compile_quoted()
|> Enum.at(0)
|> elem(0)
|> apply(function, args)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment