Files
n8n-openai-adapter/lib/elixir/lib/exception.ex
T

227 lines
6.0 KiB
Elixir

defmodule Exception do
@moduledoc """
Several convenience functions to work and pretty print
exceptions and backtraces.
"""
# Normalize an exception converting Erlang exceptions
# to Elixir style exceptions. This is meant to be used
# internally.
@doc false
def normalize(exception) when is_exception(exception) do
exception
end
def normalize(:badarg) do
ArgumentError.new
end
def normalize(:badarith) do
ArithmeticError.new
end
def normalize(:system_limit) do
SystemLimitError.new
end
def normalize({ :badarity, { fun, args } }) do
BadArityError.new(function: fun, args: args)
end
def normalize({ :badfun, actual }) do
BadFunctionError.new(actual: actual)
end
def normalize({ :badmatch, actual }) do
MatchError.new(actual: actual)
end
def normalize({ :case_clause, actual }) do
CaseClauseError.new(actual: actual)
end
def normalize(:undef) do
UndefinedFunctionError.new from_stacktrace(System.stacktrace)
end
def normalize(:function_clause) do
FunctionClauseError.new from_stacktrace(System.stacktrace)
end
def normalize({ :badarg, payload }) do
ArgumentError.new message: "argument error: #{inspect(payload)}"
end
def normalize(other) do
ErlangError.new original: other
end
# Check the given module is a valid record.
@doc false
def check!(module) do
unless :erlang.function_exported(module, :message, 1) do
raise "Expected #{inspect module} to implement message/1"
end
end
@doc """
Receives a module, fun and arity and returns a string
representing such invocation. Arity may also be a list
of arguments. It follows the same syntax as in stacktraces.
"""
def format_module_fun_arity(module, fun, arity) do
case inspect(fun) do
<< ?:, fun :: binary >> -> :ok
fun -> :ok
end
if is_list(arity) do
inspected = lc x inlist arity, do: inspect(x)
"#{inspect module}.#{fun}(#{Enum.join(inspected, ", ")})"
else
"#{inspect module}.#{fun}/#{arity}"
end
end
@doc """
Returns the stacktrace as a binary formatted as per `format_stacktrace/1`.
"""
def formatted_stacktrace(trace // System.stacktrace) do
case trace do
[] -> ""
s -> " " <> Enum.map_join(s, "\n ", format_stacktrace(&1)) <> "\n"
end
end
@doc """
Formats each line in the stacktrace.
"""
def format_stacktrace({module, fun, arity, file_line}) do
"#{format_file_line(file_line)}#{format_module_fun_arity(module, fun, arity)}"
end
@doc """
Formats file and line information present in stacktraces.
Expect them to be given in a keyword list.
"""
def format_file_line(file_line) do
format_file_line(Keyword.get(file_line, :file), Keyword.get(file_line, :line))
end
@doc """
Formats the given file and line.
"""
def format_file_line(file, line) do
if file do
file = to_binary(file)
if line && line != 0 do
"#{file}:#{line}: "
else
"#{file}: "
end
else
""
end
end
## Helpers
defp from_stacktrace([{ module, function, arity, _ }|_]) do
[module: module, function: function, arity: arity]
end
defp from_stacktrace(_), do: []
end
defexception RuntimeError, message: "runtime error"
defexception ArgumentError, message: "argument error"
defexception ArithmeticError, message: "bad argument in arithmetic expression"
defexception SystemLimitError, message: "a system limit has been reached"
defexception SyntaxError, [file: nil, line: nil, description: "syntax error"] do
def message(exception) do
"#{Exception.format_file_line(exception.file, exception.line)}#{exception.description}"
end
end
defexception TokenMissingError, [file: nil, line: nil, description: "expression is incomplete"] do
def message(exception) do
"#{Exception.format_file_line(exception.file, exception.line)}#{exception.description}"
end
end
defexception CompileError, [file: nil, line: nil, description: "compile error"] do
def message(exception) do
"#{Exception.format_file_line(exception.file, exception.line)}#{exception.description}"
end
end
defexception BadFunctionError, [actual: nil] do
def message(exception) do
"bad function: #{inspect(exception.actual)}"
end
end
defexception MatchError, [actual: nil] do
def message(exception) do
"no match of right hand side value: #{inspect(exception.actual)}"
end
end
defexception CaseClauseError, [actual: nil] do
def message(exception) do
"no case clause matching: #{inspect(exception.actual)}"
end
end
defexception BadArityError, [function: nil, args: nil] do
def message(exception) do
"bad arity error: #{inspect(exception.function)} called with #{inspect(exception.args)}"
end
end
defexception UndefinedFunctionError, [module: nil, function: nil, arity: nil] do
def message(exception) do
if exception.function do
formatted = Exception.format_module_fun_arity exception.module, exception.function, to_arity(exception.arity)
"undefined function: #{formatted}"
else
"undefined function"
end
end
defp to_arity(arity) when is_integer(arity), do: arity
defp to_arity(list) when is_list(list), do: length(list)
end
defexception FunctionClauseError, [module: nil, function: nil, arity: nil] do
def message(exception) do
if exception.function do
formatted = Exception.format_module_fun_arity exception.module, exception.function, exception.arity
"no function clause matching: #{formatted}"
else
"no function clause matches"
end
end
end
defexception Protocol.UndefinedError, [protocol: nil, structure: nil] do
def message(exception) do
"protocol #{inspect exception.protocol} not implemented for #{inspect exception.structure}"
end
end
defexception ErlangError, [original: nil] do
def message(exception) do
"erlang error: #{inspect(exception.original)}"
end
end
defexception Keyword.KeyError, key: nil do
def message(exception) do
"key not found: #{inspect exception.key}"
end
end
defexception Enum.OutOfBoundsError, message: "out of bounds error"