diff options
author | Louis Pilfold <louis@lpil.uk> | 2021-09-09 21:53:51 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2021-09-09 21:53:51 +0100 |
commit | 3546644ebcd8112b089555e69dcd7a5dad5b434b (patch) | |
tree | 0525c7ac4274c3ef1a91907b75f3f1f30897d25e | |
parent | bb88a32d105da31e5cdd2ad713016c88b96ac0ce (diff) | |
download | gleam_stdlib-3546644ebcd8112b089555e69dcd7a5dad5b434b.tar.gz gleam_stdlib-3546644ebcd8112b089555e69dcd7a5dad5b434b.zip |
Negative indexes in Erlang
-rw-r--r-- | src/gleam_stdlib.erl | 53 | ||||
-rw-r--r-- | src/gleam_stdlib.js | 2 | ||||
-rw-r--r-- | test/gleam/dynamic_test.gleam | 92 |
3 files changed, 98 insertions, 49 deletions
diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl index 92cae8e..2f234e7 100644 --- a/src/gleam_stdlib.erl +++ b/src/gleam_stdlib.erl @@ -59,24 +59,31 @@ classify(X) when is_integer(X) -> <<"Int">>; classify(X) when is_float(X) -> <<"Float">>; classify(X) when is_list(X) -> <<"List">>; classify(X) when is_boolean(X) -> <<"Bool">>; -classify(X) when is_function(X, 0) -> <<"zero arity function">>; -classify(X) when is_tuple(X) -> iolist_to_binary([integer_to_list(tuple_size(X)), " element tuple"]); -classify(_) -> "some other type". +classify(X) when is_map(X) -> <<"Map">>; +classify(X) when is_tuple(X) -> + iolist_to_binary(["Tuple of ", integer_to_list(tuple_size(X)), " elements"]); +classify(X) when + is_function(X, 0) orelse is_function(X, 1) orelse is_function(X, 2) orelse + is_function(X, 3) orelse is_function(X, 4) orelse is_function(X, 5) orelse + is_function(X, 6) orelse is_function(X, 7) orelse is_function(X, 8) orelse + is_function(X, 9) orelse is_function(X, 10) orelse is_function(X, 11) orelse + is_function(X, 12) -> <<"Function">>; +classify(_) -> "Some other type". decode_tuple2({_, _} = T) -> {ok, T}; -decode_tuple2(Data) -> decode_error_msg(<<"2 element tuple">>, Data). +decode_tuple2(Data) -> decode_error_msg(<<"Tuple of 2 elements">>, Data). decode_tuple3({_, _, _} = T) -> {ok, T}; -decode_tuple3(Data) -> decode_error_msg(<<"3 element tuple">>, Data). +decode_tuple3(Data) -> decode_error_msg(<<"Tuple of 3 elements">>, Data). decode_tuple4({_, _, _, _} = T) -> {ok, T}; -decode_tuple4(Data) -> decode_error_msg(<<"4 element tuple">>, Data). +decode_tuple4(Data) -> decode_error_msg(<<"Tuple of 4 elements">>, Data). decode_tuple5({_, _, _, _, _} = T) -> {ok, T}; -decode_tuple5(Data) -> decode_error_msg(<<"5 element tuple">>, Data). +decode_tuple5(Data) -> decode_error_msg(<<"Tuple of 5 elements">>, Data). decode_tuple6({_, _, _, _, _, _} = T) -> {ok, T}; -decode_tuple6(Data) -> decode_error_msg(<<"6 element tuple">>, Data). +decode_tuple6(Data) -> decode_error_msg(<<"Tuple of 6 elements">>, Data). decode_map(Data) when is_map(Data) -> {ok, Data}; decode_map(Data) -> decode_error_msg(<<"Map">>, Data). @@ -108,16 +115,28 @@ decode_field(Data, Key) -> decode_error_msg(io_lib:format("a map with key `~p`", [Key]), Data) end. -decode_element(Data, Position) when is_tuple(Data) -> - case catch element(Position + 1, Data) of - {'EXIT', _Reason} -> - Msg = ["Tuple of at least ", integer_to_list(Position + 1), " elements"], - decode_error_msg(list_to_binary(Msg), Data); - - Value -> - {ok, Value} +decode_element(Data, Index) when is_tuple(Data) -> + Error = fun(Size) -> + S = case Size of + 1 -> "s"; + _ -> "" + end, + Msg = list_to_binary(["Tuple of at least ", integer_to_list(Size), S, " elements"]), + decode_error_msg(Msg, Data) + end, + Size = tuple_size(Data), + case Index >= 0 of + true -> case Index < Size of + true -> {ok, element(Index + 1, Data)}; + false -> Error(Index + 1) + end; + false -> case abs(Index) < Size of + true -> {ok, element(Size + Index + 1, Data)}; + false -> Error(abs(Index)) + end end; -decode_element(Data, _Position) -> decode_error_msg(<<"Tuple">>, Data). +decode_element(Data, _Position) -> + decode_error_msg(<<"Tuple of at least 1 element">>, Data). decode_optional(Term, F) -> Decode = fun(Inner) -> diff --git a/src/gleam_stdlib.js b/src/gleam_stdlib.js index 9a80a6d..7ecbe11 100644 --- a/src/gleam_stdlib.js +++ b/src/gleam_stdlib.js @@ -521,7 +521,7 @@ export function decode_bit_string(data) { export function decode_element(data, index) { let error = (size) => decoder_error( - `Tuple of at least ${size} element${size > 1 ? "s" : ""}`, + `Tuple of at least ${size} element${size == 1 ? "" : "s"}`, data ); if (!Array.isArray(data)) return error(index < 0 ? 1 : index + 1); diff --git a/test/gleam/dynamic_test.gleam b/test/gleam/dynamic_test.gleam index 4ab3d65..1bf0eee 100644 --- a/test/gleam/dynamic_test.gleam +++ b/test/gleam/dynamic_test.gleam @@ -324,14 +324,17 @@ if erlang { |> dynamic.from |> dynamic.tuple2 |> should.equal(Error(DecodeError( - expected: "2 element tuple", - found: "3 element tuple", + expected: "Tuple of 2 elements", + found: "Tuple of 3 elements", ))) 1 |> dynamic.from |> dynamic.tuple2 - |> should.equal(Error(DecodeError(expected: "2 element tuple", found: "Int"))) + |> should.equal(Error(DecodeError( + expected: "Tuple of 2 elements", + found: "Int", + ))) } pub fn typed_tuple2_test() { @@ -354,14 +357,17 @@ if erlang { |> dynamic.from |> dynamic.typed_tuple2(dynamic.int, dynamic.int) |> should.equal(Error(DecodeError( - expected: "2 element tuple", - found: "3 element tuple", + expected: "Tuple of 2 elements", + found: "Tuple of 3 elements", ))) 1 |> dynamic.from |> dynamic.typed_tuple2(dynamic.int, dynamic.int) - |> should.equal(Error(DecodeError(expected: "2 element tuple", found: "Int"))) + |> should.equal(Error(DecodeError( + expected: "Tuple of 2 elements", + found: "Int", + ))) } pub fn tuple3_test() { @@ -379,14 +385,17 @@ if erlang { |> dynamic.from |> dynamic.tuple3 |> should.equal(Error(DecodeError( - expected: "3 element tuple", - found: "2 element tuple", + expected: "Tuple of 3 elements", + found: "Tuple of 2 elements", ))) 1 |> dynamic.from |> dynamic.tuple3 - |> should.equal(Error(DecodeError(expected: "3 element tuple", found: "Int"))) + |> should.equal(Error(DecodeError( + expected: "Tuple of 3 elements", + found: "Int", + ))) } pub fn typed_tuple3_test() { @@ -409,14 +418,17 @@ if erlang { |> dynamic.from |> dynamic.typed_tuple3(dynamic.int, dynamic.int, dynamic.int) |> should.equal(Error(DecodeError( - expected: "3 element tuple", - found: "2 element tuple", + expected: "Tuple of 3 elements", + found: "Tuple of 2 elements", ))) 1 |> dynamic.from |> dynamic.typed_tuple3(dynamic.int, dynamic.int, dynamic.int) - |> should.equal(Error(DecodeError(expected: "3 element tuple", found: "Int"))) + |> should.equal(Error(DecodeError( + expected: "Tuple of 3 elements", + found: "Int", + ))) } pub fn tuple4_test() { @@ -444,14 +456,17 @@ if erlang { |> dynamic.from |> dynamic.tuple4 |> should.equal(Error(DecodeError( - expected: "4 element tuple", - found: "2 element tuple", + expected: "Tuple of 4 elements", + found: "Tuple of 2 elements", ))) 1 |> dynamic.from |> dynamic.tuple4 - |> should.equal(Error(DecodeError(expected: "4 element tuple", found: "Int"))) + |> should.equal(Error(DecodeError( + expected: "Tuple of 4 elements", + found: "Int", + ))) } pub fn typed_tuple4_test() { @@ -479,14 +494,17 @@ if erlang { |> dynamic.from |> dynamic.typed_tuple4(dynamic.int, dynamic.int, dynamic.int, dynamic.int) |> should.equal(Error(DecodeError( - expected: "4 element tuple", - found: "2 element tuple", + expected: "Tuple of 4 elements", + found: "Tuple of 2 elements", ))) 1 |> dynamic.from |> dynamic.typed_tuple4(dynamic.int, dynamic.int, dynamic.int, dynamic.int) - |> should.equal(Error(DecodeError(expected: "4 element tuple", found: "Int"))) + |> should.equal(Error(DecodeError( + expected: "Tuple of 4 elements", + found: "Int", + ))) } pub fn tuple5_test() { @@ -516,14 +534,17 @@ if erlang { |> dynamic.from |> dynamic.tuple5 |> should.equal(Error(DecodeError( - expected: "5 element tuple", - found: "2 element tuple", + expected: "Tuple of 5 elements", + found: "Tuple of 2 elements", ))) 1 |> dynamic.from |> dynamic.tuple5 - |> should.equal(Error(DecodeError(expected: "5 element tuple", found: "Int"))) + |> should.equal(Error(DecodeError( + expected: "Tuple of 5 elements", + found: "Int", + ))) } pub fn typed_tuple5_test() { @@ -570,8 +591,8 @@ if erlang { dynamic.int, ) |> should.equal(Error(DecodeError( - expected: "5 element tuple", - found: "2 element tuple", + expected: "Tuple of 5 elements", + found: "Tuple of 2 elements", ))) 1 @@ -583,7 +604,10 @@ if erlang { dynamic.int, dynamic.int, ) - |> should.equal(Error(DecodeError(expected: "5 element tuple", found: "Int"))) + |> should.equal(Error(DecodeError( + expected: "Tuple of 5 elements", + found: "Int", + ))) } pub fn tuple6_test() { @@ -615,14 +639,17 @@ if erlang { |> dynamic.from |> dynamic.tuple6 |> should.equal(Error(DecodeError( - expected: "6 element tuple", - found: "2 element tuple", + expected: "Tuple of 6 elements", + found: "Tuple of 2 elements", ))) 1 |> dynamic.from |> dynamic.tuple6 - |> should.equal(Error(DecodeError(expected: "6 element tuple", found: "Int"))) + |> should.equal(Error(DecodeError( + expected: "Tuple of 6 elements", + found: "Int", + ))) } pub fn typed_tuple6_test() { @@ -673,8 +700,8 @@ if erlang { dynamic.int, ) |> should.equal(Error(DecodeError( - expected: "6 element tuple", - found: "2 element tuple", + expected: "Tuple of 6 elements", + found: "Tuple of 2 elements", ))) 1 @@ -687,7 +714,10 @@ if erlang { dynamic.int, dynamic.int, ) - |> should.equal(Error(DecodeError(expected: "6 element tuple", found: "Int"))) + |> should.equal(Error(DecodeError( + expected: "Tuple of 6 elements", + found: "Int", + ))) } pub fn map_test() { @@ -745,7 +775,7 @@ if erlang { |> dynamic.result |> should.equal(Error(DecodeError( expected: "result tuple", - found: "2 element tuple", + found: "Tuple of 2 elements", ))) } |