Packages

KDL v2 parser, serializer, normalizer, and document builder for Gleam

Current section

Files

Jump to
kdleam src kdleam@value.erl
Raw

src/kdleam@value.erl

-module(kdleam@value).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/kdleam/value.gleam").
-export([value_to_kdl_document/1, kdl_document_to_value/1]).
-export_type([value/0, value_error/0, value_error_reason/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(" KDL 文書と汎用的な値の表現を相互に変換する。\n").
-type value() :: null |
{bool, boolean()} |
{integer, integer()} |
{float, float()} |
{string, binary()} |
{array, list(value())} |
{object, list({binary(), value()})}.
-type value_error() :: {value_error, value_error_reason()}.
-type value_error_reason() :: top_level_must_be_object |
nested_collection_in_array |
empty_array_cannot_be_converted |
property_cannot_be_converted |
mixed_arguments_and_children |
{unsupported_type_annotation, binary()} |
{number_cannot_be_converted, binary()}.
-file("src/kdleam/value.gleam", 155).
-spec is_finite_float(float()) -> boolean().
is_finite_float(_) ->
true.
-file("src/kdleam/value.gleam", 126).
-spec value_to_entry(value()) -> {ok, kdleam@document:kdl_entry()} |
{error, value_error()}.
value_to_entry(Value) ->
case Value of
null ->
{ok, {kdl_argument, none, kdl_null}};
{bool, B} ->
{ok, {kdl_argument, none, {kdl_bool, B}}};
{string, S} ->
{ok, {kdl_argument, none, {kdl_string, S}}};
{integer, I} ->
Number@1 = case kdleam@document:new_number(
erlang:integer_to_binary(I),
{some, I},
{some, erlang:float(I)}
) of
{ok, Number} -> Number;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"kdleam/value"/utf8>>,
function => <<"value_to_entry"/utf8>>,
line => 133,
value => _assert_fail,
start => 3685,
'end' => 3786,
pattern_start => 3696,
pattern_end => 3706})
end,
{ok, {kdl_argument, none, {kdl_number_value, Number@1}}};
{float, F} ->
case is_finite_float(F) of
false ->
{error,
{value_error,
{number_cannot_be_converted,
gleam_stdlib:float_to_string(F)}}};
true ->
Number@3 = case kdleam@document:new_number(
gleam_stdlib:float_to_string(F),
none,
{some, F}
) of
{ok, Number@2} -> Number@2;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"kdleam/value"/utf8>>,
function => <<"value_to_entry"/utf8>>,
line => 141,
value => _assert_fail@1,
start => 4030,
'end' => 4120,
pattern_start => 4041,
pattern_end => 4051})
end,
{ok,
{kdl_argument,
{some, <<"f64"/utf8>>},
{kdl_number_value, Number@3}}}
end;
{array, _} ->
{error, {value_error, nested_collection_in_array}};
{object, _} ->
{error, {value_error, nested_collection_in_array}}
end.
-file("src/kdleam/value.gleam", 108).
-spec array_to_entries(list(value()), list(kdleam@document:kdl_entry())) -> {ok,
list(kdleam@document:kdl_entry())} |
{error, value_error()}.
array_to_entries(Elements, Acc) ->
case Elements of
[] ->
{ok, lists:reverse(Acc)};
[Element | Rest] ->
case Element of
{array, _} ->
{error, {value_error, nested_collection_in_array}};
{object, _} ->
{error, {value_error, nested_collection_in_array}};
_ ->
case value_to_entry(Element) of
{ok, Entry} ->
array_to_entries(Rest, [Entry | Acc]);
{error, E} ->
{error, E}
end
end
end.
-file("src/kdleam/value.gleam", 67).
-spec value_to_node(binary(), value()) -> {ok, kdleam@document:kdl_node()} |
{error, value_error()}.
value_to_node(Name, Value) ->
case Value of
null ->
{ok, kdleam@document:new_node(Name, [], none, none)};
{bool, _} ->
case value_to_entry(Value) of
{ok, Entry} ->
{ok, kdleam@document:new_node(Name, [Entry], none, none)};
{error, E} ->
{error, E}
end;
{integer, _} ->
case value_to_entry(Value) of
{ok, Entry} ->
{ok, kdleam@document:new_node(Name, [Entry], none, none)};
{error, E} ->
{error, E}
end;
{float, _} ->
case value_to_entry(Value) of
{ok, Entry} ->
{ok, kdleam@document:new_node(Name, [Entry], none, none)};
{error, E} ->
{error, E}
end;
{string, _} ->
case value_to_entry(Value) of
{ok, Entry} ->
{ok, kdleam@document:new_node(Name, [Entry], none, none)};
{error, E} ->
{error, E}
end;
{array, []} ->
{error, {value_error, empty_array_cannot_be_converted}};
{array, Elements} ->
case array_to_entries(Elements, []) of
{ok, Entries} ->
{ok, kdleam@document:new_node(Name, Entries, none, none)};
{error, E@1} ->
{error, E@1}
end;
{object, Items} ->
case items_to_nodes(Items, []) of
{ok, Nodes} ->
{ok,
kdleam@document:new_node(Name, [], {some, Nodes}, none)};
{error, E@2} ->
{error, E@2}
end
end.
-file("src/kdleam/value.gleam", 53).
-spec items_to_nodes(
list({binary(), value()}),
list(kdleam@document:kdl_node())
) -> {ok, list(kdleam@document:kdl_node())} | {error, value_error()}.
items_to_nodes(Items, Acc) ->
case Items of
[] ->
{ok, lists:reverse(Acc)};
[{Key, Value} | Rest] ->
case value_to_node(Key, Value) of
{ok, Node} ->
items_to_nodes(Rest, [Node | Acc]);
{error, E} ->
{error, E}
end
end.
-file("src/kdleam/value.gleam", 41).
?DOC(" 最上位の `Object` を文書へ損失なく変換し、表現できない値を `Error` にする。\n").
-spec value_to_kdl_document(value()) -> {ok, kdleam@document:kdl_document()} |
{error, value_error()}.
value_to_kdl_document(Value) ->
case Value of
{object, Items} ->
case items_to_nodes(Items, []) of
{ok, Nodes} ->
{ok, kdleam@document:new_document(Nodes)};
{error, E} ->
{error, E}
end;
_ ->
{error, {value_error, top_level_must_be_object}}
end.
-file("src/kdleam/value.gleam", 313).
-spec raw_of(kdleam@document:kdl_value()) -> binary().
raw_of(Value) ->
case kdleam@document:raw_number(Value) of
{some, Raw} ->
Raw;
none ->
<<""/utf8>>
end.
-file("src/kdleam/value.gleam", 291).
-spec number_to_value(kdleam@document:kdl_value()) -> {ok, value()} |
{error, value_error()}.
number_to_value(Value) ->
case kdleam@document:as_int(Value) of
{some, I} ->
{ok, {integer, I}};
none ->
case kdleam@document:as_float(Value) of
{some, F} ->
{ok, {float, F}};
none ->
{error,
{value_error,
{number_cannot_be_converted, raw_of(Value)}}}
end
end.
-file("src/kdleam/value.gleam", 302).
-spec number_to_float(kdleam@document:kdl_value()) -> {ok, value()} |
{error, value_error()}.
number_to_float(Value) ->
case kdleam@document:as_float(Value) of
{some, F} ->
{ok, {float, F}};
none ->
case kdleam@document:as_int(Value) of
{some, I} ->
{ok, {float, erlang:float(I)}};
none ->
{error,
{value_error,
{number_cannot_be_converted, raw_of(Value)}}}
end
end.
-file("src/kdleam/value.gleam", 277).
-spec value_of_entry(kdleam@document:kdl_entry()) -> {ok, value()} |
{error, value_error()}.
value_of_entry(Entry) ->
Value = kdleam@document:value(Entry),
case Value of
kdl_null ->
{ok, null};
{kdl_bool, B} ->
{ok, {bool, B}};
{kdl_string, S} ->
{ok, {string, S}};
{kdl_number_value, _} ->
case kdleam@document:entry_ty(Entry) of
{some, <<"f64"/utf8>>} ->
number_to_float(Value);
_ ->
number_to_value(Value)
end
end.
-file("src/kdleam/value.gleam", 263).
-spec array_of_entries(list(kdleam@document:kdl_entry()), list(value())) -> {ok,
value()} |
{error, value_error()}.
array_of_entries(Entries, Acc) ->
case Entries of
[] ->
{ok, {array, lists:reverse(Acc)}};
[Entry | Rest] ->
case value_of_entry(Entry) of
{ok, Value} ->
array_of_entries(Rest, [Value | Acc]);
{error, E} ->
{error, E}
end
end.
-file("src/kdleam/value.gleam", 253).
-spec arguments(kdleam@document:kdl_node()) -> list(kdleam@document:kdl_entry()).
arguments(Node) ->
_pipe = kdleam@document:entries(Node),
gleam@list:filter(_pipe, fun(Entry) -> case Entry of
{kdl_argument, _, _} ->
true;
_ ->
false
end end).
-file("src/kdleam/value.gleam", 221).
-spec check_entry_annotations(list(kdleam@document:kdl_entry())) -> gleam@option:option(value_error()).
check_entry_annotations(Entries) ->
case Entries of
[] ->
none;
[Entry | Rest] ->
case kdleam@document:entry_ty(Entry) of
none ->
check_entry_annotations(Rest);
{some, <<"f64"/utf8>>} ->
case kdleam@document:value(Entry) of
{kdl_number_value, _} ->
check_entry_annotations(Rest);
_ ->
{some,
{value_error,
{unsupported_type_annotation,
<<"f64"/utf8>>}}}
end;
{some, Other} ->
{some, {value_error, {unsupported_type_annotation, Other}}}
end
end.
-file("src/kdleam/value.gleam", 212).
-spec has_property(list(kdleam@document:kdl_entry())) -> boolean().
has_property(Entries) ->
gleam@list:any(Entries, fun(Entry) -> case Entry of
{kdl_property, _, _, _} ->
true;
_ ->
false
end end).
-file("src/kdleam/value.gleam", 199).
-spec stage_one_reject(kdleam@document:kdl_node()) -> gleam@option:option(value_error()).
stage_one_reject(Node) ->
Entries = kdleam@document:entries(Node),
case kdleam@document:ty(Node) of
{some, _} ->
{some,
{value_error, {unsupported_type_annotation, <<"node"/utf8>>}}};
none ->
case has_property(Entries) of
true ->
{some, {value_error, property_cannot_be_converted}};
false ->
check_entry_annotations(Entries)
end
end.
-file("src/kdleam/value.gleam", 238).
-spec stage_two_classify(kdleam@document:kdl_node()) -> {ok, value()} |
{error, value_error()}.
stage_two_classify(Node) ->
Args = arguments(Node),
case {kdleam@document:children(Node), Args} of
{none, []} ->
{ok, null};
{none, [Entry]} ->
value_of_entry(Entry);
{none, Entries} ->
array_of_entries(Entries, []);
{{some, _}, [_ | _]} ->
{error, {value_error, mixed_arguments_and_children}};
{{some, Nodes}, []} ->
case nodes_to_items(Nodes, []) of
{ok, Items} ->
{ok, {object, Items}};
{error, E} ->
{error, E}
end
end.
-file("src/kdleam/value.gleam", 191).
-spec node_to_value(kdleam@document:kdl_node()) -> {ok, value()} |
{error, value_error()}.
node_to_value(Node) ->
case stage_one_reject(Node) of
{some, E} ->
{error, E};
none ->
stage_two_classify(Node)
end.
-file("src/kdleam/value.gleam", 176).
-spec nodes_to_items(
list(kdleam@document:kdl_node()),
list({binary(), value()})
) -> {ok, list({binary(), value()})} | {error, value_error()}.
nodes_to_items(Nodes, Acc) ->
case Nodes of
[] ->
{ok, lists:reverse(Acc)};
[Node | Rest] ->
case node_to_value(Node) of
{ok, Value} ->
nodes_to_items(
Rest,
[{kdleam@document:name(Node), Value} | Acc]
);
{error, E} ->
{error, E}
end
end.
-file("src/kdleam/value.gleam", 169).
?DOC(
" 文書を `Object` へ損失なく変換する。\n"
"\n"
" プロパティ、未対応の型注釈、混在した構造、表現できない数値は `Error` にする。\n"
).
-spec kdl_document_to_value(kdleam@document:kdl_document()) -> {ok, value()} |
{error, value_error()}.
kdl_document_to_value(Doc) ->
case nodes_to_items(kdleam@document:nodes(Doc), []) of
{ok, Items} ->
{ok, {object, Items}};
{error, E} ->
{error, E}
end.