Current section
Files
Jump to
Current section
Files
src/libero@gen_error.erl
-module(libero@gen_error).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/libero/gen_error.gleam").
-export([error_box/4, print_error/1]).
-export_type([gen_error/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type gen_error() :: {cannot_read_dir, binary(), simplifile:file_error()} |
{cannot_read_file, binary(), simplifile:file_error()} |
{parse_failed, binary(), glance:error()} |
{unresolved_type_module, binary(), binary()} |
{type_not_found, binary(), binary()} |
{type_identity_hash_collision, binary(), binary(), binary()} |
{dict_key_must_be_primitive, binary(), binary()} |
{wire_type_contains_type_var, binary(), binary()} |
{type_resolution_failed, binary(), binary()}.
-file("src/libero/gen_error.gleam", 58).
?DOC(
" Format a structured error as the boxed message libero prints to the\n"
" terminal. `title` is the one-line headline, `path` is the source file\n"
" or context the error refers to (rendered after `┌─`), `body_lines`\n"
" are the explanation lines (each prefixed with `│`), and `hint` is an\n"
" optional remediation tip rendered below a separator.\n"
"\n"
" Used by both typed `GenError` rendering and the TOML parser to keep\n"
" every error in the codebase consistent without duplicating the box\n"
" drawing.\n"
).
-spec error_box(
binary(),
binary(),
list(binary()),
gleam@option:option(binary())
) -> binary().
error_box(Title, Path, Body_lines, Hint) ->
Body = begin
_pipe = Body_lines,
_pipe@1 = gleam@list:map(
_pipe,
fun(Line) -> <<" \x{2502} "/utf8, Line/binary>> end
),
gleam@string:join(_pipe@1, <<"\n"/utf8>>)
end,
Hint_block = case Hint of
none ->
<<""/utf8>>;
{some, H} ->
<<"\n \x{2502}\n hint: "/utf8, H/binary>>
end,
<<<<<<<<<<<<"error: "/utf8, Title/binary>>/binary,
"\n \x{250c}\x{2500} "/utf8>>/binary,
Path/binary>>/binary,
"\n \x{2502}\n"/utf8>>/binary,
Body/binary>>/binary,
Hint_block/binary>>.
-file("src/libero/gen_error.gleam", 193).
?DOC(
" Format a `glance.Error` cause into the body lines of a parse-failure\n"
" box. Surfaces the offending token's source text and its byte offset\n"
" so the user can locate the problem without re-running another tool.\n"
" `byte_offset` is the lexer's offset (codeunit offset on JavaScript).\n"
).
-spec format_glance_error(glance:error()) -> list(binary()).
format_glance_error(Err) ->
case Err of
unexpected_end_of_input ->
[<<"glance hit unexpected end of input while parsing this file"/utf8>>];
{unexpected_token, Tok, {position, Byte_offset}} ->
[<<<<<<"unexpected token `"/utf8,
(glexer@token:to_source(Tok))/binary>>/binary,
"` at byte offset "/utf8>>/binary,
(erlang:integer_to_binary(Byte_offset))/binary>>]
end.
-file("src/libero/gen_error.gleam", 185).
-spec format_file_error(simplifile:file_error()) -> binary().
format_file_error(Err) ->
simplifile:describe_error(Err).
-file("src/libero/gen_error.gleam", 81).
-spec to_string(gen_error()) -> binary().
to_string(Err) ->
case Err of
{cannot_read_dir, Path, Cause} ->
error_box(
<<"Cannot read directory"/utf8>>,
Path,
[format_file_error(Cause)],
none
);
{cannot_read_file, Path@1, Cause@1} ->
error_box(
<<"Cannot read file"/utf8>>,
Path@1,
[format_file_error(Cause@1)],
none
);
{parse_failed, Path@2, Cause@2} ->
error_box(
<<"Failed to parse Gleam source"/utf8>>,
Path@2,
format_glance_error(Cause@2),
{some,
<<"Run `gleam check` to see the full compiler error"/utf8>>}
);
{unresolved_type_module, Module_path, Type_name} ->
error_box(
<<"Unresolved type module"/utf8>>,
Module_path,
[<<<<"Type `"/utf8, Type_name/binary>>/binary,
"` could not be resolved to a file path"/utf8>>],
{some,
<<<<"Ensure the module exists in the source tree.\n Check that `"/utf8,
Module_path/binary>>/binary,
"` is reachable from the file_paths\n passed to walker.walk"/utf8>>}
);
{type_not_found, Module_path@1, Type_name@1} ->
error_box(
<<"Type not found"/utf8>>,
<<Module_path@1/binary, ".gleam"/utf8>>,
[<<<<"Type `"/utf8, Type_name@1/binary>>/binary,
"` was not found in this module"/utf8>>],
{some,
<<"The type may be private (add `pub`) or the module path may be\n incorrect. Libero walks custom types, not type aliases."/utf8>>}
);
{type_identity_hash_collision, Hash, Signature_a, Signature_b} ->
error_box(
<<"Type identity hash collision"/utf8>>,
<<"wire-identity"/utf8>>,
[<<"Two distinct canonical type signatures hash to the same value:"/utf8>>,
<<" Signature A: "/utf8, Signature_a/binary>>,
<<" Signature B: "/utf8, Signature_b/binary>>,
<<" Both hash to: "/utf8, Hash/binary>>],
{some,
<<"This is an extremely rare birthday collision. File a libero\n issue with both canonical signatures so the hash algorithm\n can be adjusted."/utf8>>}
);
{dict_key_must_be_primitive, Field_path, Key_type_repr} ->
error_box(
<<"Unsupported Dict key type"/utf8>>,
Field_path,
[<<<<"Field declares Dict("/utf8, Key_type_repr/binary>>/binary,
", _) but only Int,"/utf8>>,
<<"String, and Bool are allowed as Dict keys on the wire."/utf8>>],
{some,
<<"Use Int/String/Bool keys, or restructure the data as\n List(#(KeyType, ValueType)) and convert at the application\n boundary."/utf8>>}
);
{wire_type_contains_type_var, Field_path@1, Var_name} ->
error_box(
<<"Wire type contains unresolved generic"/utf8>>,
Field_path@1,
[<<<<"Type variable `"/utf8, Var_name/binary>>/binary,
"` survived to runtime in this"/utf8>>,
<<"field. Wire transformer codegen needs concrete types so it can"/utf8>>,
<<"emit per-field encode/decode logic."/utf8>>],
{some,
<<"Replace the generic parameter with a concrete type at the\n wire boundary, or wrap it in a fully-applied user type before\n the value crosses the wire."/utf8>>}
);
{type_resolution_failed, Path@3, Message} ->
error_box(
<<"Failed to resolve Gleam type"/utf8>>,
Path@3,
[Message],
{some,
<<"Check for duplicate or conflicting type imports in this module."/utf8>>}
)
end.
-file("src/libero/gen_error.gleam", 45).
-spec print_error(gen_error()) -> nil.
print_error(Err) ->
gleam_stdlib:println_error(to_string(Err)).