From 34e62e795cf0cb02200bd0b238f7868a6419185c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 27 Sep 2011 15:08:09 +0200 Subject: [PATCH] Complete node modules for all standard types The modules "yaml_node_bool" and "yaml_node_int" are renamed to "yaml_node_ext_bool" and "yaml_node_ext_int", because they do not implement what is written in the YAML 1.2 specification but the ones from the types repository (http://yaml.org/type/). New modules are added to implement the officiel YAML 1.2 types and the JSON types (defined in this same specification). Note that these new modules are untested material. --- src/Makefile.am | 7 ++ src/yaml_node_bool.erl | 10 +-- src/yaml_node_ext_bool.erl | 70 +++++++++++++++ src/yaml_node_ext_float.erl | 124 +++++++++++++++++++++++++++ src/yaml_node_ext_int.erl | 162 +++++++++++++++++++++++++++++++++++ src/yaml_node_float.erl | 108 +++++++++++++++++++++++ src/yaml_node_int.erl | 71 +-------------- src/yaml_node_json_bool.erl | 64 ++++++++++++++ src/yaml_node_json_float.erl | 99 +++++++++++++++++++++ src/yaml_node_json_int.erl | 88 +++++++++++++++++++ src/yaml_node_json_null.erl | 44 ++++++++++ 11 files changed, 771 insertions(+), 76 deletions(-) create mode 100644 src/yaml_node_ext_bool.erl create mode 100644 src/yaml_node_ext_float.erl create mode 100644 src/yaml_node_ext_int.erl create mode 100644 src/yaml_node_float.erl create mode 100644 src/yaml_node_json_bool.erl create mode 100644 src/yaml_node_json_float.erl create mode 100644 src/yaml_node_json_int.erl create mode 100644 src/yaml_node_json_null.erl diff --git a/src/Makefile.am b/src/Makefile.am index e1ec7de..ffe6f9d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,8 +9,15 @@ dist_erlsrc_DATA = yaml_app.erl \ yaml_node_map.erl \ yaml_node_str.erl \ yaml_node_null.erl \ + yaml_node_json_null.erl \ yaml_node_bool.erl \ + yaml_node_json_bool.erl \ yaml_node_int.erl \ + yaml_node_json_int.erl \ + yaml_node_ext_int.erl \ + yaml_node_float.erl \ + yaml_node_json_float.erl \ + yaml_node_ext_float.erl \ yaml_node_size.erl \ yaml_node_timestamp.erl \ yaml_node_ipaddr.erl \ diff --git a/src/yaml_node_bool.erl b/src/yaml_node_bool.erl index 31e8988..211f915 100644 --- a/src/yaml_node_bool.erl +++ b/src/yaml_node_bool.erl @@ -15,16 +15,10 @@ -define(TAG, "tag:yaml.org,2002:bool"). -define(IS_TRUE(S), - S == "true" orelse S == "True" orelse S == "TRUE" orelse - S == "y" orelse S == "Y" orelse - S == "yes" orelse S == "Yes" orelse S == "YES" orelse - S == "on" orelse S == "On" orelse S == "ON"). + S == "true" orelse S == "True" orelse S == "TRUE"). -define(IS_FALSE(S), - S == "false" orelse S == "False" orelse S == "FALSE" orelse - S == "n" orelse S == "N" orelse - S == "no" orelse S == "No" orelse S == "NO" orelse - S == "off" orelse S == "Off" orelse S == "OFF"). + S == "false" orelse S == "False" orelse S == "FALSE"). %% ------------------------------------------------------------------- %% Public API. diff --git a/src/yaml_node_ext_bool.erl b/src/yaml_node_ext_bool.erl new file mode 100644 index 0000000..d65e9b5 --- /dev/null +++ b/src/yaml_node_ext_bool.erl @@ -0,0 +1,70 @@ +-module(yaml_node_ext_bool). + +-include("yaml_tokens.hrl"). +-include("yaml_nodes.hrl"). +-include("internal/yaml_constr.hrl"). + +%% Public API. +-export([ + tags/0, + try_construct_token/3, + construct_token/3, + node_pres/1 + ]). + +-define(TAG, "tag:yaml.org,2002:bool"). + +-define(IS_TRUE(S), + S == "true" orelse S == "True" orelse S == "TRUE" orelse + S == "y" orelse S == "Y" orelse + S == "yes" orelse S == "Yes" orelse S == "YES" orelse + S == "on" orelse S == "On" orelse S == "ON"). + +-define(IS_FALSE(S), + S == "false" orelse S == "False" orelse S == "FALSE" orelse + S == "n" orelse S == "N" orelse + S == "no" orelse S == "No" orelse S == "NO" orelse + S == "off" orelse S == "Off" orelse S == "OFF"). + +%% ------------------------------------------------------------------- +%% Public API. +%% ------------------------------------------------------------------- + +tags() -> [?TAG]. + +try_construct_token(Repr, Node, + #yaml_scalar{tag = #yaml_tag{uri = {non_specific, "?"}}, + text = Text} = Token) when ?IS_TRUE(Text) orelse ?IS_FALSE(Text) -> + construct_token(Repr, Node, Token); +try_construct_token(_, _, _) -> + unrecognized. + +construct_token(#yaml_constr{simple_structs = true}, + undefined, #yaml_scalar{text = Text}) when ?IS_TRUE(Text) -> + {finished, true}; +construct_token(#yaml_constr{simple_structs = true}, + undefined, #yaml_scalar{text = Text}) when ?IS_FALSE(Text) -> + {finished, false}; +construct_token(#yaml_constr{simple_structs = false}, + undefined, #yaml_scalar{text = Text} = Token) when ?IS_TRUE(Text) -> + Pres = yaml_constr:get_pres_details(Token), + Node = #yaml_bool{ + module = ?MODULE, + tag = ?TAG, + pres = Pres, + value = true + }, + {finished, Node}; +construct_token(#yaml_constr{simple_structs = false}, + undefined, #yaml_scalar{text = Text} = Token) when ?IS_FALSE(Text) -> + Pres = yaml_constr:get_pres_details(Token), + Node = #yaml_bool{ + module = ?MODULE, + tag = ?TAG, + pres = Pres, + value = false + }, + {finished, Node}. + +node_pres(Node) -> + ?NODE_PRES(Node). diff --git a/src/yaml_node_ext_float.erl b/src/yaml_node_ext_float.erl new file mode 100644 index 0000000..e543003 --- /dev/null +++ b/src/yaml_node_ext_float.erl @@ -0,0 +1,124 @@ +-module(yaml_node_ext_float). + +-include("yaml_errors.hrl"). +-include("yaml_tokens.hrl"). +-include("yaml_nodes.hrl"). +-include("internal/yaml_constr.hrl"). + +%% Public API. +-export([ + tags/0, + try_construct_token/3, + construct_token/3, + node_pres/1, + string_to_float/1 + ]). + +-define(TAG, "tag:yaml.org,2002:float"). + +%% ------------------------------------------------------------------- +%% Public API. +%% ------------------------------------------------------------------- + +tags() -> [?TAG]. + +try_construct_token(Repr, Node, + #yaml_scalar{tag = #yaml_tag{uri = {non_specific, "?"}}} = Token) -> + try + construct_token(Repr, Node, Token) + catch + _:#yaml_parsing_error{name = not_an_float} -> + unrecognized + end; +try_construct_token(_, _, _) -> + unrecognized. + +construct_token(#yaml_constr{simple_structs = true}, + undefined, #yaml_scalar{text = Text} = Token) -> + case string_to_float(Text) of + error -> + exception(Token); + Int -> + {finished, Int} + end; +construct_token(#yaml_constr{simple_structs = false}, + undefined, #yaml_scalar{text = Text} = Token) -> + case string_to_float(Text) of + error -> + exception(Token); + Int -> + Pres = yaml_constr:get_pres_details(Token), + Node = #yaml_int{ + module = ?MODULE, + tag = ?TAG, + pres = Pres, + value = Int + }, + {finished, Node} + end; + +construct_token(_, _, Token) -> + exception(Token). + +node_pres(Node) -> + ?NODE_PRES(Node). + +%% ------------------------------------------------------------------- +%% Internal functions. +%% ------------------------------------------------------------------- + +string_to_float(".nan") -> 'nan'; +string_to_float(".Nan") -> 'nan'; +string_to_float(".NAN") -> 'nan'; +string_to_float(".inf") -> '+inf'; +string_to_float(".Inf") -> '+inf'; +string_to_float(".INF") -> '+inf'; +string_to_float("+.inf") -> '+inf'; +string_to_float("+.Inf") -> '+inf'; +string_to_float("+.INF") -> '+inf'; +string_to_float("-.inf") -> '-inf'; +string_to_float("-.Inf") -> '-inf'; +string_to_float("-.INF") -> '-inf'; +string_to_float([$+ | Text]) -> string_to_float2(Text); +string_to_float([$- | Text]) -> -string_to_float2(Text); +string_to_float(Text) -> string_to_float2(Text). + +string_to_float2(Text) -> + %% Try base 10. + O1 = [{capture, none}], + case re:run(Text, "([0-9][0-9_]*)?\.[0-9.]*([eE][-+][0-9]+)?", O1) of + match -> + string_to_float3(Text); + nomatch -> + %% Try base 60. + O2 = [{capture, all_but_first, list}], + case re:run(Text, "([0-9][0-9_]*)(:[0-5]?[0-9])+\.([0-9_]*)", O2) of + {match, [P1, P2, Dec]} -> + case yaml_node_ext_int:base60_to_integer(P1 ++ P2, 0, 0) of + error -> + error; + Int -> + string_to_float3( + erlang:integer_to_list(Int) ++ "." ++ Dec) + end; + nomatch -> + error + end + end. + +string_to_float3(Text) -> + try + erlang:list_to_float(Text) + catch + error:badarg -> error + end. + +exception(Token) -> + Error = #yaml_parsing_error{ + name = not_a_float, + token = Token, + text = "Invalid float", + line = ?TOKEN_LINE(Token), + column = ?TOKEN_COLUMN(Token) + }, + throw(Error). diff --git a/src/yaml_node_ext_int.erl b/src/yaml_node_ext_int.erl new file mode 100644 index 0000000..67b36e4 --- /dev/null +++ b/src/yaml_node_ext_int.erl @@ -0,0 +1,162 @@ +-module(yaml_node_ext_int). + +-include("yaml_errors.hrl"). +-include("yaml_tokens.hrl"). +-include("yaml_nodes.hrl"). +-include("internal/yaml_constr.hrl"). + +%% Public API. +-export([ + tags/0, + try_construct_token/3, + construct_token/3, + node_pres/1, + string_to_integer/1, + base2_to_integer/2, + base8_to_integer/2, + base10_to_integer/2, + base16_to_integer/2, + base60_to_integer/3 + ]). + +-define(TAG, "tag:yaml.org,2002:int"). + +%% ------------------------------------------------------------------- +%% Public API. +%% ------------------------------------------------------------------- + +tags() -> [?TAG]. + +try_construct_token(Repr, Node, + #yaml_scalar{tag = #yaml_tag{uri = {non_specific, "?"}}} = Token) -> + try + construct_token(Repr, Node, Token) + catch + _:#yaml_parsing_error{name = not_an_integer} -> + unrecognized + end; +try_construct_token(_, _, _) -> + unrecognized. + +construct_token(#yaml_constr{simple_structs = true}, + undefined, #yaml_scalar{text = Text} = Token) -> + case string_to_integer(Text) of + error -> + exception(Token); + Int -> + {finished, Int} + end; +construct_token(#yaml_constr{simple_structs = false}, + undefined, #yaml_scalar{text = Text} = Token) -> + case string_to_integer(Text) of + error -> + exception(Token); + Int -> + Pres = yaml_constr:get_pres_details(Token), + Node = #yaml_int{ + module = ?MODULE, + tag = ?TAG, + pres = Pres, + value = Int + }, + {finished, Node} + end; + +construct_token(_, _, Token) -> + exception(Token). + +node_pres(Node) -> + ?NODE_PRES(Node). + +%% ------------------------------------------------------------------- +%% Internal functions. +%% ------------------------------------------------------------------- + +%% Sign. +string_to_integer([$+ | Text]) -> string_to_integer2(Text); +string_to_integer([$- | Text]) -> -string_to_integer2(Text); +string_to_integer(Text) -> string_to_integer2(Text). + +%% Base. +string_to_integer2("0b" ++ Text) -> + base2_to_integer(Text, 0); +string_to_integer2("0x" ++ Text) -> + base16_to_integer(Text, 0); +string_to_integer2("0o" ++ Text) -> + base8_to_integer(Text, 0); +string_to_integer2("0" ++ Text) -> + base8_to_integer(Text, 0); +string_to_integer2(Text) -> + Opts = [{capture, none}], + case re:run(Text, "[1-9][0-9_]*(?::[0-5]?[0-9])+", Opts) of + match -> base60_to_integer(Text, 0, 0); + nomatch -> base10_to_integer(Text, 0) + end. + +%% Parsing. +base10_to_integer([C | Rest], Int) when C >= $0 andalso C =< $9 -> + Int1 = (Int * 10) + (C - $0), + base10_to_integer(Rest, Int1); +base10_to_integer([$_ | Rest], Int) -> + base10_to_integer(Rest, Int); +base10_to_integer([], Int) -> + Int; +base10_to_integer(_, _) -> + error. + +base2_to_integer([C | Rest], Int) when C == $0 orelse C == $1 -> + Int1 = (Int * 2) + (C - $0), + base2_to_integer(Rest, Int1); +base2_to_integer([$_ | Rest], Int) -> + base2_to_integer(Rest, Int); +base2_to_integer([], Int) -> + Int; +base2_to_integer(_, _) -> + error. + +base8_to_integer([C | Rest], Int) when C >= $0 andalso C =< $7 -> + Int1 = (Int * 8) + (C - $0), + base8_to_integer(Rest, Int1); +base8_to_integer([$_ | Rest], Int) -> + base8_to_integer(Rest, Int); +base8_to_integer([], Int) -> + Int; +base8_to_integer(_, _) -> + error. + +base16_to_integer([C | Rest], Int) when C >= $0 andalso C =< $9 -> + Int1 = (Int * 16) + (C - $0), + base16_to_integer(Rest, Int1); +base16_to_integer([C | Rest], Int) when C >= $a andalso C =< $f -> + Int1 = (Int * 16) + (C - $a + 10), + base16_to_integer(Rest, Int1); +base16_to_integer([C | Rest], Int) when C >= $A andalso C =< $F -> + Int1 = (Int * 16) + (C - $A + 10), + base16_to_integer(Rest, Int1); +base16_to_integer([$_ | Rest], Int) -> + base16_to_integer(Rest, Int); +base16_to_integer([], Int) -> + Int; +base16_to_integer(_, _) -> + error. + +base60_to_integer([C | Rest], Current, Int) when C >= $0 andalso C =< $9 -> + Current1 = (Current * 10) + (C - $0), + base60_to_integer(Rest, Current1, Int); +base60_to_integer([$: | Rest], Current, Int) -> + Int1 = (Int * 60) + Current, + base60_to_integer(Rest, 0, Int1); +base60_to_integer([$_ | Rest], Current, Int) -> + base60_to_integer(Rest, Current, Int); +base60_to_integer([], Current, Int) -> + (Int * 60) + Current. + +exception(Token) -> + Error = #yaml_parsing_error{ + name = not_an_integer, + token = Token, + text = "Invalid integer", + line = ?TOKEN_LINE(Token), + column = ?TOKEN_COLUMN(Token) + }, + throw(Error). diff --git a/src/yaml_node_float.erl b/src/yaml_node_float.erl new file mode 100644 index 0000000..7234ff1 --- /dev/null +++ b/src/yaml_node_float.erl @@ -0,0 +1,108 @@ +-module(yaml_node_float). + +-include("yaml_errors.hrl"). +-include("yaml_tokens.hrl"). +-include("yaml_nodes.hrl"). +-include("internal/yaml_constr.hrl"). + +%% Public API. +-export([ + tags/0, + try_construct_token/3, + construct_token/3, + node_pres/1, + string_to_float/1 + ]). + +-define(TAG, "tag:yaml.org,2002:float"). + +%% ------------------------------------------------------------------- +%% Public API. +%% ------------------------------------------------------------------- + +tags() -> [?TAG]. + +try_construct_token(Repr, Node, + #yaml_scalar{tag = #yaml_tag{uri = {non_specific, "?"}}} = Token) -> + try + construct_token(Repr, Node, Token) + catch + _:#yaml_parsing_error{name = not_an_float} -> + unrecognized + end; +try_construct_token(_, _, _) -> + unrecognized. + +construct_token(#yaml_constr{simple_structs = true}, + undefined, #yaml_scalar{text = Text} = Token) -> + case string_to_float(Text) of + error -> + exception(Token); + Int -> + {finished, Int} + end; +construct_token(#yaml_constr{simple_structs = false}, + undefined, #yaml_scalar{text = Text} = Token) -> + case string_to_float(Text) of + error -> + exception(Token); + Int -> + Pres = yaml_constr:get_pres_details(Token), + Node = #yaml_int{ + module = ?MODULE, + tag = ?TAG, + pres = Pres, + value = Int + }, + {finished, Node} + end; + +construct_token(_, _, Token) -> + exception(Token). + +node_pres(Node) -> + ?NODE_PRES(Node). + +%% ------------------------------------------------------------------- +%% Internal functions. +%% ------------------------------------------------------------------- + +string_to_float(".nan") -> 'nan'; +string_to_float(".Nan") -> 'nan'; +string_to_float(".NAN") -> 'nan'; +string_to_float(".inf") -> '+inf'; +string_to_float(".Inf") -> '+inf'; +string_to_float(".INF") -> '+inf'; +string_to_float("+.inf") -> '+inf'; +string_to_float("+.Inf") -> '+inf'; +string_to_float("+.INF") -> '+inf'; +string_to_float("-.inf") -> '-inf'; +string_to_float("-.Inf") -> '-inf'; +string_to_float("-.INF") -> '-inf'; +string_to_float([$+ | Text]) -> string_to_float2(Text); +string_to_float([$- | Text]) -> -string_to_float2(Text); +string_to_float(Text) -> string_to_float2(Text). + +string_to_float2(Text) -> + Opts = [{capture, none}], + case re:run(Text, "(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?", Opts) of + match -> string_to_float3(Text); + nomatch -> error + end. + +string_to_float3(Text) -> + try + erlang:list_to_float(Text) + catch + error:badarg -> error + end. + +exception(Token) -> + Error = #yaml_parsing_error{ + name = not_a_float, + token = Token, + text = "Invalid float", + line = ?TOKEN_LINE(Token), + column = ?TOKEN_COLUMN(Token) + }, + throw(Error). diff --git a/src/yaml_node_int.erl b/src/yaml_node_int.erl index 7e2ca61..2f40302 100644 --- a/src/yaml_node_int.erl +++ b/src/yaml_node_int.erl @@ -73,77 +73,12 @@ string_to_integer([$- | Text]) -> -string_to_integer2(Text); string_to_integer(Text) -> string_to_integer2(Text). %% Base. -string_to_integer2("0b" ++ Text) -> - base2_to_integer(Text, 0); string_to_integer2("0x" ++ Text) -> - base16_to_integer(Text, 0); + yaml_node_ext_int:base16_to_integer(Text, 0); string_to_integer2("0o" ++ Text) -> - base8_to_integer(Text, 0); -string_to_integer2("0" ++ Text) -> - base8_to_integer(Text, 0); + yaml_node_ext_int:base8_to_integer(Text, 0); string_to_integer2(Text) -> - case re:run(Text, "[1-9][0-9_]*(?::[0-5]?[0-9])+") of - {match, _} -> base60_to_integer(Text, 0, 0); - nomatch -> base10_to_integer(Text, 0) - end. - -%% Parsing. -base10_to_integer([C | Rest], Int) when C >= $0 andalso C =< $9 -> - Int1 = (Int * 10) + (C - $0), - base10_to_integer(Rest, Int1); -base10_to_integer([$_ | Rest], Int) -> - base10_to_integer(Rest, Int); -base10_to_integer([], Int) -> - Int; -base10_to_integer(_, _) -> - error. - -base2_to_integer([C | Rest], Int) when C == $0 orelse C == $1 -> - Int1 = (Int * 2) + (C - $0), - base2_to_integer(Rest, Int1); -base2_to_integer([$_ | Rest], Int) -> - base2_to_integer(Rest, Int); -base2_to_integer([], Int) -> - Int; -base2_to_integer(_, _) -> - error. - -base8_to_integer([C | Rest], Int) when C >= $0 andalso C =< $7 -> - Int1 = (Int * 8) + (C - $0), - base8_to_integer(Rest, Int1); -base8_to_integer([$_ | Rest], Int) -> - base8_to_integer(Rest, Int); -base8_to_integer([], Int) -> - Int; -base8_to_integer(_, _) -> - error. - -base16_to_integer([C | Rest], Int) when C >= $0 andalso C =< $9 -> - Int1 = (Int * 16) + (C - $0), - base16_to_integer(Rest, Int1); -base16_to_integer([C | Rest], Int) when C >= $a andalso C =< $f -> - Int1 = (Int * 16) + (C - $a + 10), - base16_to_integer(Rest, Int1); -base16_to_integer([C | Rest], Int) when C >= $A andalso C =< $F -> - Int1 = (Int * 16) + (C - $A + 10), - base16_to_integer(Rest, Int1); -base16_to_integer([$_ | Rest], Int) -> - base16_to_integer(Rest, Int); -base16_to_integer([], Int) -> - Int; -base16_to_integer(_, _) -> - error. - -base60_to_integer([C | Rest], Current, Int) when C >= $0 andalso C =< $9 -> - Current1 = (Current * 10) + (C - $0), - base60_to_integer(Rest, Current1, Int); -base60_to_integer([$: | Rest], Current, Int) -> - Int1 = (Int * 60) + Current, - base60_to_integer(Rest, 0, Int1); -base60_to_integer([$_ | Rest], Current, Int) -> - base60_to_integer(Rest, Current, Int); -base60_to_integer([], Current, Int) -> - (Int * 60) + Current. + yaml_node_ext_int:base10_to_integer(Text, 0). exception(Token) -> Error = #yaml_parsing_error{ diff --git a/src/yaml_node_json_bool.erl b/src/yaml_node_json_bool.erl new file mode 100644 index 0000000..8efd17a --- /dev/null +++ b/src/yaml_node_json_bool.erl @@ -0,0 +1,64 @@ +-module(yaml_node_json_bool). + +-include("yaml_tokens.hrl"). +-include("yaml_nodes.hrl"). +-include("internal/yaml_constr.hrl"). + +%% Public API. +-export([ + tags/0, + try_construct_token/3, + construct_token/3, + node_pres/1 + ]). + +-define(TAG, "tag:yaml.org,2002:bool"). + +-define(IS_TRUE(S), + S == "true"). + +-define(IS_FALSE(S), + S == "false"). + +%% ------------------------------------------------------------------- +%% Public API. +%% ------------------------------------------------------------------- + +tags() -> [?TAG]. + +try_construct_token(Repr, Node, + #yaml_scalar{tag = #yaml_tag{uri = {non_specific, "?"}}, + text = Text} = Token) when ?IS_TRUE(Text) orelse ?IS_FALSE(Text) -> + construct_token(Repr, Node, Token); +try_construct_token(_, _, _) -> + unrecognized. + +construct_token(#yaml_constr{simple_structs = true}, + undefined, #yaml_scalar{text = Text}) when ?IS_TRUE(Text) -> + {finished, true}; +construct_token(#yaml_constr{simple_structs = true}, + undefined, #yaml_scalar{text = Text}) when ?IS_FALSE(Text) -> + {finished, false}; +construct_token(#yaml_constr{simple_structs = false}, + undefined, #yaml_scalar{text = Text} = Token) when ?IS_TRUE(Text) -> + Pres = yaml_constr:get_pres_details(Token), + Node = #yaml_bool{ + module = ?MODULE, + tag = ?TAG, + pres = Pres, + value = true + }, + {finished, Node}; +construct_token(#yaml_constr{simple_structs = false}, + undefined, #yaml_scalar{text = Text} = Token) when ?IS_FALSE(Text) -> + Pres = yaml_constr:get_pres_details(Token), + Node = #yaml_bool{ + module = ?MODULE, + tag = ?TAG, + pres = Pres, + value = false + }, + {finished, Node}. + +node_pres(Node) -> + ?NODE_PRES(Node). diff --git a/src/yaml_node_json_float.erl b/src/yaml_node_json_float.erl new file mode 100644 index 0000000..1c44cf5 --- /dev/null +++ b/src/yaml_node_json_float.erl @@ -0,0 +1,99 @@ +-module(yaml_node_json_float). + +-include("yaml_errors.hrl"). +-include("yaml_tokens.hrl"). +-include("yaml_nodes.hrl"). +-include("internal/yaml_constr.hrl"). + +%% Public API. +-export([ + tags/0, + try_construct_token/3, + construct_token/3, + node_pres/1, + string_to_float/1 + ]). + +-define(TAG, "tag:yaml.org,2002:float"). + +%% ------------------------------------------------------------------- +%% Public API. +%% ------------------------------------------------------------------- + +tags() -> [?TAG]. + +try_construct_token(Repr, Node, + #yaml_scalar{tag = #yaml_tag{uri = {non_specific, "?"}}} = Token) -> + try + construct_token(Repr, Node, Token) + catch + _:#yaml_parsing_error{name = not_an_float} -> + unrecognized + end; +try_construct_token(_, _, _) -> + unrecognized. + +construct_token(#yaml_constr{simple_structs = true}, + undefined, #yaml_scalar{text = Text} = Token) -> + case string_to_float(Text) of + error -> + exception(Token); + Int -> + {finished, Int} + end; +construct_token(#yaml_constr{simple_structs = false}, + undefined, #yaml_scalar{text = Text} = Token) -> + case string_to_float(Text) of + error -> + exception(Token); + Int -> + Pres = yaml_constr:get_pres_details(Token), + Node = #yaml_int{ + module = ?MODULE, + tag = ?TAG, + pres = Pres, + value = Int + }, + {finished, Node} + end; + +construct_token(_, _, Token) -> + exception(Token). + +node_pres(Node) -> + ?NODE_PRES(Node). + +%% ------------------------------------------------------------------- +%% Internal functions. +%% ------------------------------------------------------------------- + +string_to_float("0") -> 0.0; +string_to_float(".nan") -> 'nan'; +string_to_float(".inf") -> '+inf'; +string_to_float("-.inf") -> '-inf'; +string_to_float([$- | Text]) -> -string_to_float2(Text); +string_to_float(Text) -> string_to_float2(Text). + +string_to_float2(Text) -> + Opts = [{capture, none}], + case re:run(Text, "(0|[1-9][0-9]*)(\.[0-9]*)?([eE][-+]?[0-9]+)?", Opts) of + match -> string_to_float3(Text); + nomatch -> error + end. + +string_to_float3(Text) -> + try + erlang:list_to_float(Text) + catch + error:badarg -> error + end. + +exception(Token) -> + Error = #yaml_parsing_error{ + name = not_a_float, + token = Token, + text = "Invalid float", + line = ?TOKEN_LINE(Token), + column = ?TOKEN_COLUMN(Token) + }, + throw(Error). diff --git a/src/yaml_node_json_int.erl b/src/yaml_node_json_int.erl new file mode 100644 index 0000000..054b365 --- /dev/null +++ b/src/yaml_node_json_int.erl @@ -0,0 +1,88 @@ +-module(yaml_node_json_int). + +-include("yaml_errors.hrl"). +-include("yaml_tokens.hrl"). +-include("yaml_nodes.hrl"). +-include("internal/yaml_constr.hrl"). + +%% Public API. +-export([ + tags/0, + try_construct_token/3, + construct_token/3, + node_pres/1, + string_to_integer/1 + ]). + +-define(TAG, "tag:yaml.org,2002:int"). + +%% ------------------------------------------------------------------- +%% Public API. +%% ------------------------------------------------------------------- + +tags() -> [?TAG]. + +try_construct_token(Repr, Node, + #yaml_scalar{tag = #yaml_tag{uri = {non_specific, "?"}}} = Token) -> + try + construct_token(Repr, Node, Token) + catch + _:#yaml_parsing_error{name = not_an_integer} -> + unrecognized + end; +try_construct_token(_, _, _) -> + unrecognized. + +construct_token(#yaml_constr{simple_structs = true}, + undefined, #yaml_scalar{text = Text} = Token) -> + case string_to_integer(Text) of + error -> + exception(Token); + Int -> + {finished, Int} + end; +construct_token(#yaml_constr{simple_structs = false}, + undefined, #yaml_scalar{text = Text} = Token) -> + case string_to_integer(Text) of + error -> + exception(Token); + Int -> + Pres = yaml_constr:get_pres_details(Token), + Node = #yaml_int{ + module = ?MODULE, + tag = ?TAG, + pres = Pres, + value = Int + }, + {finished, Node} + end; + +construct_token(_, _, Token) -> + exception(Token). + +node_pres(Node) -> + ?NODE_PRES(Node). + +%% ------------------------------------------------------------------- +%% Internal functions. +%% ------------------------------------------------------------------- + +%% Zero and sign. +string_to_integer("0") -> + 0; +string_to_integer([$-, C | Text]) when C >= $1 andalso C =< $9 -> + -yaml_node_ext_int:base10_to_integer(Text, C - $0); +string_to_integer([C | Text]) when C >= $1 andalso C =< $9 -> + yaml_node_ext_int:base10_to_integer(Text, C - $0); +string_to_integer(_) -> + error. + +exception(Token) -> + Error = #yaml_parsing_error{ + name = not_an_integer, + token = Token, + text = "Invalid integer", + line = ?TOKEN_LINE(Token), + column = ?TOKEN_COLUMN(Token) + }, + throw(Error). diff --git a/src/yaml_node_json_null.erl b/src/yaml_node_json_null.erl new file mode 100644 index 0000000..53791ce --- /dev/null +++ b/src/yaml_node_json_null.erl @@ -0,0 +1,44 @@ +-module(yaml_node_json_null). + +-include("yaml_tokens.hrl"). +-include("yaml_nodes.hrl"). +-include("internal/yaml_constr.hrl"). + +%% Public API. +-export([ + tags/0, + try_construct_token/3, + construct_token/3, + node_pres/1 + ]). + +-define(TAG, "tag:yaml.org,2002:null"). + +%% ------------------------------------------------------------------- +%% Public API. +%% ------------------------------------------------------------------- + +tags() -> [?TAG]. + +try_construct_token(Repr, Node, + #yaml_scalar{tag = #yaml_tag{uri = {non_specific, "?"}}, + text = "null"} = Token) -> + construct_token(Repr, Node, Token); +try_construct_token(_, _, _) -> + unrecognized. + +construct_token(#yaml_constr{simple_structs = true}, + undefined, #yaml_scalar{}) -> + {finished, null}; +construct_token(#yaml_constr{simple_structs = false}, + undefined, #yaml_scalar{} = Token) -> + Pres = yaml_constr:get_pres_details(Token), + Node = #yaml_null{ + module = ?MODULE, + tag = ?TAG, + pres = Pres + }, + {finished, Node}. + +node_pres(Node) -> + ?NODE_PRES(Node).