-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 => <>, 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 => <>, 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.