Current section

Files

Jump to
fmglee src fmglee.erl
Raw

src/fmglee.erl

-module(fmglee).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([new/1, s/2, d/2, f/2, try_fmt/2, write/3, print/2, println/2, writef/2, printf/1, printlnf/1, fmt/2, try_build/1, build/1]).
-export_type([fmt_error/0, fmt/0, formatter/0]).
-type fmt_error() :: incorrect_value_type | too_many_values | not_enough_values.
-type fmt() :: {s, binary()} | {d, integer()} | {f, float()}.
-type formatter() :: {formatter, binary(), list(fmt())}.
-spec new(binary()) -> formatter().
new(S) ->
{formatter, S, []}.
-spec s(formatter(), binary()) -> formatter().
s(Formatter, S) ->
{formatter,
erlang:element(2, Formatter),
[{s, S} | erlang:element(3, Formatter)]}.
-spec d(formatter(), integer()) -> formatter().
d(Formatter, D) ->
{formatter,
erlang:element(2, Formatter),
[{d, D} | erlang:element(3, Formatter)]}.
-spec f(formatter(), float()) -> formatter().
f(Formatter, F) ->
{formatter,
erlang:element(2, Formatter),
[{f, F} | erlang:element(3, Formatter)]}.
-spec process_fmt(binary(), binary(), binary(), list(fmt())) -> {ok, binary()} |
{error, fmt_error()}.
process_fmt(Placeholder, Value, Str, Values) ->
case gleam@string:split_once(Str, Placeholder) of
{ok, {First, Last}} ->
fmt_iter(
<<<<First/binary, Value/binary>>/binary, Last/binary>>,
Values
);
{error, _} ->
{error, incorrect_value_type}
end.
-spec fmt_iter(binary(), list(fmt())) -> {ok, binary()} | {error, fmt_error()}.
fmt_iter(Str, Values) ->
case Values of
[{s, Value} | Rest] ->
process_fmt(<<"%s"/utf8>>, Value, Str, Rest);
[{d, Value@1} | Rest@1] ->
process_fmt(
<<"%d"/utf8>>,
gleam@int:to_string(Value@1),
Str,
Rest@1
);
[{f, Value@2} | Rest@2] ->
process_fmt(
<<"%f"/utf8>>,
gleam@float:to_string(Value@2),
Str,
Rest@2
);
[] ->
{ok, Str}
end.
-spec try_fmt(binary(), list(fmt())) -> {ok, binary()} | {error, fmt_error()}.
try_fmt(S, V) ->
_assert_subject = gleam@regex:from_string(<<"(\\%d|\\%f|\\%s)"/utf8>>),
{ok, Re} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"fmglee"/utf8>>,
function => <<"try_fmt"/utf8>>,
line => 117})
end,
Matches = erlang:length(gleam@regex:scan(Re, S)),
Values = erlang:length(V),
case {Matches > Values, Values > Matches} of
{true, false} ->
{error, not_enough_values};
{false, true} ->
{error, too_many_values};
{_, _} ->
fmt_iter(S, V)
end.
-spec write(binary(), list(fmt()), fun((binary()) -> nil)) -> nil.
write(S, V, Writer) ->
_assert_subject = try_fmt(S, V),
{ok, Str} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"fmglee"/utf8>>,
function => <<"write"/utf8>>,
line => 99})
end,
Writer(Str).
-spec print(binary(), list(fmt())) -> nil.
print(S, V) ->
write(S, V, fun gleam@io:print/1).
-spec println(binary(), list(fmt())) -> nil.
println(S, V) ->
write(S, V, fun gleam@io:println/1).
-spec writef(formatter(), fun((binary()) -> nil)) -> nil.
writef(Formatter, Writer) ->
write(erlang:element(2, Formatter), erlang:element(3, Formatter), Writer).
-spec printf(formatter()) -> nil.
printf(Formatter) ->
writef(Formatter, fun gleam@io:print/1).
-spec printlnf(formatter()) -> nil.
printlnf(Formatter) ->
writef(Formatter, fun gleam@io:println/1).
-spec fmt(binary(), list(fmt())) -> binary().
fmt(S, V) ->
_assert_subject = try_fmt(S, V),
{ok, Str} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"fmglee"/utf8>>,
function => <<"fmt"/utf8>>,
line => 107})
end,
Str.
-spec try_build(formatter()) -> {ok, binary()} | {error, fmt_error()}.
try_build(Formatter) ->
try_fmt(
erlang:element(2, Formatter),
lists:reverse(erlang:element(3, Formatter))
).
-spec build(formatter()) -> binary().
build(Formatter) ->
_assert_subject = try_build(Formatter),
{ok, Str} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"fmglee"/utf8>>,
function => <<"build"/utf8>>,
line => 198})
end,
Str.