-module(graded). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/graded.gleam"). -export([infer_path_dep/2, run/1, run_format/1, run_format_check/1, run_format_stdin/1, run_infer/1, main/0]). -export_type([graded_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. ?MODULEDOC( " Effect checker for Gleam via sidecar `.graded` annotation files.\n" "\n" " graded verifies that your Gleam functions respect their declared effect\n" " budgets. Annotations live in `.graded` sidecar files alongside your source\n" " — your Gleam code stays clean.\n" "\n" " ## Usage\n" "\n" " ```sh\n" " gleam run -m graded check [directory] # enforce check annotations (default)\n" " gleam run -m graded infer [directory] # infer and write effect annotations\n" " gleam run -m graded format [directory] # normalize .graded file formatting\n" " ```\n" "\n" " ## Programmatic API\n" "\n" " Use `run` to check a directory and get back a list of `CheckResult` values,\n" " each containing any violations found per file. Use `run_infer` to infer\n" " effects and write `.graded` files.\n" "\n" ). -type graded_error() :: {directory_read_error, binary(), simplifile:file_error()} | {file_read_error, binary(), simplifile:file_error()} | {file_write_error, binary(), simplifile:file_error()} | {directory_create_error, binary(), simplifile:file_error()} | {gleam_parse_error, binary(), glance:error()} | {graded_parse_error, binary(), graded@internal@annotation:parse_error()} | {invalid_config, binary(), graded@internal@config:config_error()} | {format_check_failed, list(binary())} | {cyclic_imports, list(binary())}. -file("src/graded.gleam", 1255). -spec target_directory(list(binary())) -> binary(). target_directory(Arguments) -> case Arguments of [Directory | _] -> Directory; [] -> <<"src"/utf8>> end. -file("src/graded.gleam", 1322). -spec format_error(graded_error()) -> binary(). format_error(Error) -> case Error of {directory_read_error, Path, _} -> <<"Could not read directory: "/utf8, Path/binary>>; {file_read_error, Path@1, _} -> <<"Could not read: "/utf8, Path@1/binary>>; {file_write_error, Path@2, _} -> <<"Could not write: "/utf8, Path@2/binary>>; {directory_create_error, Path@3, _} -> <<"Could not create directory: "/utf8, Path@3/binary>>; {gleam_parse_error, Path@4, _} -> <<"Could not parse: "/utf8, Path@4/binary>>; {graded_parse_error, Path@5, _} -> <<"Parse error in .graded file for: "/utf8, Path@5/binary>>; {invalid_config, Path@6, _} -> <<"Invalid gleam.toml: "/utf8, Path@6/binary>>; {format_check_failed, Paths} -> <<"Unformatted .graded files:\n"/utf8, (gleam@string:join( gleam@list:map( Paths, fun(Path@7) -> <<" "/utf8, Path@7/binary>> end ), <<"\n"/utf8>> ))/binary>>; {cyclic_imports, Modules} -> <<"Cyclic project imports detected (this should be unreachable — Gleam disallows circular imports):\n"/utf8, (gleam@string:join( gleam@list:map( Modules, fun(M) -> <<" "/utf8, M/binary>> end ), <<"\n"/utf8>> ))/binary>> end. -file("src/graded.gleam", 1346). -spec print_violation(binary(), graded@internal@types:violation()) -> nil. print_violation(File, Violation) -> Base = <<<<<<<<<<<<<<<<<<<>/binary, (erlang:element(2, Violation))/binary>>/binary, " calls "/utf8>>/binary, (erlang:element(2, erlang:element(3, Violation)))/binary>>/binary, "."/utf8>>/binary, (erlang:element(3, erlang:element(3, Violation)))/binary>>/binary, " with effects "/utf8>>/binary, (graded@internal@effects:format_effect_set( erlang:element(6, Violation) ))/binary>>/binary, " but declared "/utf8>>/binary, (graded@internal@effects:format_effect_set(erlang:element(5, Violation)))/binary>>, Hint = case graded@internal@types:has_variables( erlang:element(6, Violation) ) of true -> <<<<<<"\n hint: actual effects contain unresolved variables; add a `check "/utf8, (erlang:element(2, Violation))/binary>>/binary, "(: [...])` bound, or pass a function reference / constructor"/utf8>>/binary, " whose effects are known"/utf8>>; false -> <<""/utf8>> end, gleam_stdlib:println(<>). -file("src/graded.gleam", 1340). -spec print_violations(graded@internal@types:check_result()) -> nil. print_violations(Check_result) -> gleam@list:each( erlang:element(3, Check_result), fun(Violation) -> print_violation(erlang:element(2, Check_result), Violation) end ). -file("src/graded.gleam", 1379). -spec print_warning(binary(), graded@internal@types:warning()) -> nil. print_warning(File, Warning) -> case Warning of {untracked_effect_warning, Function, Reference, _, Effs} -> gleam_stdlib:println( <<<<<<<<<<<<<<<<<>/binary, Function/binary>>/binary, " passes "/utf8>>/binary, (erlang:element(2, Reference))/binary>>/binary, "."/utf8>>/binary, (erlang:element(3, Reference))/binary>>/binary, " as a value — its effects "/utf8>>/binary, (graded@internal@effects:format_effect_set(Effs))/binary>>/binary, " won't be tracked"/utf8>> ); {unmatched_field_bound_warning, Function@1, Field_path, Receiver_is_param} -> Cause = case Receiver_is_param of true -> <<" matches no field call in its body — check the path"/utf8>>; false -> <<<<<<" matches no field call in its body — check the path,"/utf8, " or the receiver is traced to a construction site and resolved"/utf8>>/binary, " through value provenance (field bounds apply only to untraceable"/utf8>>/binary, " receivers)"/utf8>> end, gleam_stdlib:println( <<<<<<<<<>/binary, Field_path/binary>>/binary, " on "/utf8>>/binary, Function@1/binary>>/binary, Cause/binary>> ); {unmatched_param_bound_warning, Function@2, Param} -> gleam_stdlib:println( <<<<<<<<<>/binary, Param/binary>>/binary, " on "/utf8>>/binary, Function@2/binary>>/binary, " names no parameter of the function — check the name"/utf8>> ) end. -file("src/graded.gleam", 1373). -spec print_warnings(graded@internal@types:check_result()) -> nil. print_warnings(Check_result) -> gleam@list:each( erlang:element(4, Check_result), fun(Warning) -> print_warning(erlang:element(2, Check_result), Warning) end ). -file("src/graded.gleam", 917). -spec check_one_file( binary(), glance:module_(), list(graded@internal@types:effect_annotation()), graded@internal@effects:knowledge_base(), graded@internal@signatures:signature_registry(), gleam@dict:dict({integer(), integer()}, girard@types:type()), gleam@dict:dict(binary(), gleam@set:set(binary())) ) -> graded@internal@types:check_result(). check_one_file( Gleam_path, Module, Module_checks, Knowledge_base, Registry, Module_types, Girard_fn_typed ) -> {Violations, Warnings} = graded@internal@checker:check( Module, Module_checks, Knowledge_base, Registry, Module_types, Girard_fn_typed ), {check_result, Gleam_path, Violations, Warnings}. -file("src/graded.gleam", 429). -spec qualify_by_module( gleam@dict:dict(binary(), {binary(), glance:module_()}), fun((glance:module_()) -> gleam@dict:dict(binary(), TKV)) ) -> gleam@dict:dict({binary(), binary()}, TKV). qualify_by_module(Index, Per_module) -> gleam@dict:fold( Index, maps:new(), fun(Acc, Path, Entry) -> {_, Module} = Entry, gleam@dict:fold( Per_module(Module), Acc, fun(Inner, Name, Value) -> gleam@dict:insert(Inner, {Path, Name}, Value) end ) end ). -file("src/graded.gleam", 530). -spec merge_field_effect( graded@internal@types:type_field_effect(), graded@internal@types:type_field_effect() ) -> graded@internal@types:type_field_effect(). merge_field_effect(Existing, New) -> {Bounds, Source} = case erlang:element(4, Existing) of {some, _} -> {erlang:element(3, Existing), erlang:element(4, Existing)}; none -> {erlang:element(3, New), erlang:element(4, New)} end, {type_field_effect, graded@internal@effect_term:normalize( {t_union, [erlang:element(2, Existing), erlang:element(2, New)]} ), Bounds, Source}. -file("src/graded.gleam", 516). -spec field_value_function(graded@internal@types:argument_value(), binary()) -> gleam@option:option(graded@internal@types:qualified_name()). field_value_function(Value, Module_path) -> case Value of {function_ref, Name} -> {some, Name}; {local_ref, Name@1} -> {some, {qualified_name, Module_path, Name@1}}; _ -> none end. -file("src/graded.gleam", 476). -spec field_effect_of( graded@internal@effects:knowledge_base(), graded@internal@types:argument_value(), binary(), fun((list(binary()), list(glance:statement())) -> graded@internal@types:effect_term()) ) -> graded@internal@types:type_field_effect(). field_effect_of(Knowledge_base, Value, Module_path, Closure_effect) -> case field_value_function(Value, Module_path) of {some, Name} -> Field_effects = graded@internal@effects:lookup_effects( Knowledge_base, Name ), case gleam@set:is_empty( graded@internal@effect_term:free_vars(Field_effects) ) of true -> {type_field_effect, Field_effects, [], none}; false -> {type_field_effect, Field_effects, graded@internal@effects:lookup_param_bounds( Knowledge_base, Name ), {some, Name}} end; none -> case Value of {closure, Params, Body} -> {type_field_effect, Closure_effect(Params, Body), [], none}; _ -> {type_field_effect, graded@internal@effects:argument_value_effects( Knowledge_base, Value ), [], none} end end. -file("src/graded.gleam", 446). -spec accumulate_constructor_binding( gleam@dict:dict({binary(), binary(), binary()}, graded@internal@types:type_field_effect()), graded@internal@extract:constructor_binding(), gleam@dict:dict({binary(), binary()}, binary()), graded@internal@effects:knowledge_base(), binary(), fun((list(binary()), list(glance:statement())) -> graded@internal@types:effect_term()) ) -> gleam@dict:dict({binary(), binary(), binary()}, graded@internal@types:type_field_effect()). accumulate_constructor_binding( Acc, Binding, Constructor_types, Knowledge_base, Module_path, Closure_effect ) -> {constructor_binding, Binding_module, Constructor, Fields} = Binding, Module = gleam@option:unwrap(Binding_module, Module_path), case gleam_stdlib:map_get(Constructor_types, {Module, Constructor}) of {error, nil} -> Acc; {ok, Type_name} -> gleam@dict:fold( Fields, Acc, fun(Inner, Label, Value) -> Field_effect = field_effect_of( Knowledge_base, Value, Module_path, Closure_effect ), Key = {Module, Type_name, Label}, Merged = case gleam_stdlib:map_get(Inner, Key) of {ok, Existing} -> merge_field_effect(Existing, Field_effect); {error, nil} -> Field_effect end, gleam@dict:insert(Inner, Key, Merged) end ) end. -file("src/graded.gleam", 371). -spec build_constructor_field_index( gleam@dict:dict(binary(), {binary(), glance:module_()}), graded@internal@effects:knowledge_base() ) -> list({{binary(), binary(), binary()}, graded@internal@types:type_field_effect()}). build_constructor_field_index(Index, Knowledge_base) -> Constructor_types = qualify_by_module( Index, fun graded@internal@extract:build_constructor_type_map/1 ), Cross_constructors = qualify_by_module( Index, fun graded@internal@extract:constructor_label_map/1 ), _pipe@2 = gleam@dict:fold( Index, maps:new(), fun(Acc, Path, Entry) -> {_, Module} = Entry, Context = begin _pipe = graded@internal@extract:build_import_context(Module), graded@internal@extract:with_cross_constructors( _pipe, Cross_constructors ) end, Function_map = graded@internal@checker:build_function_map(Module), Scc_ids = graded@internal@checker:build_scc_ids( Module, Context, maps:new(), false ), Closure_effect = fun(Params, Body) -> graded@internal@checker:closure_field_operator( Params, Body, Context, Function_map, Knowledge_base, Scc_ids ) end, _pipe@1 = graded@internal@extract:collect_constructor_bindings( Module, Context ), gleam@list:fold( _pipe@1, Acc, fun(Inner, Binding) -> accumulate_constructor_binding( Inner, Binding, Constructor_types, Knowledge_base, Path, Closure_effect ) end ) end ), maps:to_list(_pipe@2). -file("src/graded.gleam", 1116). -spec fold_inferred_into_kb( graded@internal@effects:knowledge_base(), gleam@dict:dict(graded@internal@types:qualified_name(), graded@internal@types:effect_term()), gleam@dict:dict(graded@internal@types:qualified_name(), list(graded@internal@types:param_bound())), gleam@dict:dict(graded@internal@types:qualified_name(), graded@internal@types:effect_term()) ) -> graded@internal@effects:knowledge_base(). fold_inferred_into_kb(Knowledge_base, Effs, Params, Returns) -> _pipe = Knowledge_base, _pipe@1 = graded@internal@effects:with_inferred(_pipe, Effs), _pipe@2 = graded@internal@effects:with_inferred_params(_pipe@1, Params), graded@internal@effects:with_inferred_returned_operators(_pipe@2, Returns). -file("src/graded.gleam", 830). -spec qualified_inferred( list(graded@internal@types:effect_annotation()), gleam@dict:dict(binary(), graded@internal@types:effect_term()), binary() ) -> {gleam@dict:dict(graded@internal@types:qualified_name(), graded@internal@types:effect_term()), gleam@dict:dict(graded@internal@types:qualified_name(), list(graded@internal@types:param_bound())), gleam@dict:dict(graded@internal@types:qualified_name(), graded@internal@types:effect_term())}. qualified_inferred(Inferred, Returned_operators, Module_path) -> Qualify = fun(Function) -> {qualified_name, Module_path, Function} end, Effects_dict = gleam@list:fold( Inferred, maps:new(), fun(Acc, Ann) -> gleam@dict:insert( Acc, Qualify(erlang:element(3, Ann)), erlang:element(5, Ann) ) end ), Params_dict = gleam@list:fold( Inferred, maps:new(), fun(Acc@1, Ann@1) -> case erlang:element(4, Ann@1) of [] -> Acc@1; Params -> gleam@dict:insert( Acc@1, Qualify(erlang:element(3, Ann@1)), Params ) end end ), Returns_dict = gleam@dict:fold( Returned_operators, maps:new(), fun(Acc@2, Function@1, Op) -> gleam@dict:insert(Acc@2, Qualify(Function@1), Op) end ), {Effects_dict, Params_dict, Returns_dict}. -file("src/graded.gleam", 814). -spec thread_inferred_into_kb( graded@internal@effects:knowledge_base(), list(graded@internal@types:effect_annotation()), gleam@dict:dict(binary(), graded@internal@types:effect_term()), binary() ) -> graded@internal@effects:knowledge_base(). thread_inferred_into_kb( Knowledge_base, Inferred, Returned_operators, Module_path ) -> {Effects_dict, Params_dict, Returns_dict} = qualified_inferred( Inferred, Returned_operators, Module_path ), fold_inferred_into_kb( Knowledge_base, Effects_dict, Params_dict, Returns_dict ). -file("src/graded.gleam", 792). -spec fold_inferred_module( graded@internal@effects:knowledge_base(), glance:module_(), binary(), graded@internal@signatures:signature_registry(), graded@internal@typeinfo:type_info() ) -> graded@internal@effects:knowledge_base(). fold_inferred_module(Kb, Module, Module_path, Registry, Type_info) -> {Inferred, Returned_operators} = graded@internal@checker:infer_with_returns( Module, Kb, [], Registry, graded@internal@typeinfo:for_module(Type_info, Module_path), graded@internal@typeinfo:fn_typed_for_module(Type_info, Module_path) ), thread_inferred_into_kb(Kb, Inferred, Returned_operators, Module_path). -file("src/graded.gleam", 673). -spec build_dependency_graph( gleam@dict:dict(binary(), {binary(), glance:module_()}) ) -> gleam@dict:dict(binary(), gleam@set:set(binary())). build_dependency_graph(Index) -> gleam@dict:map_values( Index, fun(_, Entry) -> {_, Module} = Entry, Context = graded@internal@extract:build_import_context(Module), _pipe = erlang:element(2, Context), _pipe@1 = maps:values(_pipe), _pipe@2 = gleam@list:filter( _pipe@1, fun(Imported) -> gleam@dict:has_key(Index, Imported) end ), gleam@set:from_list(_pipe@2) end ). -file("src/graded.gleam", 770). -spec infer_project_in_memory( graded@internal@effects:knowledge_base(), gleam@dict:dict(binary(), {binary(), glance:module_()}), graded@internal@signatures:signature_registry(), graded@internal@typeinfo:type_info() ) -> graded@internal@effects:knowledge_base(). infer_project_in_memory(Base_kb, Index, Registry, Type_info) -> case graded@internal@topo:sort(build_dependency_graph(Index)) of {error, _} -> Base_kb; {ok, Sorted} -> gleam@list:fold( Sorted, Base_kb, fun(Kb, Module_path) -> case gleam_stdlib:map_get(Index, Module_path) of {error, _} -> Kb; {ok, {_, Module}} -> fold_inferred_module( Kb, Module, Module_path, Registry, Type_info ) end end ) end. -file("src/graded.gleam", 1208). -spec infer_path_dep_module( {gleam@dict:dict(graded@internal@types:qualified_name(), graded@internal@types:effect_term()), gleam@dict:dict(graded@internal@types:qualified_name(), list(graded@internal@types:param_bound())), gleam@dict:dict(graded@internal@types:qualified_name(), graded@internal@types:effect_term()), graded@internal@effects:knowledge_base()}, binary(), gleam@dict:dict(binary(), {glance:module_(), list(graded@internal@types:effect_annotation())}), graded@internal@signatures:signature_registry() ) -> {gleam@dict:dict(graded@internal@types:qualified_name(), graded@internal@types:effect_term()), gleam@dict:dict(graded@internal@types:qualified_name(), list(graded@internal@types:param_bound())), gleam@dict:dict(graded@internal@types:qualified_name(), graded@internal@types:effect_term()), graded@internal@effects:knowledge_base()}. infer_path_dep_module(State, Module_path, Index, Registry) -> {Eff_acc, Param_acc, Returns_acc, Kb} = State, case gleam_stdlib:map_get(Index, Module_path) of {error, _} -> State; {ok, {Module, Checks}} -> {Annotations, Returned_operators} = graded@internal@checker:infer_with_returns( Module, Kb, Checks, Registry, maps:new(), maps:new() ), {Module_effects, Module_params, Module_returns} = qualified_inferred( Annotations, Returned_operators, Module_path ), New_kb = fold_inferred_into_kb( Kb, Module_effects, Module_params, Module_returns ), {maps:merge(Eff_acc, Module_effects), maps:merge(Param_acc, Module_params), maps:merge(Returns_acc, Module_returns), New_kb} end. -file("src/graded.gleam", 1303). -spec read_and_parse_gleam(binary()) -> {ok, glance:module_()} | {error, graded_error()}. read_and_parse_gleam(Gleam_path) -> gleam@result:'try'( begin _pipe = simplifile:read(Gleam_path), gleam@result:map_error( _pipe, fun(_capture) -> {file_read_error, Gleam_path, _capture} end ) end, fun(Source) -> _pipe@1 = glance:module(Source), gleam@result:map_error( _pipe@1, fun(_capture@1) -> {gleam_parse_error, Gleam_path, _capture@1} end ) end ). -file("src/graded.gleam", 1140). ?DOC( " Build the dependency-graph index for a single path dep, topo-sort it,\n" " then infer every module in dependency order. Returns the union of all\n" " inferred effects, polymorphic param bounds, and returned-operator\n" " signatures keyed by `QualifiedName` so the caller can fold them into the\n" " global knowledge base. Errors are swallowed (returned as `Error(Nil)`) to\n" " preserve the existing tolerance: a malformed dep shouldn't break the whole\n" " project.\n" "\n" " Exposed (pub) primarily so tests can exercise the topological-order path\n" " inference on a temporary directory tree without going through\n" " `gleam.toml` resolution. Production callers go through\n" " `enrich_with_path_deps` which reads `gleam.toml` to discover dep paths.\n" ). -spec infer_path_dep(binary(), graded@internal@effects:knowledge_base()) -> {ok, {gleam@dict:dict(graded@internal@types:qualified_name(), graded@internal@types:effect_term()), gleam@dict:dict(graded@internal@types:qualified_name(), list(graded@internal@types:param_bound())), gleam@dict:dict(graded@internal@types:qualified_name(), graded@internal@types:effect_term())}} | {error, nil}. infer_path_dep(Dep_path, Base_kb) -> Source_dir = <>, Gleam_files = case simplifile:get_files(Source_dir) of {ok, Found} -> gleam@list:filter( Found, fun(Path) -> gleam_stdlib:string_ends_with(Path, <<".gleam"/utf8>>) end ); {error, _} -> [] end, Entries = gleam@list:filter_map( Gleam_files, fun(Gleam_path) -> gleam@result:'try'( begin _pipe = read_and_parse_gleam(Gleam_path), gleam@result:map_error(_pipe, fun(_) -> nil end) end, fun(Module) -> Module_path = graded@internal@config:module_path_for_source( Gleam_path, Source_dir ), {ok, {Module_path, Module, []}} end ) end ), Index = gleam@list:fold( Entries, maps:new(), fun(Acc, Entry) -> {Module_path@1, Module@1, Checks} = Entry, gleam@dict:insert(Acc, Module_path@1, {Module@1, Checks}) end ), Graph = gleam@dict:map_values( Index, fun(_, Entry@1) -> {Module@2, _} = Entry@1, Context = graded@internal@extract:build_import_context(Module@2), _pipe@1 = erlang:element(2, Context), _pipe@2 = maps:values(_pipe@1), _pipe@3 = gleam@list:filter( _pipe@2, fun(Imported) -> gleam@dict:has_key(Index, Imported) end ), gleam@set:from_list(_pipe@3) end ), Registry = gleam@dict:fold( Index, graded@internal@signatures:empty(), fun(Acc@1, Module_path@2, Entry@2) -> {Module@3, _} = Entry@2, graded@internal@signatures:merge( Acc@1, graded@internal@signatures:from_glance_module( Module_path@2, Module@3 ) ) end ), gleam@result:'try'( begin _pipe@4 = graded@internal@topo:sort(Graph), gleam@result:map_error(_pipe@4, fun(_) -> nil end) end, fun(Sorted) -> {Effs, Params, Returns, _} = gleam@list:fold( Sorted, {maps:new(), maps:new(), maps:new(), Base_kb}, fun(State, Module_path@3) -> infer_path_dep_module(State, Module_path@3, Index, Registry) end ), {ok, {Effs, Params, Returns}} end ). -file("src/graded.gleam", 1026). -spec resolve_path(binary(), binary()) -> binary(). resolve_path(Root, Path) -> gleam@bool:guard( gleam_stdlib:string_starts_with(Path, <<"/"/utf8>>) orelse (Root =:= <<"."/utf8>>), Path, fun() -> filepath:join(Root, Path) end ). -file("src/graded.gleam", 1066). -spec enrich_with_path_deps(graded@internal@effects:knowledge_base(), binary()) -> graded@internal@effects:knowledge_base(). enrich_with_path_deps(Knowledge_base, Package_root) -> Path_deps = graded@internal@effects:parse_path_dependencies( filepath:join(Package_root, <<"gleam.toml"/utf8>>) ), gleam@list:fold( Path_deps, Knowledge_base, fun(Kb, Dep) -> {Name, Dep_path} = Dep, Resolved_dep_path = resolve_path(Package_root, Dep_path), Spec_path = graded@internal@config:spec_file_for( Resolved_dep_path, Name ), case simplifile_erl:is_file(Spec_path) of {ok, true} -> {Effs, Params, Returns} = graded@internal@effects:load_dep_spec( Resolved_dep_path, Name ), fold_inferred_into_kb(Kb, Effs, Params, Returns); _ -> case infer_path_dep(Resolved_dep_path, Kb) of {error, nil} -> Kb; {ok, {Effs@1, Params@1, Returns@1}} -> fold_inferred_into_kb( Kb, Effs@1, Params@1, Returns@1 ) end end end ). -file("src/graded.gleam", 996). -spec manifest_path(binary()) -> binary(). manifest_path(Package_root) -> filepath:join(Package_root, <<"manifest.toml"/utf8>>). -file("src/graded.gleam", 990). -spec packages_dir(binary()) -> binary(). packages_dir(Package_root) -> filepath:join(Package_root, <<"build/packages"/utf8>>). -file("src/graded.gleam", 616). -spec fn_typed_names(glance:function_(), list(girard@types:type())) -> gleam@set:set(binary()). fn_typed_names(Function, Argument_types) -> gleam@bool:guard( erlang:length(erlang:element(5, Function)) /= erlang:length( Argument_types ), gleam@set:new(), fun() -> _pipe = gleam@list:zip(erlang:element(5, Function), Argument_types), _pipe@1 = gleam@list:filter_map( _pipe, fun(Pair) -> {Parameter, Argument_type} = Pair, case {Argument_type, erlang:element(3, Parameter)} of {{fn, _, _}, {named, Parameter_name}} -> {ok, Parameter_name}; {_, _} -> {error, nil} end end ), gleam@set:from_list(_pipe@1) end ). -file("src/graded.gleam", 596). -spec fn_typed_params_from_schemes(girard:module_result(), glance:module_()) -> gleam@dict:dict(binary(), gleam@set:set(binary())). fn_typed_params_from_schemes(Module_result, Module) -> Function_map = gleam@list:fold( erlang:element(6, Module), maps:new(), fun(Acc, Definition) -> gleam@dict:insert( Acc, erlang:element(3, erlang:element(3, Definition)), erlang:element(3, Definition) ) end ), gleam@list:fold( erlang:element(2, erlang:element(2, Module_result)), maps:new(), fun(Acc@1, Entry) -> {Name, Scheme} = Entry, case {erlang:element(3, Scheme), gleam_stdlib:map_get(Function_map, Name)} of {{fn, Argument_types, _}, {ok, Function}} -> gleam@dict:insert( Acc@1, Name, fn_typed_names(Function, Argument_types) ); {_, _} -> Acc@1 end end ). -file("src/graded.gleam", 642). -spec build_girard_resolver( gleam@dict:dict(binary(), {binary(), glance:module_()}) ) -> fun((binary()) -> {ok, binary()} | {error, nil}). build_girard_resolver(Index) -> Disk = girard:disk_resolver(), fun(Module_path) -> case gleam_stdlib:map_get(Index, Module_path) of {ok, {Gleam_path, _}} -> _pipe = simplifile:read(Gleam_path), gleam@result:replace_error(_pipe, nil); {error, nil} -> Disk(Module_path) end end. -file("src/graded.gleam", 549). -spec build_type_index(gleam@dict:dict(binary(), {binary(), glance:module_()})) -> graded@internal@typeinfo:type_info(). build_type_index(Index) -> Options = begin _pipe = girard:default_options(), girard:with_resolver(_pipe, build_girard_resolver(Index)) end, Entries = begin _pipe@1 = maps:to_list(Index), gleam@list:map( _pipe@1, fun(Pair) -> {Module_path, {_, Module}} = Pair, {Module_path, Module} end ) end, Results = begin _pipe@2 = girard:annotate_package(Entries, Options), maps:to_list(_pipe@2) end, Span_types = gleam@list:map( Results, fun(Pair@1) -> {Module_path@1, Module_result} = Pair@1, Types = gleam@list:fold( erlang:element(4, erlang:element(2, Module_result)), maps:new(), fun(Acc, Annotation) -> gleam@dict:insert( Acc, {erlang:element(2, erlang:element(2, Annotation)), erlang:element(3, erlang:element(2, Annotation))}, erlang:element(3, Annotation) ) end ), {Module_path@1, Types} end ), Fn_typed = gleam@list:filter_map( Results, fun(Pair@2) -> {Module_path@2, Module_result@1} = Pair@2, case gleam_stdlib:map_get(Index, Module_path@2) of {ok, {_, Module@1}} -> {ok, {Module_path@2, fn_typed_params_from_schemes( Module_result@1, Module@1 )}}; {error, nil} -> {error, nil} end end ), graded@internal@typeinfo:from_modules(Span_types, Fn_typed). -file("src/graded.gleam", 356). -spec build_project_registry( gleam@dict:dict(binary(), {binary(), glance:module_()}) ) -> graded@internal@signatures:signature_registry(). build_project_registry(Index) -> gleam@dict:fold( Index, graded@internal@signatures:empty(), fun(Acc, Module_path, Entry) -> {_, Module} = Entry, graded@internal@signatures:merge( Acc, graded@internal@signatures:from_glance_module( Module_path, Module ) ) end ). -file("src/graded.gleam", 1099). -spec path_dep_registry(binary()) -> graded@internal@signatures:signature_registry(). path_dep_registry(Package_root) -> _pipe = graded@internal@effects:parse_path_dependencies( filepath:join(Package_root, <<"gleam.toml"/utf8>>) ), gleam@list:fold( _pipe, graded@internal@signatures:empty(), fun(Acc, Dep) -> {_, Dep_path} = Dep, Resolved_dep_path = resolve_path(Package_root, Dep_path), graded@internal@signatures:merge( Acc, graded@internal@signatures:load_from_source_dir( <> ) ) end ). -file("src/graded.gleam", 658). -spec build_module_index(list({binary(), glance:module_()}), binary()) -> gleam@dict:dict(binary(), {binary(), glance:module_()}). build_module_index(Parsed, Directory) -> gleam@list:fold( Parsed, maps:new(), fun(Acc, Entry) -> {Gleam_path, Module} = Entry, Module_path = graded@internal@config:module_path_for_source( Gleam_path, Directory ), gleam@dict:insert(Acc, Module_path, {Gleam_path, Module}) end ). -file("src/graded.gleam", 344). -spec parse_all_files(list(binary())) -> {ok, list({binary(), glance:module_()})} | {error, graded_error()}. parse_all_files(Gleam_files) -> gleam@list:try_map( Gleam_files, fun(Gleam_path) -> gleam@result:'try'( read_and_parse_gleam(Gleam_path), fun(Module) -> {ok, {Gleam_path, Module}} end ) end ). -file("src/graded.gleam", 1297). -spec find_gleam_files(binary()) -> {ok, list(binary())} | {error, graded_error()}. find_gleam_files(Directory) -> _pipe = simplifile:get_files(Directory), _pipe@1 = gleam@result:map_error( _pipe, fun(_capture) -> {directory_read_error, Directory, _capture} end ), gleam@result:map( _pipe@1, fun(_capture@1) -> gleam@list:filter( _capture@1, fun(Path) -> gleam_stdlib:string_ends_with(Path, <<".gleam"/utf8>>) end ) end ). -file("src/graded.gleam", 897). -spec checks_grouped_by_module(graded@internal@types:graded_file()) -> gleam@dict:dict(binary(), list(graded@internal@types:effect_annotation())). checks_grouped_by_module(Spec) -> gleam@list:fold( graded@internal@annotation:extract_checks(Spec), maps:new(), fun(Acc, Ann) -> case graded@internal@annotation:split_qualified_name( erlang:element(3, Ann) ) of {error, _} -> Acc; {ok, {Module, Function}} -> Bare = {effect_annotation, erlang:element(2, Ann), Function, erlang:element(4, Ann), erlang:element(5, Ann)}, Existing = case gleam_stdlib:map_get(Acc, Module) of {ok, List} -> List; {error, _} -> [] end, gleam@dict:insert(Acc, Module, [Bare | Existing]) end end ). -file("src/graded.gleam", 1043). -spec read_spec(binary()) -> graded@internal@types:graded_file(). read_spec(Spec_path) -> case simplifile:read(Spec_path) of {error, _} -> {graded_file, []}; {ok, Content} -> case graded@internal@annotation:parse_file(Content) of {ok, File} -> File; {error, _} -> {graded_file, []} end end. -file("src/graded.gleam", 1000). -spec find_gleam_toml_dir(binary(), binary()) -> binary(). find_gleam_toml_dir(Dir, Original) -> Dir@1 = case Dir of <<""/utf8>> -> <<"."/utf8>>; _ -> Dir end, case simplifile_erl:is_file(filepath:join(Dir@1, <<"gleam.toml"/utf8>>)) of {ok, true} -> Dir@1; _ -> Parent = case filepath:directory_name(Dir@1) of <<""/utf8>> -> <<"."/utf8>>; Other -> Other end, case Parent =:= Dir@1 of true -> Original; false -> find_gleam_toml_dir(Parent, Original) end end. -file("src/graded.gleam", 982). -spec source_root_for(binary()) -> binary(). source_root_for(Directory) -> case Directory of <<"src"/utf8>> -> <<"."/utf8>>; _ -> Directory end. -file("src/graded.gleam", 973). -spec resolve_package_root(binary()) -> binary(). resolve_package_root(Directory) -> Source_root = source_root_for(Directory), find_gleam_toml_dir(Source_root, Source_root). -file("src/graded.gleam", 1034). -spec default_package_name(binary()) -> binary(). default_package_name(Project_root) -> case filepath:base_name(Project_root) of <<""/utf8>> -> <<"graded"/utf8>>; <<"/"/utf8>> -> <<"graded"/utf8>>; <<"."/utf8>> -> <<"graded"/utf8>>; Name -> Name end. -file("src/graded.gleam", 949). -spec read_config(binary()) -> {ok, graded@internal@config:graded_config()} | {error, graded_error()}. read_config(Directory) -> Project_root = source_root_for(Directory), Toml_path = filepath:join(Project_root, <<"gleam.toml"/utf8>>), gleam@result:'try'(case graded@internal@config:read(Toml_path) of {ok, Cfg} -> {ok, Cfg}; {error, {toml_read_error, _, _}} -> {ok, graded@internal@config:defaults_for( default_package_name(Project_root) )}; {error, Cause} -> {error, {invalid_config, Toml_path, Cause}} end, fun(Raw) -> {ok, {graded_config, erlang:element(2, Raw), resolve_path(Project_root, erlang:element(3, Raw)), resolve_path(Project_root, erlang:element(4, Raw))}} end). -file("src/graded.gleam", 125). ?DOC( " Run the checker on all .gleam files in a directory.\n" "\n" " Reads the project's single spec file (default `.graded`)\n" " to find inferred public-API effects, `check` invariants, `external`\n" " hints, and `type` field annotations, then reports violations per source\n" " file.\n" ). -spec run(binary()) -> {ok, list(graded@internal@types:check_result())} | {error, graded_error()}. run(Directory) -> gleam@result:'try'( read_config(Directory), fun(Cfg) -> Package_root = resolve_package_root(Directory), Spec = read_spec(erlang:element(3, Cfg)), Checks_by_module = checks_grouped_by_module(Spec), gleam@result:'try'( find_gleam_files(Directory), fun(Gleam_files) -> gleam@result:'try'( parse_all_files(Gleam_files), fun(Parsed) -> Index = build_module_index(Parsed, Directory), Dep_registry = begin _pipe = graded@internal@signatures:load_from_packages_dir( packages_dir(Package_root) ), graded@internal@signatures:merge( _pipe, path_dep_registry(Package_root) ) end, Registry = graded@internal@signatures:merge( Dep_registry, build_project_registry(Index) ), Type_info = build_type_index(Index), Kb_base = begin _pipe@1 = graded@internal@effects:load_knowledge_base( packages_dir(Package_root), manifest_path(Package_root) ), _pipe@2 = enrich_with_path_deps( _pipe@1, Package_root ), _pipe@3 = graded@internal@effects:with_inferred( _pipe@2, graded@internal@effects:load_spec_effects_from_file( Spec ) ), _pipe@4 = graded@internal@effects:with_inferred_returned_operators( _pipe@3, graded@internal@effects:load_spec_returns_from_file( Spec ) ), _pipe@5 = graded@internal@effects:with_externals( _pipe@4, graded@internal@annotation:extract_externals( Spec ) ), infer_project_in_memory( _pipe@5, Index, Registry, Type_info ) end, Knowledge_base = begin _pipe@6 = Kb_base, _pipe@7 = graded@internal@effects:with_inferred_type_fields( _pipe@6, build_constructor_field_index( Index, Kb_base ) ), _pipe@8 = graded@internal@effects:with_type_fields( _pipe@7, graded@internal@annotation:extract_type_fields( Spec ) ), graded@internal@effects:with_factories( _pipe@8, qualify_by_module( Index, fun graded@internal@extract:factory_map/1 ) ) end, Results = gleam@list:map( Parsed, fun(Entry) -> {Gleam_path, Module} = Entry, Module_path = graded@internal@config:module_path_for_source( Gleam_path, Directory ), Module_checks = case gleam_stdlib:map_get( Checks_by_module, Module_path ) of {ok, List} -> List; {error, _} -> [] end, check_one_file( Gleam_path, Module, Module_checks, Knowledge_base, Registry, graded@internal@typeinfo:for_module( Type_info, Module_path ), graded@internal@typeinfo:fn_typed_for_module( Type_info, Module_path ) ) end ), {ok, Results} end ) end ) end ). -file("src/graded.gleam", 1262). -spec run_check(binary()) -> nil. run_check(Directory) -> case run(Directory) of {ok, Results} -> Violations = gleam@list:flat_map( Results, fun(Check_result) -> erlang:element(3, Check_result) end ), Warnings = gleam@list:flat_map( Results, fun(Check_result@1) -> erlang:element(4, Check_result@1) end ), gleam@list:each(Results, fun print_warnings/1), case Warnings of [] -> nil; _ -> gleam_stdlib:println( <<<<"graded: "/utf8, (erlang:integer_to_binary( erlang:length(Warnings) ))/binary>>/binary, " warning(s)"/utf8>> ) end, case Violations of [] -> gleam_stdlib:println(<<"graded: all checks passed"/utf8>>); _ -> gleam@list:each(Results, fun print_violations/1), gleam_stdlib:println( <<<<"\ngraded: "/utf8, (erlang:integer_to_binary( erlang:length(Violations) ))/binary>>/binary, " violation(s) found"/utf8>> ), erlang:halt(1) end; {error, Error} -> gleam_stdlib:println_error( <<"graded: error: "/utf8, (format_error(Error))/binary>> ), erlang:halt(1) end. -file("src/graded.gleam", 327). -spec format_one_spec(binary()) -> {ok, gleam@option:option(binary())} | {error, graded_error()}. format_one_spec(Spec_path) -> case simplifile:read(Spec_path) of {error, _} -> {ok, none}; {ok, Content} -> _pipe = graded@internal@annotation:parse_file(Content), _pipe@1 = gleam@result:map( _pipe, fun(File) -> {some, graded@internal@annotation:format_sorted(File)} end ), gleam@result:map_error( _pipe@1, fun(_capture) -> {graded_parse_error, Spec_path, _capture} end ) end. -file("src/graded.gleam", 285). ?DOC( " Format the project's spec file in place. The spec file is the single\n" " source of truth for hand-written `check`/`external`/`type` lines and\n" " the inferred public-API effects.\n" ). -spec run_format(binary()) -> {ok, nil} | {error, graded_error()}. run_format(Directory) -> gleam@result:'try'( read_config(Directory), fun(Cfg) -> gleam@result:'try'( format_one_spec(erlang:element(3, Cfg)), fun(Formatted) -> case Formatted of none -> {ok, nil}; {some, Formatted@1} -> _pipe = simplifile:write( erlang:element(3, Cfg), Formatted@1 ), gleam@result:map_error( _pipe, fun(_capture) -> {file_write_error, erlang:element(3, Cfg), _capture} end ) end end ) end ). -file("src/graded.gleam", 308). ?DOC( " Check that the project's spec file is already formatted. Returns error\n" " with the file path if it isn't. Used by CI as `format --check`.\n" ). -spec run_format_check(binary()) -> {ok, nil} | {error, graded_error()}. run_format_check(Directory) -> gleam@result:'try'( read_config(Directory), fun(Cfg) -> gleam@result:'try'( format_one_spec(erlang:element(3, Cfg)), fun(Formatted) -> case Formatted of none -> {ok, nil}; {some, Formatted@1} -> case simplifile:read(erlang:element(3, Cfg)) of {error, _} -> {ok, nil}; {ok, Content} -> case Content =:= Formatted@1 of true -> {ok, nil}; false -> {error, {format_check_failed, [erlang:element(3, Cfg)]}} end end end end ) end ). -file("src/graded.gleam", 299). ?DOC( " Format a `.graded` spec given as a string, as `graded format --stdin` does\n" " for editor integration: parse the input, then sort and reformat it. Returns\n" " the input's parse error if it doesn't parse.\n" ). -spec run_format_stdin(binary()) -> {ok, binary()} | {error, graded@internal@annotation:parse_error()}. run_format_stdin(Input) -> gleam@result:map( graded@internal@annotation:parse_file(Input), fun(File) -> graded@internal@annotation:format_sorted(File) end ). -file("src/graded.gleam", 1314). -spec write_graded_file(binary(), graded@internal@types:graded_file()) -> {ok, nil} | {error, graded_error()}. write_graded_file(Path, Graded_file) -> _pipe = simplifile:write( Path, graded@internal@annotation:format_file(Graded_file) ), gleam@result:map_error( _pipe, fun(_capture) -> {file_write_error, Path, _capture} end ). -file("src/graded.gleam", 872). -spec write_spec_file( binary(), graded@internal@types:graded_file(), list(graded@internal@types:effect_annotation()), list(graded@internal@types:returns_annotation()) ) -> {ok, nil} | {error, graded_error()}. write_spec_file(Spec_path, Existing, Inferred, Inferred_returns) -> Merged = graded@internal@annotation:merge_inferred( Existing, Inferred, Inferred_returns ), Parent = filepath:directory_name(Spec_path), gleam@result:'try'( case (Parent =:= <<""/utf8>>) orelse (Parent =:= <<"."/utf8>>) of true -> {ok, nil}; false -> _pipe = simplifile:create_directory_all(Parent), gleam@result:map_error( _pipe, fun(_capture) -> {directory_create_error, Parent, _capture} end ) end, fun(_use0) -> nil = _use0, write_graded_file(Spec_path, Merged) end ). -file("src/graded.gleam", 859). -spec public_function_names(glance:module_()) -> gleam@set:set(binary()). public_function_names(Module) -> gleam@list:fold( erlang:element(6, Module), gleam@set:new(), fun(Acc, Def) -> case erlang:element(4, erlang:element(3, Def)) of public -> gleam@set:insert( Acc, erlang:element(3, erlang:element(3, Def)) ); private -> Acc end end ). -file("src/graded.gleam", 690). -spec infer_one_module( glance:module_(), binary(), binary(), graded@internal@effects:knowledge_base(), graded@internal@signatures:signature_registry(), gleam@dict:dict({integer(), integer()}, girard@types:type()), gleam@dict:dict(binary(), gleam@set:set(binary())) ) -> {ok, {graded@internal@effects:knowledge_base(), list(graded@internal@types:effect_annotation()), list(graded@internal@types:returns_annotation())}} | {error, graded_error()}. infer_one_module( Module, Module_path, Cache_dir, Knowledge_base, Registry, Module_types, Girard_fn_typed ) -> {Inferred, Returned_operators} = graded@internal@checker:infer_with_returns( Module, Knowledge_base, [], Registry, Module_types, Girard_fn_typed ), Cache_path = filepath:join( Cache_dir, <> ), gleam@result:'try'(case Inferred of [] -> {ok, nil}; _ -> Parent_directory = filepath:directory_name(Cache_path), gleam@result:'try'( begin _pipe = simplifile:create_directory_all( Parent_directory ), gleam@result:map_error( _pipe, fun(_capture) -> {directory_create_error, Parent_directory, _capture} end ) end, fun(_use0) -> nil = _use0, Cache_file = {graded_file, gleam@list:map( Inferred, fun(Field@0) -> {annotation_line, Field@0} end )}, write_graded_file(Cache_path, Cache_file) end ) end, fun(_use0@1) -> nil = _use0@1, New_kb = thread_inferred_into_kb( Knowledge_base, Inferred, Returned_operators, Module_path ), Public_names = public_function_names(Module), Public_annotations = begin _pipe@1 = Inferred, _pipe@2 = gleam@list:filter( _pipe@1, fun(Ann) -> gleam@set:contains(Public_names, erlang:element(3, Ann)) end ), gleam@list:map( _pipe@2, fun(Ann@1) -> {effect_annotation, erlang:element(2, Ann@1), <<<>/binary, (erlang:element(3, Ann@1))/binary>>, erlang:element(4, Ann@1), erlang:element(5, Ann@1)} end ) end, Public_returns = begin _pipe@3 = Returned_operators, _pipe@4 = maps:to_list(_pipe@3), _pipe@5 = gleam@list:filter( _pipe@4, fun(Pair) -> gleam@set:contains( Public_names, erlang:element(1, Pair) ) end ), gleam@list:map( _pipe@5, fun(Pair@1) -> {returns_annotation, <<<>/binary, (erlang:element(1, Pair@1))/binary>>, erlang:element(2, Pair@1)} end ) end, {ok, {New_kb, Public_annotations, Public_returns}} end). -file("src/graded.gleam", 202). ?DOC( " Infer effects for all `.gleam` files in `directory`. Writes two outputs:\n" "\n" " 1. **Per-module cache files** under `/.graded`,\n" " containing the inferred effects of every function in the module\n" " (public + private). Regenerated freely; not shipped.\n" "\n" " 2. **One spec file** at `` containing the inferred effects of\n" " every *public* function across all modules, plus any hand-written\n" " `check`, `external effects`, or `type` annotations the user already\n" " had in the spec file (those lines are preserved verbatim).\n" "\n" " Walks the project's import graph in topological order so each module is\n" " analysed after every other project module it imports — a single pass\n" " resolves transitive chains of any depth.\n" ). -spec run_infer(binary()) -> {ok, nil} | {error, graded_error()}. run_infer(Directory) -> gleam@result:'try'( read_config(Directory), fun(Cfg) -> Package_root = resolve_package_root(Directory), Spec = read_spec(erlang:element(3, Cfg)), gleam@result:'try'( find_gleam_files(Directory), fun(Gleam_files) -> gleam@result:'try'( parse_all_files(Gleam_files), fun(Parsed) -> Index = build_module_index(Parsed, Directory), Kb_base = begin _pipe = graded@internal@effects:load_knowledge_base( packages_dir(Package_root), manifest_path(Package_root) ), _pipe@1 = enrich_with_path_deps( _pipe, Package_root ), graded@internal@effects:with_externals( _pipe@1, graded@internal@annotation:extract_externals( Spec ) ) end, Construction_kb = graded@internal@effects:with_inferred( Kb_base, graded@internal@effects:load_spec_effects_from_file( Spec ) ), Base_kb = begin _pipe@2 = Kb_base, _pipe@3 = graded@internal@effects:with_inferred_type_fields( _pipe@2, build_constructor_field_index( Index, Construction_kb ) ), _pipe@4 = graded@internal@effects:with_type_fields( _pipe@3, graded@internal@annotation:extract_type_fields( Spec ) ), graded@internal@effects:with_factories( _pipe@4, qualify_by_module( Index, fun graded@internal@extract:factory_map/1 ) ) end, Graph = build_dependency_graph(Index), gleam@result:'try'( begin _pipe@5 = graded@internal@topo:sort(Graph), gleam@result:map_error( _pipe@5, fun(Error) -> {cycle, Nodes} = Error, {cyclic_imports, Nodes} end ) end, fun(Sorted) -> Dep_registry = begin _pipe@6 = graded@internal@signatures:load_from_packages_dir( packages_dir(Package_root) ), graded@internal@signatures:merge( _pipe@6, path_dep_registry(Package_root) ) end, Registry = graded@internal@signatures:merge( Dep_registry, build_project_registry(Index) ), Type_info = build_type_index(Index), gleam@result:'try'( gleam@list:try_fold( Sorted, {Base_kb, [], []}, fun(State, Module_path) -> {Kb, Acc, Returns_acc} = State, case gleam_stdlib:map_get( Index, Module_path ) of {error, _} -> {ok, State}; {ok, {_, Module}} -> gleam@result:'try'( infer_one_module( Module, Module_path, erlang:element( 4, Cfg ), Kb, Registry, graded@internal@typeinfo:for_module( Type_info, Module_path ), graded@internal@typeinfo:fn_typed_for_module( Type_info, Module_path ) ), fun(_use0) -> {New_kb, New_public, New_returns} = _use0, {ok, {New_kb, lists:append( New_public, Acc ), lists:append( New_returns, Returns_acc )}} end ) end end ), fun(_use0@1) -> {_, Public_annotations, Public_returns} = _use0@1, write_spec_file( erlang:element(3, Cfg), Spec, Public_annotations, Public_returns ) end ) end ) end ) end ) end ). -file("src/graded.gleam", 79). -spec main() -> nil. main() -> Arguments = erlang:element(4, argv:load()), case Arguments of [<<"infer"/utf8>> | Rest] -> case run_infer(target_directory(Rest)) of {ok, nil} -> gleam_stdlib:println( <<"graded: inferred effects written"/utf8>> ); {error, Error} -> gleam_stdlib:println_error( <<"graded: error: "/utf8, (format_error(Error))/binary>> ), erlang:halt(1) end; [<<"format"/utf8>>, <<"--stdin"/utf8>> | _] -> case run_format_stdin(graded_ffi:read_stdin()) of {ok, Output} -> gleam_stdlib:print(Output); {error, _} -> gleam_stdlib:println_error( <<"graded: error: could not parse stdin"/utf8>> ), erlang:halt(1) end; [<<"format"/utf8>>, <<"--check"/utf8>> | Rest@1] -> case run_format_check(target_directory(Rest@1)) of {ok, nil} -> nil; {error, Error@1} -> gleam_stdlib:println_error( <<"graded: error: "/utf8, (format_error(Error@1))/binary>> ), erlang:halt(1) end; [<<"format"/utf8>> | Rest@2] -> case run_format(target_directory(Rest@2)) of {ok, nil} -> nil; {error, Error@2} -> gleam_stdlib:println_error( <<"graded: error: "/utf8, (format_error(Error@2))/binary>> ), erlang:halt(1) end; [<<"check"/utf8>> | Rest@3] -> run_check(target_directory(Rest@3)); _ -> run_check(target_directory(Arguments)) end.