aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/src')
-rw-r--r--lib/stdlib/src/array.erl111
-rw-r--r--lib/stdlib/src/base64.erl24
-rw-r--r--lib/stdlib/src/beam_lib.erl150
-rw-r--r--lib/stdlib/src/binary.erl37
-rw-r--r--lib/stdlib/src/c.erl68
-rw-r--r--lib/stdlib/src/calendar.erl109
-rw-r--r--lib/stdlib/src/dets.erl414
-rw-r--r--lib/stdlib/src/dets.hrl3
-rw-r--r--lib/stdlib/src/dets_v8.erl20
-rw-r--r--lib/stdlib/src/dets_v9.erl118
-rw-r--r--lib/stdlib/src/dict.erl99
-rw-r--r--lib/stdlib/src/digraph.erl159
-rw-r--r--lib/stdlib/src/digraph_utils.erl84
-rw-r--r--lib/stdlib/src/epp.erl52
-rw-r--r--lib/stdlib/src/erl_compile.erl3
-rw-r--r--lib/stdlib/src/erl_eval.erl144
-rw-r--r--lib/stdlib/src/erl_expand_records.erl8
-rw-r--r--lib/stdlib/src/erl_internal.erl42
-rw-r--r--lib/stdlib/src/erl_lint.erl79
-rw-r--r--lib/stdlib/src/erl_parse.yrl49
-rw-r--r--lib/stdlib/src/erl_pp.erl65
-rw-r--r--lib/stdlib/src/erl_scan.erl122
-rw-r--r--lib/stdlib/src/erl_tar.erl30
-rw-r--r--lib/stdlib/src/error_logger_tty_h.erl69
-rw-r--r--lib/stdlib/src/escript.erl8
-rw-r--r--lib/stdlib/src/ets.erl148
-rw-r--r--lib/stdlib/src/eval_bits.erl57
-rw-r--r--lib/stdlib/src/file_sorter.erl119
-rw-r--r--lib/stdlib/src/filelib.erl39
-rw-r--r--lib/stdlib/src/filename.erl84
-rw-r--r--lib/stdlib/src/gb_sets.erl147
-rw-r--r--lib/stdlib/src/gb_trees.erl109
-rw-r--r--lib/stdlib/src/gen.erl9
-rw-r--r--lib/stdlib/src/gen_event.erl97
-rw-r--r--lib/stdlib/src/gen_fsm.erl58
-rw-r--r--lib/stdlib/src/gen_server.erl52
-rw-r--r--lib/stdlib/src/io.erl195
-rw-r--r--lib/stdlib/src/io_lib.erl78
-rw-r--r--lib/stdlib/src/io_lib_fread.erl103
-rw-r--r--lib/stdlib/src/lib.erl66
-rw-r--r--lib/stdlib/src/lists.erl430
-rw-r--r--lib/stdlib/src/log_mf_h.erl21
-rw-r--r--lib/stdlib/src/ms_transform.erl16
-rw-r--r--lib/stdlib/src/orddict.erl98
-rw-r--r--lib/stdlib/src/ordsets.erl72
-rw-r--r--lib/stdlib/src/otp_internal.erl142
-rw-r--r--lib/stdlib/src/pg.erl28
-rw-r--r--lib/stdlib/src/pool.erl27
-rw-r--r--lib/stdlib/src/proc_lib.erl138
-rw-r--r--lib/stdlib/src/proplists.erl154
-rw-r--r--lib/stdlib/src/qlc.erl311
-rw-r--r--lib/stdlib/src/qlc_pt.erl18
-rw-r--r--lib/stdlib/src/queue.erl66
-rw-r--r--lib/stdlib/src/random.erl22
-rw-r--r--lib/stdlib/src/re.erl63
-rw-r--r--lib/stdlib/src/regexp.erl69
-rw-r--r--lib/stdlib/src/sets.erl74
-rw-r--r--lib/stdlib/src/shell.erl25
-rw-r--r--lib/stdlib/src/slave.erl52
-rw-r--r--lib/stdlib/src/sofs.erl546
-rw-r--r--lib/stdlib/src/string.erl175
-rw-r--r--lib/stdlib/src/supervisor.erl208
-rw-r--r--lib/stdlib/src/supervisor_bridge.erl27
-rw-r--r--lib/stdlib/src/sys.erl182
-rw-r--r--lib/stdlib/src/timer.erl142
-rw-r--r--lib/stdlib/src/unicode.erl63
-rw-r--r--lib/stdlib/src/win32reg.erl70
-rw-r--r--lib/stdlib/src/zip.erl187
68 files changed, 5270 insertions, 1584 deletions
diff --git a/lib/stdlib/src/array.erl b/lib/stdlib/src/array.erl
index 83576c9fd3..2f69e2b0a4 100644
--- a/lib/stdlib/src/array.erl
+++ b/lib/stdlib/src/array.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -163,17 +163,17 @@
-type array_indx() :: non_neg_integer().
--type array_opt() :: 'fixed' | non_neg_integer()
- | {'default', term()} | {'fixed', boolean()}
- | {'size', non_neg_integer()}.
+-type array_opt() :: {'fixed', boolean()} | 'fixed'
+ | {'default', Value :: term()}
+ | {'size', N :: non_neg_integer()}
+ | (N :: non_neg_integer()).
-type array_opts() :: array_opt() | [array_opt()].
--type indx_pair() :: {array_indx(), term()}.
+-type indx_pair() :: {Index :: array_indx(), Value :: term()}.
-type indx_pairs() :: [indx_pair()].
%%--------------------------------------------------------------------------
-%% @spec () -> array()
%% @doc Create a new, extendible array with initial size zero.
%% @equiv new([])
%%
@@ -185,7 +185,6 @@
new() ->
new([]).
-%% @spec (Options::term()) -> array()
%% @doc Create a new array according to the given options. By default,
%% the array is extendible and has initial size zero. Array indices
%% start at 0.
@@ -224,12 +223,11 @@ new() ->
%% @see from_list/2
%% @see fix/1
--spec new(array_opts()) -> array().
+-spec new(Options :: array_opts()) -> array().
new(Options) ->
new_0(Options, 0, false).
-%% @spec (Size::integer(), Options::term()) -> array()
%% @doc Create a new array according to the given size and options. If
%% `Size' is not a nonnegative integer, the call fails with reason
%% `badarg'. By default, the array has fixed size. Note that any size
@@ -245,7 +243,7 @@ new(Options) ->
%%
%% @see new/1
--spec new(non_neg_integer(), array_opts()) -> array().
+-spec new(Size :: non_neg_integer(), Options :: array_opts()) -> array().
new(Size, Options) when is_integer(Size), Size >= 0 ->
new_0(Options, Size, true);
@@ -293,13 +291,12 @@ find_max(_I, M) ->
M.
-%% @spec (X::term()) -> boolean()
%% @doc Returns `true' if `X' appears to be an array, otherwise `false'.
%% Note that the check is only shallow; there is no guarantee that `X'
%% is a well-formed array representation even if this function returns
%% `true'.
--spec is_array(term()) -> boolean().
+-spec is_array(X :: term()) -> boolean().
is_array(#array{size = Size, max = Max})
when is_integer(Size), is_integer(Max) ->
@@ -308,25 +305,23 @@ is_array(_) ->
false.
-%% @spec (array()) -> integer()
%% @doc Get the number of entries in the array. Entries are numbered
%% from 0 to `size(Array)-1'; hence, this is also the index of the first
%% entry that is guaranteed to not have been previously set.
%% @see set/3
%% @see sparse_size/1
--spec size(array()) -> non_neg_integer().
+-spec size(Array :: array()) -> non_neg_integer().
size(#array{size = N}) -> N;
size(_) -> erlang:error(badarg).
-%% @spec (array()) -> term()
%% @doc Get the value used for uninitialized entries.
%%
%% @see new/2
--spec default(array()) -> term().
+-spec default(Array :: array()) -> term().
default(#array{default = D}) -> D;
default(_) -> erlang:error(badarg).
@@ -405,23 +400,21 @@ new_test_() ->
-endif.
-%% @spec (array()) -> array()
%% @doc Fix the size of the array. This prevents it from growing
%% automatically upon insertion; see also {@link set/3}.
%% @see relax/1
--spec fix(array()) -> array().
+-spec fix(Array :: array()) -> array().
fix(#array{}=A) ->
A#array{max = 0}.
-%% @spec (array()) -> boolean()
%% @doc Check if the array has fixed size.
%% Returns `true' if the array is fixed, otherwise `false'.
%% @see fix/1
--spec is_fix(array()) -> boolean().
+-spec is_fix(Array :: array()) -> boolean().
is_fix(#array{max = 0}) -> true;
is_fix(#array{}) -> false.
@@ -455,12 +448,11 @@ fix_test_() ->
-endif.
-%% @spec (array()) -> array()
%% @doc Make the array resizable. (Reverses the effects of {@link
%% fix/1}.)
%% @see fix/1
--spec relax(array()) -> array().
+-spec relax(Array :: array()) -> array().
relax(#array{size = N}=A) ->
A#array{max = find_max(N-1, ?LEAFSIZE)}.
@@ -481,12 +473,11 @@ relax_test_() ->
-endif.
-%% @spec (integer(), array()) -> array()
%% @doc Change the size of the array. If `Size' is not a nonnegative
%% integer, the call fails with reason `badarg'. If the given array has
%% fixed size, the resulting array will also have fixed size.
--spec resize(non_neg_integer(), array()) -> array().
+-spec resize(Size :: non_neg_integer(), Array :: array()) -> array().
resize(Size, #array{size = N, max = M, elements = E}=A)
when is_integer(Size), Size >= 0 ->
@@ -510,8 +501,6 @@ resize(_Size, _) ->
erlang:error(badarg).
-%% @spec (array()) -> array()
-
%% @doc Change the size of the array to that reported by {@link
%% sparse_size/1}. If the given array has fixed size, the resulting
%% array will also have fixed size.
@@ -519,7 +508,7 @@ resize(_Size, _) ->
%% @see resize/2
%% @see sparse_size/1
--spec resize(array()) -> array().
+-spec resize(Array :: array()) -> array().
resize(Array) ->
resize(sparse_size(Array), Array).
@@ -559,7 +548,6 @@ resize_test_() ->
-endif.
-%% @spec (integer(), term(), array()) -> array()
%% @doc Set entry `I' of the array to `Value'. If `I' is not a
%% nonnegative integer, or if the array has fixed size and `I' is larger
%% than the maximum index, the call fails with reason `badarg'.
@@ -570,7 +558,7 @@ resize_test_() ->
%% @see get/2
%% @see reset/2
--spec set(array_indx(), term(), array()) -> array().
+-spec set(I :: array_indx(), Value :: term(), Array :: array()) -> array().
set(I, Value, #array{size = N, max = M, default = D, elements = E}=A)
when is_integer(I), I >= 0 ->
@@ -624,7 +612,6 @@ expand(I, _S, X, D) ->
setelement(I+1, ?NEW_LEAF(D), X).
-%% @spec (integer(), array()) -> term()
%% @doc Get the value of entry `I'. If `I' is not a nonnegative
%% integer, or if the array has fixed size and `I' is larger than the
%% maximum index, the call fails with reason `badarg'.
@@ -634,7 +621,7 @@ expand(I, _S, X, D) ->
%% @see set/3
--spec get(array_indx(), array()) -> term().
+-spec get(I :: array_indx(), Array :: array()) -> term().
get(I, #array{size = N, max = M, elements = E, default = D})
when is_integer(I), I >= 0 ->
@@ -660,7 +647,6 @@ get_1(I, E, _D) ->
element(I+1, E).
-%% @spec (integer(), array()) -> array()
%% @doc Reset entry `I' to the default value for the array.
%% If the value of entry `I' is the default value the array will be
%% returned unchanged. Reset will never change size of the array.
@@ -675,7 +661,7 @@ get_1(I, E, _D) ->
%% TODO: a reset_range function
--spec reset(array_indx(), array()) -> array().
+-spec reset(I :: array_indx(), Array :: array()) -> array().
reset(I, #array{size = N, max = M, default = D, elements = E}=A)
when is_integer(I), I >= 0 ->
@@ -756,13 +742,12 @@ set_get_test_() ->
-endif.
-%% @spec (array()) -> list()
%% @doc Converts the array to a list.
%%
%% @see from_list/2
%% @see sparse_to_list/1
--spec to_list(array()) -> list().
+-spec to_list(Array :: array()) -> list().
to_list(#array{size = 0}) ->
[];
@@ -831,12 +816,11 @@ to_list_test_() ->
-endif.
-%% @spec (array()) -> list()
%% @doc Converts the array to a list, skipping default-valued entries.
%%
%% @see to_list/1
--spec sparse_to_list(array()) -> list().
+-spec sparse_to_list(Array :: array()) -> list().
sparse_to_list(#array{size = 0}) ->
[];
@@ -901,15 +885,13 @@ sparse_to_list_test_() ->
-endif.
-%% @spec (list()) -> array()
%% @equiv from_list(List, undefined)
--spec from_list(list()) -> array().
+-spec from_list(List :: list()) -> array().
from_list(List) ->
from_list(List, undefined).
-%% @spec (list(), term()) -> array()
%% @doc Convert a list to an extendible array. `Default' is used as the value
%% for uninitialized entries of the array. If `List' is not a proper list,
%% the call fails with reason `badarg'.
@@ -917,7 +899,7 @@ from_list(List) ->
%% @see new/2
%% @see to_list/1
--spec from_list(list(), term()) -> array().
+-spec from_list(List :: list(), Default :: term()) -> array().
from_list([], Default) ->
new({default,Default});
@@ -1011,13 +993,12 @@ from_list_test_() ->
-endif.
-%% @spec (array()) -> [{Index::integer(), Value::term()}]
%% @doc Convert the array to an ordered list of pairs `{Index, Value}'.
%%
%% @see from_orddict/2
%% @see sparse_to_orddict/1
--spec to_orddict(array()) -> indx_pairs().
+-spec to_orddict(Array :: array()) -> indx_pairs().
to_orddict(#array{size = 0}) ->
[];
@@ -1104,13 +1085,12 @@ to_orddict_test_() ->
-endif.
-%% @spec (array()) -> [{Index::integer(), Value::term()}]
%% @doc Convert the array to an ordered list of pairs `{Index, Value}',
%% skipping default-valued entries.
%%
%% @see to_orddict/1
--spec sparse_to_orddict(array()) -> indx_pairs().
+-spec sparse_to_orddict(Array :: array()) -> indx_pairs().
sparse_to_orddict(#array{size = 0}) ->
[];
@@ -1188,15 +1168,13 @@ sparse_to_orddict_test_() ->
-endif.
-%% @spec (list()) -> array()
%% @equiv from_orddict(Orddict, undefined)
--spec from_orddict(indx_pairs()) -> array().
+-spec from_orddict(Orddict :: indx_pairs()) -> array().
from_orddict(Orddict) ->
from_orddict(Orddict, undefined).
-%% @spec (list(), term()) -> array()
%% @doc Convert an ordered list of pairs `{Index, Value}' to a
%% corresponding extendible array. `Default' is used as the value for
%% uninitialized entries of the array. If `List' is not a proper,
@@ -1206,7 +1184,7 @@ from_orddict(Orddict) ->
%% @see new/2
%% @see to_orddict/1
--spec from_orddict(indx_pairs(), term()) -> array().
+-spec from_orddict(Orddict :: indx_pairs(), Default :: term()) -> array().
from_orddict([], Default) ->
new({default,Default});
@@ -1392,7 +1370,6 @@ from_orddict_test_() ->
-endif.
-%% @spec (Function, array()) -> array()
%% Function = (Index::integer(), Value::term()) -> term()
%% @doc Map the given function onto each element of the array. The
%% elements are visited in order from the lowest index to the highest.
@@ -1402,7 +1379,8 @@ from_orddict_test_() ->
%% @see foldr/3
%% @see sparse_map/2
--spec map(fun((array_indx(), _) -> _), array()) -> array().
+-spec map(Function, Array :: array()) -> array() when
+ Function :: fun((Index :: array_indx(), Value :: _) -> _).
map(Function, Array=#array{size = N, elements = E, default = D})
when is_function(Function, 2) ->
@@ -1485,7 +1463,6 @@ map_test_() ->
-endif.
-%% @spec (Function, array()) -> array()
%% Function = (Index::integer(), Value::term()) -> term()
%% @doc Map the given function onto each element of the array, skipping
%% default-valued entries. The elements are visited in order from the
@@ -1494,7 +1471,8 @@ map_test_() ->
%%
%% @see map/2
--spec sparse_map(fun((array_indx(), _) -> _), array()) -> array().
+-spec sparse_map(Function, Array :: array()) -> array() when
+ Function :: fun((Index :: array_indx(), Value :: _) -> _).
sparse_map(Function, Array=#array{size = N, elements = E, default = D})
when is_function(Function, 2) ->
@@ -1580,9 +1558,6 @@ sparse_map_test_() ->
-endif.
-%% @spec (Function, InitialAcc::term(), array()) -> term()
-%% Function = (Index::integer(), Value::term(), Acc::term()) ->
-%% term()
%% @doc Fold the elements of the array using the given function and
%% initial accumulator value. The elements are visited in order from the
%% lowest index to the highest. If `Function' is not a function, the
@@ -1592,7 +1567,8 @@ sparse_map_test_() ->
%% @see map/2
%% @see sparse_foldl/3
--spec foldl(fun((array_indx(), _, A) -> B), A, array()) -> B.
+-spec foldl(Function, InitialAcc :: A, Array :: array()) -> B when
+ Function :: fun((Index :: array_indx(), Value :: _, Acc :: A) -> B).
foldl(Function, A, #array{size = N, elements = E, default = D})
when is_function(Function, 3) ->
@@ -1656,9 +1632,6 @@ foldl_test_() ->
-endif.
-%% @spec (Function, InitialAcc::term(), array()) -> term()
-%% Function = (Index::integer(), Value::term(), Acc::term()) ->
-%% term()
%% @doc Fold the elements of the array using the given function and
%% initial accumulator value, skipping default-valued entries. The
%% elements are visited in order from the lowest index to the highest.
@@ -1667,7 +1640,8 @@ foldl_test_() ->
%% @see foldl/3
%% @see sparse_foldr/3
--spec sparse_foldl(fun((array_indx(), _, A) -> B), A, array()) -> B.
+-spec sparse_foldl(Function, InitialAcc :: A, Array :: array()) -> B when
+ Function :: fun((Index :: array_indx(), Value :: _, Acc :: A) -> B).
sparse_foldl(Function, A, #array{size = N, elements = E, default = D})
when is_function(Function, 3) ->
@@ -1735,9 +1709,6 @@ sparse_foldl_test_() ->
-endif.
-%% @spec (Function, InitialAcc::term(), array()) -> term()
-%% Function = (Index::integer(), Value::term(), Acc::term()) ->
-%% term()
%% @doc Fold the elements of the array right-to-left using the given
%% function and initial accumulator value. The elements are visited in
%% order from the highest index to the lowest. If `Function' is not a
@@ -1746,7 +1717,8 @@ sparse_foldl_test_() ->
%% @see foldl/3
%% @see map/2
--spec foldr(fun((array_indx(), _, A) -> B), A, array()) -> B.
+-spec foldr(Function, InitialAcc :: A, Array :: array()) -> B when
+ Function :: fun((Index :: array_indx(), Value :: _, Acc :: A) -> B).
foldr(Function, A, #array{size = N, elements = E, default = D})
when is_function(Function, 3) ->
@@ -1815,9 +1787,6 @@ foldr_test_() ->
-endif.
-%% @spec (Function, InitialAcc::term(), array()) -> term()
-%% Function = (Index::integer(), Value::term(), Acc::term()) ->
-%% term()
%% @doc Fold the elements of the array right-to-left using the given
%% function and initial accumulator value, skipping default-valued
%% entries. The elements are visited in order from the highest index to
@@ -1827,7 +1796,8 @@ foldr_test_() ->
%% @see foldr/3
%% @see sparse_foldl/3
--spec sparse_foldr(fun((array_indx(), _, A) -> B), A, array()) -> B.
+-spec sparse_foldr(Function, InitialAcc :: A, Array :: array()) -> B when
+ Function :: fun((Index :: array_indx(), Value :: _, Acc :: A) -> B).
sparse_foldr(Function, A, #array{size = N, elements = E, default = D})
when is_function(Function, 3) ->
@@ -1870,7 +1840,6 @@ sparse_foldr_3(I, T, Ix, A, F, D) ->
end.
-%% @spec (array()) -> integer()
%% @doc Get the number of entries in the array up until the last
%% non-default valued entry. In other words, returns `I+1' if `I' is the
%% last non-default valued entry in the array, or zero if no such entry
@@ -1878,7 +1847,7 @@ sparse_foldr_3(I, T, Ix, A, F, D) ->
%% @see size/1
%% @see resize/1
--spec sparse_size(array()) -> non_neg_integer().
+-spec sparse_size(Array :: array()) -> non_neg_integer().
sparse_size(A) ->
F = fun (I, _V, _A) -> throw({value, I}) end,
diff --git a/lib/stdlib/src/base64.erl b/lib/stdlib/src/base64.erl
index a14a72ac6d..5d800e87b8 100644
--- a/lib/stdlib/src/base64.erl
+++ b/lib/stdlib/src/base64.erl
@@ -38,7 +38,9 @@
%% Description: Encodes a plain ASCII string (or binary) into base64.
%%-------------------------------------------------------------------------
--spec encode_to_string(string() | binary()) -> ascii_string().
+-spec encode_to_string(Data) -> Base64String when
+ Data :: string() | binary(),
+ Base64String :: ascii_string().
encode_to_string(Bin) when is_binary(Bin) ->
encode_to_string(binary_to_list(Bin));
@@ -53,7 +55,9 @@ encode_to_string(List) when is_list(List) ->
%% Description: Encodes a plain ASCII string (or binary) into base64.
%%-------------------------------------------------------------------------
--spec encode(string() | binary()) -> binary().
+-spec encode(Data) -> Base64 when
+ Data :: string() | binary(),
+ Base64 :: binary().
encode(Bin) when is_binary(Bin) ->
encode_binary(Bin);
@@ -102,14 +106,18 @@ encode_binary(Bin) ->
%% whereas decode crashes if an illegal character is found
%%-------------------------------------------------------------------------
--spec decode(string() | binary()) -> binary().
+-spec decode(Base64) -> Data when
+ Base64 :: string() | binary(),
+ Data :: binary().
decode(Bin) when is_binary(Bin) ->
decode_binary(<<>>, Bin);
decode(List) when is_list(List) ->
list_to_binary(decode_l(List)).
--spec mime_decode(string() | binary()) -> binary().
+-spec mime_decode(Base64) -> Data when
+ Base64 :: string() | binary(),
+ Data :: binary().
mime_decode(Bin) when is_binary(Bin) ->
mime_decode_binary(<<>>, Bin);
@@ -139,14 +147,18 @@ mime_decode_l(List) ->
%% whereas decode crashes if an illegal character is found
%%-------------------------------------------------------------------------
--spec decode_to_string(string() | binary()) -> string().
+-spec decode_to_string(Base64) -> DataString when
+ Base64 :: string() | binary(),
+ DataString :: string().
decode_to_string(Bin) when is_binary(Bin) ->
decode_to_string(binary_to_list(Bin));
decode_to_string(List) when is_list(List) ->
decode_l(List).
--spec mime_decode_to_string(string() | binary()) -> string().
+-spec mime_decode_to_string(Base64) -> DataString when
+ Base64 :: string() | binary(),
+ DataString :: string().
mime_decode_to_string(Bin) when is_binary(Bin) ->
mime_decode_to_string(binary_to_list(Bin));
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index 74d4ad3da7..e9a5e6831e 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -54,13 +54,9 @@
-type beam() :: module() | file:filename() | binary().
-%% XXX: THE FOLLOWING SHOULD BE IMPORTED FROM SOMEWHERE ELSE
--type forms() :: term().
+-type forms() :: [erl_parse:abstract_form()].
--type abst_vsn() :: atom().
--type abst_code() :: {abst_vsn(), forms()} | 'no_abstract_code'.
--type attribute() :: atom().
--type attrvalue() :: term().
+-type abst_code() :: {AbstVersion :: atom(), forms()} | 'no_abstract_code'.
-type dataB() :: binary().
-type index() :: non_neg_integer().
-type label() :: integer().
@@ -74,9 +70,9 @@
| 'atoms'.
-type chunkref() :: chunkname() | chunkid().
--type attrib_entry() :: {attribute(), [attrvalue()]}.
--type compinfo_entry() :: {atom(), term()}.
--type labeled_entry() :: {atom(), arity(), label()}.
+-type attrib_entry() :: {Attribute :: atom(), [AttributeValue :: term()]}.
+-type compinfo_entry() :: {InfoKey :: atom(), term()}.
+-type labeled_entry() :: {Function :: atom(), arity(), label()}.
-type chunkdata() :: {chunkid(), dataB()}
| {'abstract_code', abst_code()}
@@ -85,20 +81,17 @@
| {'exports', [{atom(), arity()}]}
| {'labeled_exports', [labeled_entry()]}
| {'imports', [mfa()]}
- | {'indexed_imports', [{index(), module(), atom(), arity()}]}
+ | {'indexed_imports', [{index(), module(), Function :: atom(), arity()}]}
| {'locals', [{atom(), arity()}]}
| {'labeled_locals', [labeled_entry()]}
| {'atoms', [{integer(), atom()}]}.
--type info_pair() :: {'file', file:filename()}
- | {'binary', binary()}
- | {'module', module()}
- | {'chunks', [{chunkid(), integer(), integer()}]}.
-
%% Error reasons
-type info_rsn() :: {'chunk_too_big', file:filename(),
- chunkid(), integer(), integer()}
- | {'invalid_beam_file', file:filename(), integer()}
+ chunkid(), ChunkSize :: non_neg_integer(),
+ FileSize :: non_neg_integer()}
+ | {'invalid_beam_file', file:filename(),
+ Position :: non_neg_integer()}
| {'invalid_chunk', file:filename(), chunkid()}
| {'missing_chunk', file:filename(), chunkid()}
| {'not_a_beam_file', file:filename()}
@@ -118,20 +111,34 @@
%% Exported functions
%%
--spec info(beam()) -> [info_pair()] | {'error', 'beam_lib', info_rsn()}.
+-spec info(Beam) -> [InfoPair] | {'error', 'beam_lib', info_rsn()} when
+ Beam :: beam(),
+ InfoPair :: {'file', Filename :: file:filename()}
+ | {'binary', Binary :: binary()}
+ | {'module', Module :: module()}
+ | {'chunks', [{ChunkId :: chunkid(),
+ Pos :: non_neg_integer(),
+ Size :: non_neg_integer()}]}.
info(File) ->
read_info(beam_filename(File)).
--spec chunks(beam(), [chunkref()]) ->
- {'ok', {module(), [chunkdata()]}} | {'error', 'beam_lib', chnk_rsn()}.
+-spec chunks(Beam, ChunkRefs) ->
+ {'ok', {module(), [chunkdata()]}} |
+ {'error', 'beam_lib', chnk_rsn()} when
+ Beam :: beam(),
+ ChunkRefs :: [chunkref()].
chunks(File, Chunks) ->
read_chunk_data(File, Chunks).
--spec chunks(beam(), [chunkref()], ['allow_missing_chunks']) ->
- {'ok', {module(), [{chunkref(), chunkdata() | 'missing_chunk'}]}}
- | {'error', 'beam_lib', chnk_rsn()}.
+-spec chunks(Beam, ChunkRefs, Options) ->
+ {'ok', {module(), [ChunkResult]}} |
+ {'error', 'beam_lib', chnk_rsn()} when
+ Beam :: beam(),
+ ChunkRefs :: [chunkref()],
+ Options :: ['allow_missing_chunks'],
+ ChunkResult :: chunkdata() | {ChunkRef :: chunkref(), 'missing_chunk'}.
chunks(File, Chunks, Options) ->
try read_chunk_data(File, Chunks, Options)
@@ -142,49 +149,65 @@ chunks(File, Chunks, Options) ->
all_chunks(File) ->
read_all_chunks(File).
--spec cmp(beam(), beam()) -> 'ok' | {'error', 'beam_lib', cmp_rsn()}.
+-spec cmp(Beam1, Beam2) -> 'ok' | {'error', 'beam_lib', cmp_rsn()} when
+ Beam1 :: beam(),
+ Beam2 :: beam().
cmp(File1, File2) ->
try cmp_files(File1, File2)
catch Error -> Error end.
--spec cmp_dirs(atom() | file:filename(), atom() | file:filename()) ->
- {[file:filename()], [file:filename()],
- [{file:filename(), file:filename()}]}
- | {'error', 'beam_lib', {'not_a_directory', term()} | info_rsn()}.
+-spec cmp_dirs(Dir1, Dir2) ->
+ {Only1, Only2, Different} | {'error', 'beam_lib', Reason} when
+ Dir1 :: atom() | file:filename(),
+ Dir2 :: atom() | file:filename(),
+ Only1 :: [file:filename()],
+ Only2 :: [file:filename()],
+ Different :: [{Filename1 :: file:filename(), Filename2 :: file:filename()}],
+ Reason :: {'not_a_directory', term()} | info_rsn().
cmp_dirs(Dir1, Dir2) ->
catch compare_dirs(Dir1, Dir2).
--spec diff_dirs(atom() | file:filename(), atom() | file:filename()) ->
- 'ok' | {'error', 'beam_lib', {'not_a_directory', term()} | info_rsn()}.
+-spec diff_dirs(Dir1, Dir2) -> 'ok' | {'error', 'beam_lib', Reason} when
+ Dir1 :: atom() | file:filename(),
+ Dir2 :: atom() | file:filename(),
+ Reason :: {'not_a_directory', term()} | info_rsn().
diff_dirs(Dir1, Dir2) ->
catch diff_directories(Dir1, Dir2).
--spec strip(beam()) ->
- {'ok', {module(), beam()}} | {'error', 'beam_lib', info_rsn()}.
+-spec strip(Beam1) ->
+ {'ok', {module(), Beam2}} | {'error', 'beam_lib', info_rsn()} when
+ Beam1 :: beam(),
+ Beam2 :: beam().
strip(FileName) ->
try strip_file(FileName)
catch Error -> Error end.
--spec strip_files([beam()]) ->
- {'ok', [{module(), beam()}]} | {'error', 'beam_lib', info_rsn()}.
+-spec strip_files(Files) ->
+ {'ok', [{module(), Beam}]} | {'error', 'beam_lib', info_rsn()} when
+ Files :: [beam()],
+ Beam :: beam().
strip_files(Files) when is_list(Files) ->
try strip_fils(Files)
catch Error -> Error end.
--spec strip_release(atom() | file:filename()) ->
+-spec strip_release(Dir) ->
{'ok', [{module(), file:filename()}]}
- | {'error', 'beam_lib', {'not_a_directory', term()} | info_rsn()}.
+ | {'error', 'beam_lib', Reason} when
+ Dir :: atom() | file:filename(),
+ Reason :: {'not_a_directory', term()} | info_rsn().
strip_release(Root) ->
catch strip_rel(Root).
--spec version(beam()) ->
- {'ok', {module(), [term()]}} | {'error', 'beam_lib', chnk_rsn()}.
+-spec version(Beam) ->
+ {'ok', {module(), [Version :: term()]}} |
+ {'error', 'beam_lib', chnk_rsn()} when
+ Beam :: beam().
version(File) ->
case catch read_chunk_data(File, [attributes]) of
@@ -195,11 +218,13 @@ version(File) ->
Error
end.
--spec md5(beam()) ->
- {'ok', {module(), binary()}} | {'error', 'beam_lib', chnk_rsn()}.
+-spec md5(Beam) ->
+ {'ok', {module(), MD5}} | {'error', 'beam_lib', chnk_rsn()} when
+ Beam :: beam(),
+ MD5 :: binary().
md5(File) ->
- case catch read_significant_chunks(File) of
+ case catch read_significant_chunks(File, md5_chunks()) of
{ok, {Module, Chunks0}} ->
Chunks = filter_funtab(Chunks0),
{ok, {Module, erlang:md5([C || {_Id, C} <- Chunks])}};
@@ -207,7 +232,8 @@ md5(File) ->
Error
end.
--spec format_error(term()) -> [char() | string()].
+-spec format_error(Reason) -> io_lib:chars() when
+ Reason :: term().
format_error({error, Error}) ->
format_error(Error);
@@ -260,12 +286,15 @@ format_error(E) ->
| {'debug_info', mode(), module(), file:filename()}.
-type crypto_fun() :: fun((crypto_fun_arg()) -> term()).
--spec crypto_key_fun(crypto_fun()) -> 'ok' | {'error', term()}.
+-spec crypto_key_fun(CryptoKeyFun) -> 'ok' | {'error', Reason} when
+ CryptoKeyFun :: crypto_fun(),
+ Reason :: badfun | exists | term().
crypto_key_fun(F) ->
call_crypto_server({crypto_key_fun, F}).
--spec clear_crypto_key_fun() -> 'undefined' | {'ok', term()}.
+-spec clear_crypto_key_fun() -> 'undefined' | {'ok', Result} when
+ Result :: 'undefined' | term().
clear_crypto_key_fun() ->
call_crypto_server(clear_crypto_key_fun).
@@ -366,7 +395,7 @@ strip_fils(Files) ->
%% -> {ok, {Mod, FileName}} | {ok, {Mod, binary()}} | throw(Error)
strip_file(File) ->
- {ok, {Mod, Chunks}} = read_significant_chunks(File),
+ {ok, {Mod, Chunks}} = read_significant_chunks(File, significant_chunks()),
{ok, Stripped0} = build_module(Chunks),
Stripped = compress(Stripped0),
case File of
@@ -424,8 +453,8 @@ is_useless_chunk("CInf") -> true;
is_useless_chunk(_) -> false.
%% -> {ok, {Module, Chunks}} | throw(Error)
-read_significant_chunks(File) ->
- case read_chunk_data(File, significant_chunks(), [allow_missing_chunks]) of
+read_significant_chunks(File, ChunkList) ->
+ case read_chunk_data(File, ChunkList, [allow_missing_chunks]) of
{ok, {Module, Chunks0}} ->
Mandatory = mandatory_chunks(),
Chunks = filter_significant_chunks(Chunks0, Mandatory, File, Module),
@@ -806,12 +835,15 @@ file_error(FileName, {error, Reason}) ->
error(Reason) ->
throw({error, ?MODULE, Reason}).
-
-%% The following chunks are significant when calculating the MD5 for a module,
-%% and also the modules that must be retained when stripping a file.
-%% They are listed in the order that they should be MD5:ed.
+%% The following chunks must be kept when stripping a BEAM file.
significant_chunks() ->
+ ["Line" | md5_chunks()].
+
+%% The following chunks are significant when calculating the MD5
+%% for a module. They are listed in the order that they should be MD5:ed.
+
+md5_chunks() ->
["Atom", "Code", "StrT", "ImpT", "ExpT", "FunT", "LitT"].
%% The following chunks are mandatory in every Beam file.
@@ -864,13 +896,17 @@ call_crypto_server(Req) ->
gen_server:call(?CRYPTO_KEY_SERVER, Req, infinity)
catch
exit:{noproc,_} ->
- start_crypto_server(),
- erlang:yield(),
- call_crypto_server(Req)
+ %% Not started.
+ call_crypto_server_1(Req);
+ exit:{normal,_} ->
+ %% The process finished just as we called it.
+ call_crypto_server_1(Req)
end.
-start_crypto_server() ->
- gen_server:start({local,?CRYPTO_KEY_SERVER}, ?MODULE, [], []).
+call_crypto_server_1(Req) ->
+ gen_server:start({local,?CRYPTO_KEY_SERVER}, ?MODULE, [], []),
+ erlang:yield(),
+ call_crypto_server(Req).
-spec init([]) -> {'ok', #state{}}.
diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl
index f6489788b2..cb1e12ae46 100644
--- a/lib/stdlib/src/binary.erl
+++ b/lib/stdlib/src/binary.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -38,11 +38,28 @@
%% Implemented in this module:
-export([split/2,split/3,replace/3,replace/4]).
+-opaque cp() :: tuple().
+-type part() :: {Start :: non_neg_integer(), Length :: integer()}.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% split
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-spec split(Subject, Pattern) -> Parts when
+ Subject :: binary(),
+ Pattern :: binary() | [binary()] | cp(),
+ Parts :: [binary()].
+
split(H,N) ->
split(H,N,[]).
+
+-spec split(Subject, Pattern, Options) -> Parts when
+ Subject :: binary(),
+ Pattern :: binary() | [binary()] | cp(),
+ Options :: [Option],
+ Option :: {scope, part()} | trim | global,
+ Parts :: [binary()].
+
split(Haystack,Needles,Options) ->
try
{Part,Global,Trim} = get_opts_split(Options,{no,false,false}),
@@ -89,8 +106,26 @@ do_split(H,[{A,B}|T],N,Trim) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% replace
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-spec replace(Subject, Pattern, Replacement) -> Result when
+ Subject :: binary(),
+ Pattern :: binary() | [ binary() ] | cp(),
+ Replacement :: binary(),
+ Result :: binary().
+
replace(H,N,R) ->
replace(H,N,R,[]).
+
+-spec replace(Subject, Pattern, Replacement, Options) -> Result when
+ Subject :: binary(),
+ Pattern :: binary() | [ binary() ] | cp(),
+ Replacement :: binary(),
+ Options :: [Option],
+ Option :: global | {scope, part()} | {insert_replaced, InsPos},
+ InsPos :: OnePos | [ OnePos ],
+ OnePos :: non_neg_integer(),
+ Result :: binary().
+
replace(Haystack,Needles,Replacement,Options) ->
try
true = is_binary(Replacement), % Make badarg instead of function clause
diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl
index 235ea939a8..a920921a5e 100644
--- a/lib/stdlib/src/c.erl
+++ b/lib/stdlib/src/c.erl
@@ -71,11 +71,16 @@ help() ->
%% c(FileName)
%% Compile a file/module.
--spec c(file:name()) -> {'ok', module()} | 'error'.
+-spec c(File) -> {'ok', Module} | 'error' when
+ File :: file:name(),
+ Module :: module().
c(File) -> c(File, []).
--spec c(file:name(), [compile:option()]) -> {'ok', module()} | 'error'.
+-spec c(File, Options) -> {'ok', Module} | 'error' when
+ File :: file:name(),
+ Options :: [compile:option()],
+ Module :: module().
c(File, Opts0) when is_list(Opts0) ->
Opts = [report_errors,report_warnings|Opts0],
@@ -140,7 +145,8 @@ check_load(_, Mod) -> {ok, Mod}.
%% with constant c2 defined, c1=v1 (v1 must be a term!), include dir
%% IDir, outdir ODir.
--spec lc([erl_compile:cmd_line_arg()]) -> 'ok' | 'error'.
+-spec lc(Files) -> 'ok' | 'error' when
+ Files :: [File :: erl_compile:cmd_line_arg()].
lc(Args) ->
case catch split(Args, [], []) of
@@ -205,12 +211,17 @@ make_term(Str) ->
throw(error)
end.
--spec nc(file:name()) -> {'ok', module()} | 'error'.
+-spec nc(File) -> {'ok', Module} | 'error' when
+ File :: file:name(),
+ Module :: module().
nc(File) -> nc(File, []).
--spec nc(file:name(), [compile:option()] | compile:option()) ->
- {'ok', module} | 'error'.
+-spec nc(File, Options) -> {'ok', Module} | 'error' when
+ File :: file:name(),
+ Options :: [Option] | Option,
+ Option:: compile:option(),
+ Module :: module().
nc(File, Opts0) when is_list(Opts0) ->
Opts = Opts0 ++ [report_errors, report_warnings],
@@ -234,14 +245,17 @@ nc(File, Opt) when is_atom(Opt) ->
%% l(Mod)
%% Reload module Mod from file of same name
--spec l(module()) -> code:load_ret().
+-spec l(Module) -> code:load_ret() when
+ Module :: module().
l(Mod) ->
code:purge(Mod),
code:load_file(Mod).
%% Network version of l/1
-%%-spec nl(module()) ->
+-spec nl(Module) -> abcast | error when
+ Module :: module().
+
nl(Mod) ->
case code:get_object_code(Mod) of
{_Module, Bin, Fname} ->
@@ -396,15 +410,20 @@ fetch(Key, Info) ->
false -> 0
end.
--spec pid(non_neg_integer(), non_neg_integer(), non_neg_integer()) -> pid().
+-spec pid(X, Y, Z) -> pid() when
+ X :: non_neg_integer(),
+ Y :: non_neg_integer(),
+ Z :: non_neg_integer().
pid(X, Y, Z) ->
list_to_pid("<" ++ integer_to_list(X) ++ "." ++
integer_to_list(Y) ++ "." ++
integer_to_list(Z) ++ ">").
--spec i(non_neg_integer(), non_neg_integer(), non_neg_integer()) ->
- [{atom(), term()}].
+-spec i(X, Y, Z) -> [{atom(), term()}] when
+ X :: non_neg_integer(),
+ Y :: non_neg_integer(),
+ Z :: non_neg_integer().
i(X, Y, Z) -> pinfo(pid(X, Y, Z)).
@@ -413,7 +432,8 @@ i(X, Y, Z) -> pinfo(pid(X, Y, Z)).
q() ->
init:stop().
--spec bt(pid()) -> 'ok' | 'undefined'.
+-spec bt(Pid) -> 'ok' | 'undefined' when
+ Pid :: pid().
bt(Pid) ->
case catch erlang:process_display(Pid, backtrace) of
@@ -476,7 +496,8 @@ bi(I) ->
%%
%% Short and nice form of module info
%%
--spec m(module()) -> 'ok'.
+-spec m(Module) -> 'ok' when
+ Module :: module().
m(M) ->
L = M:module_info(),
@@ -664,7 +685,8 @@ pwd() ->
ok = io:format("Cannot determine current directory\n")
end.
--spec cd(file:name()) -> 'ok'.
+-spec cd(Dir) -> 'ok' when
+ Dir :: file:name().
cd(Dir) ->
file:set_cwd(Dir),
@@ -679,7 +701,8 @@ cd(Dir) ->
ls() ->
ls(".").
--spec ls(file:name()) -> 'ok'.
+-spec ls(Dir) -> 'ok' when
+ Dir :: file:name().
ls(Dir) ->
case file:list_dir(Dir) of
@@ -729,12 +752,19 @@ w(X) ->
%% memory/[0,1]
%%
--spec memory() -> [{atom(), non_neg_integer()}].
+-spec memory() -> [{Type, Size}] when
+ Type :: atom(),
+ Size :: non_neg_integer().
memory() -> erlang:memory().
--spec memory(atom()) -> non_neg_integer()
- ; ([atom()]) -> [{atom(), non_neg_integer()}].
+-spec memory(Type) -> Size when
+ Type :: atom(),
+ Size :: non_neg_integer()
+ ; (Types) -> [{Type, Size}] when
+ Types :: [Type],
+ Type :: atom(),
+ Size :: non_neg_integer().
memory(TypeSpec) -> erlang:memory(TypeSpec).
@@ -767,7 +797,7 @@ appcall(App, M, F, Args) ->
catch
error:undef ->
case erlang:get_stacktrace() of
- [{M,F,Args}|_] ->
+ [{M,F,Args,_}|_] ->
Arity = length(Args),
io:format("Call to ~w:~w/~w in application ~w failed.\n",
[M,F,Arity,App]);
diff --git a/lib/stdlib/src/calendar.erl b/lib/stdlib/src/calendar.erl
index 33725d999c..0320e0cd0e 100644
--- a/lib/stdlib/src/calendar.erl
+++ b/lib/stdlib/src/calendar.erl
@@ -63,6 +63,8 @@
%% Types
%%----------------------------------------------------------------------
+-export_type([date/0, time/0, datetime/0, datetime1970/0]).
+
-type year() :: non_neg_integer().
-type year1970() :: 1970..10000. % should probably be 1970..
-type month() :: 1..12.
@@ -74,13 +76,11 @@
-type ldom() :: 28 | 29 | 30 | 31. % last day of month
-type weeknum() :: 1..53.
--type t_now() :: {non_neg_integer(),non_neg_integer(),non_neg_integer()}.
-
--type t_date() :: {year(),month(),day()}.
--type t_time() :: {hour(),minute(),second()}.
--type t_datetime() :: {t_date(),t_time()}.
--type t_datetime1970() :: {{year1970(),month(),day()},t_time()}.
--type t_yearweeknum() :: {year(),weeknum()}.
+-type date() :: {year(),month(),day()}.
+-type time() :: {hour(),minute(),second()}.
+-type datetime() :: {date(),time()}.
+-type datetime1970() :: {{year1970(),month(),day()},time()}.
+-type yearweeknum() :: {year(),weeknum()}.
%%----------------------------------------------------------------------
@@ -106,7 +106,11 @@
%% January 1st.
%%
%% df/2 catches the case Year<0
--spec date_to_gregorian_days(year(),month(),day()) -> non_neg_integer().
+-spec date_to_gregorian_days(Year, Month, Day) -> Days when
+ Year :: year(),
+ Month :: month(),
+ Day :: day(),
+ Days :: non_neg_integer().
date_to_gregorian_days(Year, Month, Day) when is_integer(Day), Day > 0 ->
Last = last_day_of_the_month(Year, Month),
if
@@ -114,7 +118,9 @@ date_to_gregorian_days(Year, Month, Day) when is_integer(Day), Day > 0 ->
dy(Year) + dm(Month) + df(Year, Month) + Day - 1
end.
--spec date_to_gregorian_days(t_date()) -> non_neg_integer().
+-spec date_to_gregorian_days(Date) -> Days when
+ Date :: date(),
+ Days :: non_neg_integer().
date_to_gregorian_days({Year, Month, Day}) ->
date_to_gregorian_days(Year, Month, Day).
@@ -124,7 +130,9 @@ date_to_gregorian_days({Year, Month, Day}) ->
%% Computes the total number of seconds starting from year 0,
%% January 1st.
%%
--spec datetime_to_gregorian_seconds(t_datetime()) -> non_neg_integer().
+-spec datetime_to_gregorian_seconds(DateTime) -> Seconds when
+ DateTime :: datetime(),
+ Seconds :: non_neg_integer().
datetime_to_gregorian_seconds({Date, Time}) ->
?SECONDS_PER_DAY*date_to_gregorian_days(Date) +
time_to_seconds(Time).
@@ -135,18 +143,23 @@ datetime_to_gregorian_seconds({Date, Time}) ->
%%
%% Returns: 1 | .. | 7. Monday = 1, Tuesday = 2, ..., Sunday = 7.
%%
--spec day_of_the_week(year(), month(), day()) -> daynum().
+-spec day_of_the_week(Year, Month, Day) -> daynum() when
+ Year :: year(),
+ Month :: month(),
+ Day :: day().
day_of_the_week(Year, Month, Day) ->
(date_to_gregorian_days(Year, Month, Day) + 5) rem 7 + 1.
--spec day_of_the_week(t_date()) -> daynum().
+-spec day_of_the_week(Date) -> daynum() when
+ Date:: date().
day_of_the_week({Year, Month, Day}) ->
day_of_the_week(Year, Month, Day).
%% gregorian_days_to_date(Days) = {Year, Month, Day}
%%
--spec gregorian_days_to_date(non_neg_integer()) -> t_date().
+-spec gregorian_days_to_date(Days) -> date() when
+ Days :: non_neg_integer().
gregorian_days_to_date(Days) ->
{Year, DayOfYear} = day_to_year(Days),
{Month, DayOfMonth} = year_day_to_date(Year, DayOfYear),
@@ -155,7 +168,8 @@ gregorian_days_to_date(Days) ->
%% gregorian_seconds_to_datetime(Secs)
%%
--spec gregorian_seconds_to_datetime(non_neg_integer()) -> t_datetime().
+-spec gregorian_seconds_to_datetime(Seconds) -> datetime() when
+ Seconds :: non_neg_integer().
gregorian_seconds_to_datetime(Secs) when Secs >= 0 ->
Days = Secs div ?SECONDS_PER_DAY,
Rest = Secs rem ?SECONDS_PER_DAY,
@@ -164,7 +178,8 @@ gregorian_seconds_to_datetime(Secs) when Secs >= 0 ->
%% is_leap_year(Year) = true | false
%%
--spec is_leap_year(year()) -> boolean().
+-spec is_leap_year(Year) -> boolean() when
+ Year :: year().
is_leap_year(Y) when is_integer(Y), Y >= 0 ->
is_leap_year1(Y).
@@ -179,7 +194,7 @@ is_leap_year1(_) -> false.
%%
%% Calculates the iso week number for the current date.
%%
--spec iso_week_number() -> t_yearweeknum().
+-spec iso_week_number() -> yearweeknum().
iso_week_number() ->
{Date, _} = local_time(),
iso_week_number(Date).
@@ -188,7 +203,8 @@ iso_week_number() ->
%%
%% Calculates the iso week number for the given date.
%%
--spec iso_week_number(t_date()) -> t_yearweeknum().
+-spec iso_week_number(Date) -> yearweeknum() when
+ Date :: date().
iso_week_number({Year, Month, Day}) ->
D = date_to_gregorian_days({Year, Month, Day}),
W01_1_Year = gregorian_days_of_iso_w01_1(Year),
@@ -216,7 +232,10 @@ iso_week_number({Year, Month, Day}) ->
%%
%% Returns the number of days in a month.
%%
--spec last_day_of_the_month(year(), month()) -> ldom().
+-spec last_day_of_the_month(Year, Month) -> LastDay when
+ Year :: year(),
+ Month :: month(),
+ LastDay :: ldom().
last_day_of_the_month(Y, M) when is_integer(Y), Y >= 0 ->
last_day_of_the_month1(Y, M).
@@ -237,24 +256,28 @@ last_day_of_the_month1(_, M) when is_integer(M), M > 0, M < 13 ->
%% local_time()
%%
%% Returns: {date(), time()}, date() = {Y, M, D}, time() = {H, M, S}.
--spec local_time() -> t_datetime().
+-spec local_time() -> datetime().
local_time() ->
erlang:localtime().
%% local_time_to_universal_time(DateTime)
%%
--spec local_time_to_universal_time(t_datetime1970()) -> t_datetime1970().
+-spec local_time_to_universal_time(DateTime1) -> DateTime2 when
+ DateTime1 :: datetime1970(),
+ DateTime2 :: datetime1970().
local_time_to_universal_time(DateTime) ->
erlang:localtime_to_universaltime(DateTime).
--spec local_time_to_universal_time(t_datetime1970(),
+-spec local_time_to_universal_time(datetime1970(),
'true' | 'false' | 'undefined') ->
- t_datetime1970().
+ datetime1970().
local_time_to_universal_time(DateTime, IsDst) ->
erlang:localtime_to_universaltime(DateTime, IsDst).
--spec local_time_to_universal_time_dst(t_datetime1970()) -> [t_datetime1970()].
+-spec local_time_to_universal_time_dst(DateTime1) -> [DateTime] when
+ DateTime1 :: datetime1970(),
+ DateTime :: datetime1970().
local_time_to_universal_time_dst(DateTime) ->
UtDst = erlang:localtime_to_universaltime(DateTime, true),
Ut = erlang:localtime_to_universaltime(DateTime, false),
@@ -282,12 +305,14 @@ local_time_to_universal_time_dst(DateTime) ->
%% = MilliSec = integer()
%% Returns: {date(), time()}, date() = {Y, M, D}, time() = {H, M, S}.
%%
--spec now_to_datetime(t_now()) -> t_datetime1970().
+-spec now_to_datetime(Now) -> datetime1970() when
+ Now :: erlang:timestamp().
now_to_datetime({MSec, Sec, _uSec}) ->
Sec0 = MSec*1000000 + Sec + ?DAYS_FROM_0_TO_1970*?SECONDS_PER_DAY,
gregorian_seconds_to_datetime(Sec0).
--spec now_to_universal_time(t_now()) -> t_datetime1970().
+-spec now_to_universal_time(Now) -> datetime1970() when
+ Now :: erlang:timestamp().
now_to_universal_time(Now) ->
now_to_datetime(Now).
@@ -296,7 +321,8 @@ now_to_universal_time(Now) ->
%%
%% Args: Now = now()
%%
--spec now_to_local_time(t_now()) -> t_datetime1970().
+-spec now_to_local_time(Now) -> datetime1970() when
+ Now :: erlang:timestamp().
now_to_local_time({MSec, Sec, _uSec}) ->
erlang:universaltime_to_localtime(
now_to_universal_time({MSec, Sec, _uSec})).
@@ -305,7 +331,10 @@ now_to_local_time({MSec, Sec, _uSec}) ->
%% seconds_to_daystime(Secs) = {Days, {Hour, Minute, Second}}
%%
--spec seconds_to_daystime(integer()) -> {integer(), t_time()}.
+-spec seconds_to_daystime(Seconds) -> {Days, Time} when
+ Seconds :: integer(),
+ Days :: integer(),
+ Time :: time().
seconds_to_daystime(Secs) ->
Days0 = Secs div ?SECONDS_PER_DAY,
Secs0 = Secs rem ?SECONDS_PER_DAY,
@@ -323,7 +352,8 @@ seconds_to_daystime(Secs) ->
%% Wraps.
%%
-type secs_per_day() :: 0..?SECONDS_PER_DAY.
--spec seconds_to_time(secs_per_day()) -> t_time().
+-spec seconds_to_time(Seconds) -> time() when
+ Seconds :: secs_per_day().
seconds_to_time(Secs) when Secs >= 0, Secs < ?SECONDS_PER_DAY ->
Secs0 = Secs rem ?SECONDS_PER_DAY,
Hour = Secs0 div ?SECONDS_PER_HOUR,
@@ -340,8 +370,11 @@ seconds_to_time(Secs) when Secs >= 0, Secs < ?SECONDS_PER_DAY ->
%% Date = {Year, Month, Day}, Time = {Hour, Minute, Sec},
%% Year = Month = Day = Hour = Minute = Sec = integer()
%%
--type timediff() :: {integer(), t_time()}.
--spec time_difference(t_datetime(), t_datetime()) -> timediff().
+-spec time_difference(T1, T2) -> {Days, Time} when
+ T1 :: datetime(),
+ T2 :: datetime(),
+ Days :: integer(),
+ Time :: time().
time_difference({{Y1, Mo1, D1}, {H1, Mi1, S1}},
{{Y2, Mo2, D2}, {H2, Mi2, S2}}) ->
Secs = datetime_to_gregorian_seconds({{Y2, Mo2, D2}, {H2, Mi2, S2}}) -
@@ -352,7 +385,8 @@ time_difference({{Y1, Mo1, D1}, {H1, Mi1, S1}},
%%
%% time_to_seconds(Time)
%%
--spec time_to_seconds(t_time()) -> secs_per_day().
+-spec time_to_seconds(Time) -> secs_per_day() when
+ Time :: time().
time_to_seconds({H, M, S}) when is_integer(H), is_integer(M), is_integer(S) ->
H * ?SECONDS_PER_HOUR +
M * ?SECONDS_PER_MINUTE + S.
@@ -361,14 +395,15 @@ time_to_seconds({H, M, S}) when is_integer(H), is_integer(M), is_integer(S) ->
%% universal_time()
%%
%% Returns: {date(), time()}, date() = {Y, M, D}, time() = {H, M, S}.
--spec universal_time() -> t_datetime().
+-spec universal_time() -> datetime().
universal_time() ->
erlang:universaltime().
%% universal_time_to_local_time(DateTime)
%%
--spec universal_time_to_local_time(t_datetime()) -> t_datetime().
+-spec universal_time_to_local_time(DateTime) -> datetime() when
+ DateTime :: datetime1970().
universal_time_to_local_time(DateTime) ->
erlang:universaltime_to_localtime(DateTime).
@@ -376,7 +411,10 @@ universal_time_to_local_time(DateTime) ->
%% valid_date(Year, Month, Day) = true | false
%% valid_date({Year, Month, Day}) = true | false
%%
--spec valid_date(integer(), integer(), integer()) -> boolean().
+-spec valid_date(Year, Month, Day) -> boolean() when
+ Year :: integer(),
+ Month :: integer(),
+ Day :: integer().
valid_date(Y, M, D) when is_integer(Y), is_integer(M), is_integer(D) ->
valid_date1(Y, M, D).
@@ -386,7 +424,8 @@ valid_date1(Y, M, D) when Y >= 0, M > 0, M < 13, D > 0 ->
valid_date1(_, _, _) ->
false.
--spec valid_date({integer(),integer(),integer()}) -> boolean().
+-spec valid_date(Date) -> boolean() when
+ Date :: date().
valid_date({Y, M, D}) ->
valid_date(Y, M, D).
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index 6c91f1efb7..c0f9ce34b0 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -97,10 +97,6 @@
-include("dets.hrl").
--type object() :: tuple().
--type pattern() :: atom() | tuple().
--type tab_name() :: atom() | reference().
-
%%% This is the implementation of the mnesia file storage. Each (non
%%% ram-copy) table is maintained in a corresponding .DAT file. The
%%% dat file is organized as a segmented linear hashlist. The head of
@@ -179,6 +175,21 @@
%%-define(PROFILE(C), C).
-define(PROFILE(C), void).
+-type access() :: 'read' | 'read_write'.
+-type auto_save() :: 'infinity' | non_neg_integer().
+-opaque bindings_cont() :: #dets_cont{}.
+-opaque cont() :: #dets_cont{}.
+-type keypos() :: pos_integer().
+-type match_spec() :: ets:match_spec().
+-type object() :: tuple().
+-type no_slots() :: non_neg_integer() | 'default'.
+-opaque object_cont() :: #dets_cont{}.
+-type pattern() :: atom() | tuple().
+-opaque select_cont() :: #dets_cont{}.
+-type tab_name() :: term().
+-type type() :: 'bag' | 'duplicate_bag' | 'set'.
+-type version() :: 8 | 9 | 'default'.
+
%%% Some further debug code was added in R12B-1 (stdlib-1.15.1):
%%% - there is a new open_file() option 'debug';
%%% - there is a new OS environment variable 'DETS_DEBUG';
@@ -203,9 +214,13 @@ add_user(Pid, Tab, Args) ->
all() ->
dets_server:all().
--type cont() :: #dets_cont{}.
--spec bchunk(tab_name(), 'start' | cont()) ->
- {cont(), binary() | tuple()} | '$end_of_table' | {'error', term()}.
+-spec bchunk(Name, Continuation) ->
+ {Continuation2, Data} | '$end_of_table' | {'error', Reason} when
+ Name :: tab_name(),
+ Continuation :: 'start' | cont(),
+ Continuation2 :: cont(),
+ Data :: binary() | tuple(),
+ Reason :: term().
bchunk(Tab, start) ->
badarg(treq(Tab, {bchunk_init, Tab}), [Tab, start]);
@@ -214,7 +229,9 @@ bchunk(Tab, #dets_cont{what = bchunk, tab = Tab} = State) ->
bchunk(Tab, Term) ->
erlang:error(badarg, [Tab, Term]).
--spec close(tab_name()) -> 'ok' | {'error', term()}.
+-spec close(Name) -> 'ok' | {'error', Reason} when
+ Name :: tab_name(),
+ Reason :: term().
close(Tab) ->
case dets_server:close(Tab) of
@@ -224,12 +241,17 @@ close(Tab) ->
Reply
end.
--spec delete(tab_name(), term()) -> 'ok' | {'error', term()}.
+-spec delete(Name, Key) -> 'ok' | {'error', Reason} when
+ Name :: tab_name(),
+ Key :: term(),
+ Reason :: term().
delete(Tab, Key) ->
badarg(treq(Tab, {delete_key, [Key]}), [Tab, Key]).
--spec delete_all_objects(tab_name()) -> 'ok' | {'error', term()}.
+-spec delete_all_objects(Name) -> 'ok' | {'error', Reason} when
+ Name :: tab_name(),
+ Reason :: term().
delete_all_objects(Tab) ->
case treq(Tab, delete_all_objects) of
@@ -241,7 +263,10 @@ delete_all_objects(Tab) ->
Reply
end.
--spec delete_object(tab_name(), object()) -> 'ok' | {'error', term()}.
+-spec delete_object(Name, Object) -> 'ok' | {'error', Reason} when
+ Name :: tab_name(),
+ Object :: object(),
+ Reason :: term().
delete_object(Tab, O) ->
badarg(treq(Tab, {delete_object, [O]}), [Tab, O]).
@@ -264,23 +289,42 @@ fsck(Fname, Version) ->
end
end.
--spec first(tab_name()) -> term() | '$end_of_table'.
+-spec first(Name) -> Key | '$end_of_table' when
+ Name :: tab_name(),
+ Key :: term().
first(Tab) ->
badarg_exit(treq(Tab, first), [Tab]).
--spec foldr(fun((object(), Acc) -> Acc), Acc, tab_name()) -> Acc | {'error', term()}.
+-spec foldr(Function, Acc0, Name) -> Acc | {'error', Reason} when
+ Name :: tab_name(),
+ Function :: fun((Object :: object(), AccIn) -> AccOut),
+ Acc0 :: term(),
+ Acc :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ Reason :: term().
foldr(Fun, Acc, Tab) ->
foldl(Fun, Acc, Tab).
--spec foldl(fun((object(), Acc) -> Acc), Acc, tab_name()) -> Acc | {'error', term()}.
+-spec foldl(Function, Acc0, Name) -> Acc | {'error', Reason} when
+ Name :: tab_name(),
+ Function :: fun((Object :: object(), AccIn) -> AccOut),
+ Acc0 :: term(),
+ Acc :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ Reason :: term().
foldl(Fun, Acc, Tab) ->
Ref = make_ref(),
do_traverse(Fun, Acc, Tab, Ref).
--spec from_ets(tab_name(), ets:tab()) -> 'ok' | {'error', term()}.
+-spec from_ets(Name, EtsTab) -> 'ok' | {'error', Reason} when
+ Name :: tab_name(),
+ EtsTab :: ets:tab(),
+ Reason :: term().
from_ets(DTab, ETab) ->
ets:safe_fixtable(ETab, true),
@@ -304,6 +348,15 @@ from_ets_fun(LC, ETab) ->
{L, from_ets_fun(ets:select(C), ETab)}
end.
+-spec info(Name) -> InfoList | 'undefined' when
+ Name :: tab_name(),
+ InfoList :: [InfoTuple],
+ InfoTuple :: {'file_size', non_neg_integer()}
+ | {'filename', file:name()}
+ | {'keypos', keypos()}
+ | {'size', non_neg_integer()}
+ | {'type', type()}.
+
info(Tab) ->
case catch dets_server:get_pid(Tab) of
{'EXIT', _Reason} ->
@@ -312,6 +365,14 @@ info(Tab) ->
undefined(req(Pid, info))
end.
+-spec info(Name, Item) -> Value | 'undefined' when
+ Name :: tab_name(),
+ Item :: 'access' | 'auto_save' | 'bchunk_format'
+ | 'hash' | 'file_size' | 'filename' | 'keypos' | 'memory'
+ | 'no_keys' | 'no_objects' | 'no_slots' | 'owner' | 'ram_file'
+ | 'safe_fixed' | 'size' | 'type' | 'version',
+ Value :: term().
+
info(Tab, owner) ->
case catch dets_server:get_pid(Tab) of
Pid when is_pid(Pid) ->
@@ -334,9 +395,27 @@ info(Tab, Tag) ->
undefined(req(Pid, {info, Tag}))
end.
+-spec init_table(Name, InitFun) -> ok | {'error', Reason} when
+ Name :: tab_name(),
+ InitFun :: fun((Arg) -> Res),
+ Arg :: read | close,
+ Res :: end_of_input | {[object()], InitFun} | {Data, InitFun} | term(),
+ Reason :: term(),
+ Data :: binary() | tuple().
+
init_table(Tab, InitFun) ->
init_table(Tab, InitFun, []).
+-spec init_table(Name, InitFun, Options) -> ok | {'error', Reason} when
+ Name :: tab_name(),
+ InitFun :: fun((Arg) -> Res),
+ Arg :: read | close,
+ Res :: end_of_input | {[object()], InitFun} | {Data, InitFun} | term(),
+ Options :: Option | [Option],
+ Option :: {min_no_slots,no_slots()} | {format,term | bchunk},
+ Reason :: term(),
+ Data :: binary() | tuple().
+
init_table(Tab, InitFun, Options) when is_function(InitFun) ->
case options(Options, [format, min_no_slots]) of
{badarg,_} ->
@@ -350,11 +429,20 @@ init_table(Tab, InitFun, Options) when is_function(InitFun) ->
init_table(Tab, InitFun, Options) ->
erlang:error(badarg, [Tab, InitFun, Options]).
+-spec insert(Name, Objects) -> 'ok' | {'error', Reason} when
+ Name :: tab_name(),
+ Objects :: object() | [object()],
+ Reason :: term().
+
insert(Tab, Objs) when is_list(Objs) ->
badarg(treq(Tab, {insert, Objs}), [Tab, Objs]);
insert(Tab, Obj) ->
badarg(treq(Tab, {insert, [Obj]}), [Tab, Obj]).
+-spec insert_new(Name, Objects) -> boolean() when
+ Name :: tab_name(),
+ Objects :: object() | [object()].
+
insert_new(Tab, Objs) when is_list(Objs) ->
badarg(treq(Tab, {insert_new, Objs}), [Tab, Objs]);
insert_new(Tab, Obj) ->
@@ -366,9 +454,17 @@ internal_close(Pid) ->
internal_open(Pid, Ref, Args) ->
req(Pid, {internal_open, Ref, Args}).
+-spec is_compatible_bchunk_format(Name, BchunkFormat) -> boolean() when
+ Name :: tab_name(),
+ BchunkFormat :: binary().
+
is_compatible_bchunk_format(Tab, Term) ->
badarg(treq(Tab, {is_compatible_bchunk_format, Term}), [Tab, Term]).
+-spec is_dets_file(Filename) -> boolean() | {'error', Reason} when
+ Filename :: file:name(),
+ Reason :: term().
+
is_dets_file(FileName) ->
case catch read_file_header(FileName, read, false) of
{ok, Fd, FH} ->
@@ -382,6 +478,12 @@ is_dets_file(FileName) ->
Other
end.
+-spec lookup(Name, Key) -> Objects | {'error', Reason} when
+ Name :: tab_name(),
+ Key :: term(),
+ Objects :: [object()],
+ Reason :: term().
+
lookup(Tab, Key) ->
badarg(treq(Tab, {lookup_keys, [Key]}), [Tab, Key]).
@@ -394,19 +496,43 @@ lookup_keys(Tab, Keys) ->
erlang:error(badarg, [Tab, Keys])
end.
+-spec match(Name, Pattern) -> [Match] | {'error', Reason} when
+ Name :: tab_name(),
+ Pattern :: pattern(),
+ Match :: [term()],
+ Reason :: term().
+
match(Tab, Pat) ->
badarg(safe_match(Tab, Pat, bindings), [Tab, Pat]).
+-spec match(Name, Pattern, N) ->
+ {[Match], Continuation} | '$end_of_table' | {'error', Reason} when
+ Name :: tab_name(),
+ Pattern :: pattern(),
+ N :: 'default' | non_neg_integer(),
+ Continuation :: bindings_cont(),
+ Match :: [term()],
+ Reason :: term().
+
match(Tab, Pat, N) ->
badarg(init_chunk_match(Tab, Pat, bindings, N), [Tab, Pat, N]).
+-spec match(Continuation) ->
+ {[Match], Continuation2} | '$end_of_table' | {'error', Reason} when
+ Continuation :: bindings_cont(),
+ Continuation2 :: bindings_cont(),
+ Match :: [term()],
+ Reason :: term().
+
match(State) when State#dets_cont.what =:= bindings ->
badarg(chunk_match(State), [State]);
match(Term) ->
erlang:error(badarg, [Term]).
--spec match_delete(tab_name(), pattern()) ->
- non_neg_integer() | 'ok' | {'error', term()}.
+-spec match_delete(Name, Pattern) -> 'ok' | {'error', Reason} when
+ Name :: tab_name(),
+ Pattern :: pattern(),
+ Reason :: term().
match_delete(Tab, Pat) ->
badarg(match_delete(Tab, Pat, delete), [Tab, Pat]).
@@ -434,23 +560,60 @@ do_match_delete(Tab, _Proc, Error, _What, _N) ->
safe_fixtable(Tab, false),
Error.
+-spec match_object(Name, Pattern) -> Objects | {'error', Reason} when
+ Name :: tab_name(),
+ Pattern :: pattern(),
+ Objects :: [object()],
+ Reason :: term().
+
match_object(Tab, Pat) ->
badarg(safe_match(Tab, Pat, object), [Tab, Pat]).
+-spec match_object(Name, Pattern, N) ->
+ {Objects, Continuation} | '$end_of_table' | {'error', Reason} when
+ Name :: tab_name(),
+ Pattern :: pattern(),
+ N :: 'default' | non_neg_integer(),
+ Continuation :: object_cont(),
+ Objects :: [object()],
+ Reason :: term().
+
match_object(Tab, Pat, N) ->
badarg(init_chunk_match(Tab, Pat, object, N), [Tab, Pat, N]).
+-spec match_object(Continuation) ->
+ {Objects, Continuation2} | '$end_of_table' | {'error', Reason} when
+ Continuation :: object_cont(),
+ Continuation2 :: object_cont(),
+ Objects :: [object()],
+ Reason :: term().
+
match_object(State) when State#dets_cont.what =:= object ->
badarg(chunk_match(State), [State]);
match_object(Term) ->
erlang:error(badarg, [Term]).
+-spec member(Name, Key) -> boolean() | {'error', Reason} when
+ Name :: tab_name(),
+ Key :: term(),
+ Reason :: term().
+
member(Tab, Key) ->
badarg(treq(Tab, {member, Key}), [Tab, Key]).
+-spec next(Name, Key1) -> Key2 | '$end_of_table' when
+ Name :: tab_name(),
+ Key1 :: term(),
+ Key2 :: term().
+
next(Tab, Key) ->
badarg_exit(treq(Tab, {next, Key}), [Tab, Key]).
+-spec open_file(Filename) -> {'ok', Reference} | {'error', Reason} when
+ Filename :: file:name(),
+ Reference :: reference(),
+ Reason :: term().
+
%% Assuming that a file already exists, open it with the
%% parameters as already specified in the file itself.
%% Return a ref leading to the file.
@@ -462,6 +625,22 @@ open_file(File) ->
einval(Reply, [File])
end.
+-spec open_file(Name, Args) -> {'ok', Name} | {'error', Reason} when
+ Name :: tab_name(),
+ Args :: [OpenArg],
+ OpenArg :: {'access', access()}
+ | {'auto_save', auto_save()}
+ | {'estimated_no_objects', non_neg_integer()}
+ | {'file', file:name()}
+ | {'max_no_slots', no_slots()}
+ | {'min_no_slots', no_slots()}
+ | {'keypos', keypos()}
+ | {'ram_file', boolean()}
+ | {'repair', boolean() | 'force'}
+ | {'type', type()}
+ | {'version', version()},
+ Reason :: term().
+
open_file(Tab, Args) when is_list(Args) ->
case catch defaults(Tab, Args) of
OpenArgs when is_record(OpenArgs, open_args) ->
@@ -477,12 +656,21 @@ open_file(Tab, Args) when is_list(Args) ->
open_file(Tab, Arg) ->
open_file(Tab, [Arg]).
+-spec pid2name(Pid) -> {'ok', Name} | 'undefined' when
+ Pid :: pid(),
+ Name :: tab_name().
+
pid2name(Pid) ->
dets_server:pid2name(Pid).
remove_user(Pid, From) ->
req(Pid, {close, From}).
+-spec repair_continuation(Continuation, MatchSpec) -> Continuation2 when
+ Continuation :: select_cont(),
+ Continuation2 :: select_cont(),
+ MatchSpec :: match_spec().
+
repair_continuation(#dets_cont{match_program = B}=Cont, MS)
when is_binary(B) ->
case ets:is_compiled_ms(B) of
@@ -496,25 +684,63 @@ repair_continuation(#dets_cont{}=Cont, _MS) ->
repair_continuation(T, MS) ->
erlang:error(badarg, [T, MS]).
+-spec safe_fixtable(Name, Fix) -> 'ok' when
+ Name :: tab_name(),
+ Fix :: boolean().
+
safe_fixtable(Tab, Bool) when Bool; not Bool ->
badarg(treq(Tab, {safe_fixtable, Bool}), [Tab, Bool]);
safe_fixtable(Tab, Term) ->
erlang:error(badarg, [Tab, Term]).
+-spec select(Name, MatchSpec) -> Selection | {'error', Reason} when
+ Name :: tab_name(),
+ MatchSpec :: match_spec(),
+ Selection :: [term()],
+ Reason :: term().
+
select(Tab, Pat) ->
badarg(safe_match(Tab, Pat, select), [Tab, Pat]).
+-spec select(Name, MatchSpec, N) ->
+ {Selection, Continuation} | '$end_of_table' | {'error', Reason} when
+ Name :: tab_name(),
+ MatchSpec :: match_spec(),
+ N :: 'default' | non_neg_integer(),
+ Continuation :: select_cont(),
+ Selection :: [term()],
+ Reason :: term().
+
select(Tab, Pat, N) ->
badarg(init_chunk_match(Tab, Pat, select, N), [Tab, Pat, N]).
+-spec select(Continuation) ->
+ {Selection, Continuation2} | '$end_of_table' | {'error', Reason} when
+ Continuation :: select_cont(),
+ Continuation2 :: select_cont(),
+ Selection :: [term()],
+ Reason :: term().
+
select(State) when State#dets_cont.what =:= select ->
badarg(chunk_match(State), [State]);
select(Term) ->
erlang:error(badarg, [Term]).
+-spec select_delete(Name, MatchSpec) -> N | {'error', Reason} when
+ Name :: tab_name(),
+ MatchSpec :: match_spec(),
+ N :: non_neg_integer(),
+ Reason :: term().
+
select_delete(Tab, Pat) ->
badarg(match_delete(Tab, Pat, select), [Tab, Pat]).
+-spec slot(Name, I) -> '$end_of_table' | Objects | {'error', Reason} when
+ Name :: tab_name(),
+ I :: non_neg_integer(),
+ Objects :: [object()],
+ Reason :: term().
+
slot(Tab, Slot) when is_integer(Slot), Slot >= 0 ->
badarg(treq(Tab, {slot, Slot}), [Tab, Slot]);
slot(Tab, Term) ->
@@ -529,12 +755,29 @@ stop() ->
istart_link(Server) ->
{ok, proc_lib:spawn_link(dets, init, [self(), Server])}.
+-spec sync(Name) -> 'ok' | {'error', Reason} when
+ Name :: tab_name(),
+ Reason :: term().
+
sync(Tab) ->
badarg(treq(Tab, sync), [Tab]).
+-spec table(Name) -> QueryHandle when
+ Name :: tab_name(),
+ QueryHandle :: qlc:query_handle().
+
table(Tab) ->
table(Tab, []).
+-spec table(Name, Options) -> QueryHandle when
+ Name :: tab_name(),
+ Options :: Option | [Option],
+ Option :: {'n_objects', Limit}
+ | {'traverse', TraverseMethod},
+ Limit :: 'default' | pos_integer(),
+ TraverseMethod :: 'first_next' | 'select' | {'select', match_spec()},
+ QueryHandle :: qlc:query_handle().
+
table(Tab, Opts) ->
case options(Opts, [traverse, n_objects]) of
{badarg,_} ->
@@ -612,6 +855,11 @@ table_info(_Tab, _) ->
%% End of table/2.
+-spec to_ets(Name, EtsTab) -> EtsTab | {'error', Reason} when
+ Name :: tab_name(),
+ EtsTab :: ets:tab(),
+ Reason :: term().
+
to_ets(DTab, ETab) ->
case ets:info(ETab, protection) of
undefined ->
@@ -621,6 +869,20 @@ to_ets(DTab, ETab) ->
foldl(Fun, ETab, DTab)
end.
+-spec traverse(Name, Fun) -> Return | {'error', Reason} when
+ Name :: tab_name(),
+ Fun :: fun((Object) -> FunReturn),
+ Object :: object(),
+ FunReturn :: 'continue'
+ | {'continue', Val}
+ | {'done', Value}
+ | OtherValue,
+ Return :: [term()] | OtherValue,
+ Val :: term(),
+ Value :: term(),
+ OtherValue :: term(),
+ Reason :: term().
+
traverse(Tab, Fun) ->
Ref = make_ref(),
TFun =
@@ -638,6 +900,14 @@ traverse(Tab, Fun) ->
end,
do_traverse(TFun, [], Tab, Ref).
+-spec update_counter(Name, Key, Increment) -> Result when
+ Name :: tab_name(),
+ Key :: term(),
+ Increment :: {Pos, Incr} | Incr,
+ Pos :: integer(),
+ Incr :: integer(),
+ Result :: integer().
+
update_counter(Tab, Key, C) ->
badarg(treq(Tab, {update_counter, Key, C}), [Tab, Key, C]).
@@ -1484,17 +1754,6 @@ system_code_change(State, _Module, _OldVsn, _Extra) ->
%%% Internal functions
%%%----------------------------------------------------------------------
-constants(FH, FileName) ->
- Version = FH#fileheader.version,
- if
- Version =< 8 ->
- dets_v8:constants();
- Version =:= 9 ->
- dets_v9:constants();
- true ->
- throw({error, {not_a_dets_file, FileName}})
- end.
-
%% -> {ok, Fd, fileheader()} | throw(Error)
read_file_header(FileName, Access, RamFile) ->
BF = if
@@ -1572,7 +1831,11 @@ do_bchunk_init(Head, Tab) ->
{H2, {error, old_version}};
Parms ->
L = dets_utils:all_allocated(H2),
- C0 = #dets_cont{no_objs = default, bin = <<>>, alloc = L},
+ Bin = if
+ L =:= <<>> -> eof;
+ true -> <<>>
+ end,
+ C0 = #dets_cont{no_objs = default, bin = Bin, alloc = L},
BinParms = term_to_binary(Parms),
{H2, {C0#dets_cont{tab = Tab, proc = self(),what = bchunk},
[BinParms]}}
@@ -2205,10 +2468,23 @@ fopen2(Fname, Tab) ->
%% Fd is not always closed upon error, but exit is soon called.
{ok, Fd, FH} = read_file_header(Fname, Acc, Ram),
Mod = FH#fileheader.mod,
- case Mod:check_file_header(FH, Fd) of
- {error, not_closed} ->
- io:format(user,"dets: file ~p not properly closed, "
- "repairing ...~n", [Fname]),
+ Do = case Mod:check_file_header(FH, Fd) of
+ {ok, Head1, ExtraInfo} ->
+ Head2 = Head1#head{filename = Fname},
+ try {ok, Mod:init_freelist(Head2, ExtraInfo)}
+ catch
+ throw:_ ->
+ {repair, " has bad free lists, repairing ..."}
+ end;
+ {error, not_closed} ->
+ M = " not properly closed, repairing ...",
+ {repair, M};
+ Else ->
+ Else
+ end,
+ case Do of
+ {repair, Mess} ->
+ io:format(user, "dets: file ~p~s~n", [Fname, Mess]),
Version = default,
case fsck(Fd, Tab, Fname, FH, default, default, Version) of
ok ->
@@ -2216,9 +2492,9 @@ fopen2(Fname, Tab) ->
Error ->
throw(Error)
end;
- {ok, Head, ExtraInfo} ->
+ {ok, Head} ->
open_final(Head, Fname, Acc, Ram, ?DEFAULT_CACHE,
- Tab, ExtraInfo, false);
+ Tab, false);
{error, Reason} ->
throw({error, {Reason, Fname}})
end;
@@ -2250,12 +2526,13 @@ fopen_existing_file(Tab, OpenArgs) ->
V9 = (Version =:= 9) or (Version =:= default),
MinF = (MinSlots =:= default) or (MinSlots =:= FH#fileheader.min_no_slots),
MaxF = (MaxSlots =:= default) or (MaxSlots =:= FH#fileheader.max_no_slots),
- Do = case (FH#fileheader.mod):check_file_header(FH, Fd) of
+ Mod = (FH#fileheader.mod),
+ Wh = case Mod:check_file_header(FH, Fd) of
{ok, Head, true} when Rep =:= force, Acc =:= read_write,
FH#fileheader.version =:= 9,
FH#fileheader.no_colls =/= undefined,
MinF, MaxF, V9 ->
- {compact, Head};
+ {compact, Head, true};
{ok, _Head, _Extra} when Rep =:= force, Acc =:= read ->
throw({error, {access_mode, Fname}});
{ok, Head, need_compacting} when Acc =:= read ->
@@ -2285,6 +2562,17 @@ fopen_existing_file(Tab, OpenArgs) ->
{error, Reason} ->
throw({error, {Reason, Fname}})
end,
+ Do = case Wh of
+ {Tag, Hd, Extra} when Tag =:= final; Tag =:= compact ->
+ Hd1 = Hd#head{filename = Fname},
+ try {Tag, Mod:init_freelist(Hd1, Extra)}
+ catch
+ throw:_ ->
+ {repair, " has bad free lists, repairing ..."}
+ end;
+ Else ->
+ Else
+ end,
case Do of
_ when FH#fileheader.type =/= Type ->
throw({error, {type_mismatch, Fname}});
@@ -2293,8 +2581,7 @@ fopen_existing_file(Tab, OpenArgs) ->
{compact, SourceHead} ->
io:format(user, "dets: file ~p is now compacted ...~n", [Fname]),
{ok, NewSourceHead} = open_final(SourceHead, Fname, read, false,
- ?DEFAULT_CACHE, Tab, true,
- Debug),
+ ?DEFAULT_CACHE, Tab, Debug),
case catch compact(NewSourceHead) of
ok ->
erlang:garbage_collect(),
@@ -2314,9 +2601,9 @@ fopen_existing_file(Tab, OpenArgs) ->
Version, OpenArgs);
_ when FH#fileheader.version =/= Version, Version =/= default ->
throw({error, {version_mismatch, Fname}});
- {final, H, EI} ->
+ {final, H} ->
H1 = H#head{auto_save = Auto},
- open_final(H1, Fname, Acc, Ram, CacheSz, Tab, EI, Debug)
+ open_final(H1, Fname, Acc, Ram, CacheSz, Tab, Debug)
end.
do_repair(Fd, Tab, Fname, FH, MinSlots, MaxSlots, Version, OpenArgs) ->
@@ -2330,19 +2617,16 @@ do_repair(Fd, Tab, Fname, FH, MinSlots, MaxSlots, Version, OpenArgs) ->
end.
%% -> {ok, head()} | throw(Error)
-open_final(Head, Fname, Acc, Ram, CacheSz, Tab, ExtraInfo, Debug) ->
+open_final(Head, Fname, Acc, Ram, CacheSz, Tab, Debug) ->
Head1 = Head#head{access = Acc,
ram_file = Ram,
filename = Fname,
name = Tab,
cache = dets_utils:new_cache(CacheSz)},
init_disk_map(Head1#head.version, Tab, Debug),
- Mod = Head#head.mod,
- Mod:cache_segps(Head1#head.fptr, Fname, Head1#head.next),
- Ftab = Mod:init_freelist(Head1, ExtraInfo),
+ (Head1#head.mod):cache_segps(Head1#head.fptr, Fname, Head1#head.next),
check_growth(Head1),
- NewHead = Head1#head{freelists = Ftab},
- {ok, NewHead}.
+ {ok, Head1}.
%% -> {ok, head()} | throw(Error)
fopen_init_file(Tab, OpenArgs) ->
@@ -2869,8 +3153,12 @@ init_scan(Head, NoObjs) ->
check_safe_fixtable(Head),
FreeLists = dets_utils:get_freelists(Head),
Base = Head#head.base,
- {From, To} = dets_utils:find_next_allocated(FreeLists, Base, Base),
- #dets_cont{no_objs = NoObjs, bin = <<>>, alloc = {From, To, <<>>}}.
+ case dets_utils:find_next_allocated(FreeLists, Base, Base) of
+ {From, To} ->
+ #dets_cont{no_objs = NoObjs, bin = <<>>, alloc = {From,To,<<>>}};
+ none ->
+ #dets_cont{no_objs = NoObjs, bin = eof, alloc = <<>>}
+ end.
check_safe_fixtable(Head) ->
case (Head#head.fixed =:= false) andalso
@@ -2971,18 +3259,20 @@ view(FileName) ->
case catch read_file_header(FileName, read, false) of
{ok, Fd, FH} ->
Mod = FH#fileheader.mod,
- case Mod:check_file_header(FH, Fd) of
- {ok, H0, ExtraInfo} ->
- Ftab = Mod:init_freelist(H0, ExtraInfo),
- {_Bump, Base} = constants(FH, FileName),
- H = H0#head{freelists=Ftab, base = Base},
- v_free_list(H),
- Mod:v_segments(H),
- file:close(Fd);
- X ->
- file:close(Fd),
- X
- end;
+ try Mod:check_file_header(FH, Fd) of
+ {ok, H0, ExtraInfo} ->
+ Mod = FH#fileheader.mod,
+ case Mod:check_file_header(FH, Fd) of
+ {ok, H0, ExtraInfo} ->
+ H = Mod:init_freelist(H0, ExtraInfo),
+ v_free_list(H),
+ Mod:v_segments(H),
+ ok;
+ X ->
+ X
+ end
+ after file:close(Fd)
+ end;
X ->
X
end.
diff --git a/lib/stdlib/src/dets.hrl b/lib/stdlib/src/dets.hrl
index fbffc9d008..a3f99357a2 100644
--- a/lib/stdlib/src/dets.hrl
+++ b/lib/stdlib/src/dets.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -92,6 +92,7 @@
%% Info extracted from the file header.
-record(fileheader, {
freelist,
+ fl_base,
cookie,
closed_properly,
type,
diff --git a/lib/stdlib/src/dets_v8.erl b/lib/stdlib/src/dets_v8.erl
index af36958c1c..3e962a1c8b 100644
--- a/lib/stdlib/src/dets_v8.erl
+++ b/lib/stdlib/src/dets_v8.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -21,7 +21,7 @@
%% Dets files, implementation part. This module handles versions up to
%% and including 8(c). To be called from dets.erl only.
--export([constants/0, mark_dirty/1, read_file_header/2,
+-export([mark_dirty/1, read_file_header/2,
check_file_header/2, do_perform_save/1, initiate_file/11,
init_freelist/2, fsck_input/4,
bulk_input/3, output_objs/4, write_cache/1, may_grow/3,
@@ -163,7 +163,7 @@
%% The 8(c) version uses a different hashing algorithm, erlang:phash
%% (former versions use erlang:hash).
%% Version 8(b) files are only converted to version 8(c) if repair is
-%% done, so we need compatability with 8(b) for a _long_ time.
+%% done, so we need compatibility with 8(b) for a _long_ time.
%%
%% There are known bugs due to the fact that keys and objects are
%% sometimes compared (==) and sometimes matched (=:=). The version
@@ -196,10 +196,6 @@
%%-define(DEBUGF(X,Y), io:format(X, Y)).
-define(DEBUGF(X,Y), void).
-%% {Bump}
-constants() ->
- {?BUMP, ?BASE}.
-
%% -> ok | throw({NewHead,Error})
mark_dirty(Head) ->
Dirty = [{?CLOSED_PROPERLY_POS, <<?NOT_PROPERLY_CLOSED:32>>}],
@@ -308,8 +304,9 @@ init_freelist(Head, {convert_freelist,_Version}) ->
Pos = Head#head.freelists_p,
case catch prterm(Head, Pos, ?OHDSZ) of
{0, _Sz, Term} ->
- FreeList = lists:reverse(Term),
- dets_utils:init_slots_from_old_file(FreeList, Ftab);
+ FreeList1 = lists:reverse(Term),
+ FreeList = dets_utils:init_slots_from_old_file(FreeList1, Ftab),
+ Head#head{freelists = FreeList, base = ?BASE};
_ ->
throw({error, {bad_freelists, Head#head.filename}})
end;
@@ -318,7 +315,7 @@ init_freelist(Head, _) ->
Pos = Head#head.freelists_p,
case catch prterm(Head, Pos, ?OHDSZ) of
{0, _Sz, Term} ->
- Term;
+ Head#head{freelists = Term, base = ?BASE};
_ ->
throw({error, {bad_freelists, Head#head.filename}})
end.
@@ -331,6 +328,7 @@ read_file_header(Fd, FileName) ->
{ok, EOF} = dets_utils:position_close(Fd, FileName, eof),
{ok, <<FileSize:32>>} = dets_utils:pread_close(Fd, FileName, EOF-4, 4),
FH = #fileheader{freelist = Freelist,
+ fl_base = ?BASE,
cookie = Cookie,
closed_properly = CP,
type = dets_utils:code_to_type(Type2),
@@ -413,7 +411,7 @@ check_file_header(FH, Fd) ->
version = ?FILE_FORMAT_VERSION,
mod = ?MODULE,
bump = ?BUMP,
- base = ?BASE},
+ base = FH#fileheader.fl_base},
{ok, H, ExtraInfo};
Error ->
Error
diff --git a/lib/stdlib/src/dets_v9.erl b/lib/stdlib/src/dets_v9.erl
index 132af01f79..f577b4410f 100644
--- a/lib/stdlib/src/dets_v9.erl
+++ b/lib/stdlib/src/dets_v9.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -21,7 +21,7 @@
%% Dets files, implementation part. This module handles version 9.
%% To be called from dets.erl only.
--export([constants/0, mark_dirty/1, read_file_header/2,
+-export([mark_dirty/1, read_file_header/2,
check_file_header/2, do_perform_save/1, initiate_file/11,
prep_table_copy/9, init_freelist/2, fsck_input/4,
bulk_input/3, output_objs/4, bchunk_init/2,
@@ -70,6 +70,17 @@
%% 16 MD5-sum for the 44 plus 112 bytes before the MD5-sum.
%% (FreelistsPointer, Cookie and ClosedProperly are not digested.)
%% 128 Reserved for future versions. Initially zeros.
+%% Version 9(d), introduced in R15A, has instead:
+%% 112 28 counters for the buddy system sizes (as for 9(b)).
+%% 16 MD5-sum for the 44 plus 112 bytes before the MD5-sum.
+%% (FreelistsPointer, Cookie and ClosedProperly are not digested.)
+%% 4 Base of the buddy system.
+%% 0 (zero) if the base is equal to ?BASE. Compatible with R14B.
+%% File size at the end of the file is RealFileSize - Base.
+%% The reason for modifying file size is that when a file created
+%% by R15 is read by R14 a repair takes place immediately, which
+%% is acceptable when downgrading.
+%% 124 Reserved for future versions. Initially zeros.
%% ---
%% ------------------ end of file header
%% 4*256 SegmentArray Pointers.
@@ -86,7 +97,7 @@
%% -----------------------------
%% ??? Free lists
%% -----------------------------
-%% 4 File size, in bytes.
+%% 4 File size, in bytes. See 9(d) obove.
%% Before we can find an object we must find the slot where the
%% object resides. Each slot is a (possibly empty) list (or chain) of
@@ -177,14 +188,14 @@
%%% File header
%%%
--define(RESERVED, 128). % Reserved for future use.
+-define(RESERVED, 124). % Reserved for future use.
-define(COLL_CNTRS, (28*4)). % Counters for the buddy system.
-define(MD5SZ, 16).
+-define(FL_BASE, 4).
--define(HEADSZ,
- 56+?COLL_CNTRS+?MD5SZ). % The size of the file header, in bytes,
- % not including the reserved part.
+-define(HEADSZ, 56+?COLL_CNTRS % The size of the file header, in bytes,
+ +?MD5SZ+?FL_BASE). % not including the reserved part.
-define(HEADEND, (?HEADSZ+?RESERVED)).
% End of header and reserved area.
-define(SEGSZ, 512). % Size of a segment, in words. SZOBJP*SEGSZP.
@@ -270,10 +281,6 @@
%%-define(DEBUGF(X,Y), io:format(X, Y)).
-define(DEBUGF(X,Y), void).
-%% {Bump}
-constants() ->
- {?BUMP, ?BASE}.
-
%% -> ok | throw({NewHead,Error})
mark_dirty(Head) ->
Dirty = [{?CLOSED_PROPERLY_POS, <<?NOT_PROPERLY_CLOSED:32>>}],
@@ -356,7 +363,7 @@ init_file(Fd, Tab, Fname, Type, Kp, MinSlots, MaxSlots, Ram, CacheSz,
cache = dets_utils:new_cache(CacheSz),
version = ?FILE_FORMAT_VERSION,
bump = ?BUMP,
- base = ?BASE,
+ base = ?BASE, % to be overwritten
mod = ?MODULE
},
@@ -378,13 +385,20 @@ init_file(Fd, Tab, Fname, Type, Kp, MinSlots, MaxSlots, Ram, CacheSz,
{Head1, Ws1} = init_parts(Head0, 0, no_parts(Next), Zero, []),
NoSegs = no_segs(Next),
- {Head, WsI, WsP} = init_segments(Head1, 0, NoSegs, Zero, [], []),
+ {Head2, WsI, WsP} = init_segments(Head1, 0, NoSegs, Zero, [], []),
Ws2 = if
DoInitSegments -> WsP ++ WsI;
true -> WsP
end,
dets_utils:pwrite(Fd, Fname, [W0 | lists:append(Ws1) ++ Ws2]),
- true = hash_invars(Head),
+ true = hash_invars(Head2),
+ %% The allocations that have been made so far (parts, segments)
+ %% are permanent; the table will never shrink. Therefore the base
+ %% of the Buddy system can be set to the first free object.
+ %% This is used in allocate_all(), see below.
+ {_, Where, _} = dets_utils:alloc(Head2, ?BUMP),
+ NewFtab = dets_utils:init_alloc(Where),
+ Head = Head2#head{freelists = NewFtab, base = Where},
{ok, Head}.
%% Returns a power of two not less than 256.
@@ -451,8 +465,9 @@ read_file_header(Fd, FileName) ->
Version:32, M:32, Next:32, Kp:32,
NoObjects:32, NoKeys:32, MinNoSlots:32, MaxNoSlots:32,
HashMethod:32, N:32, NoCollsB:?COLL_CNTRS/binary,
- MD5:?MD5SZ/binary>> = Bin,
- <<_:12/binary,MD5DigestedPart:(?HEADSZ-?MD5SZ-12)/binary,_/binary>> = Bin,
+ MD5:?MD5SZ/binary, FlBase:32>> = Bin,
+ <<_:12/binary,MD5DigestedPart:(?HEADSZ-?MD5SZ-?FL_BASE-12)/binary,
+ _/binary>> = Bin,
{ok, EOF} = dets_utils:position_close(Fd, FileName, eof),
{ok, <<FileSize:32>>} = dets_utils:pread_close(Fd, FileName, EOF-4, 4),
{CL, <<>>} = lists:foldl(fun(LSz, {Acc,<<NN:32,R/binary>>}) ->
@@ -468,8 +483,12 @@ read_file_header(Fd, FileName) ->
true ->
lists:reverse(CL)
end,
-
+ Base = case FlBase of
+ 0 -> ?BASE;
+ _ -> FlBase
+ end,
FH = #fileheader{freelist = FreeList,
+ fl_base = Base,
cookie = Cookie,
closed_properly = CP,
type = dets_utils:code_to_type(Type2),
@@ -486,7 +505,7 @@ read_file_header(Fd, FileName) ->
read_md5 = MD5,
has_md5 = <<0:?MD5SZ/unit:8>> =/= MD5,
md5 = erlang:md5(MD5DigestedPart),
- trailer = FileSize,
+ trailer = FileSize + FlBase,
eof = EOF,
n = N,
mod = ?MODULE},
@@ -544,7 +563,7 @@ check_file_header(FH, Fd) ->
version = ?FILE_FORMAT_VERSION,
mod = ?MODULE,
bump = ?BUMP,
- base = ?BASE},
+ base = FH#fileheader.fl_base},
{ok, H, ExtraInfo};
Error ->
Error
@@ -1185,41 +1204,25 @@ write_loop(Head, BytesToWrite, Bin) ->
write_loop(Head, BytesToWrite, SmallBin).
%% By allocating bigger objects before smaller ones, holes in the
-%% buddy system memory map are avoided. Unfortunately, the segments
-%% are always allocated first, so if there are objects bigger than a
-%% segment, there is a hole to handle. (Haven't considered placing the
-%% segments among other objects of the same size.)
+%% buddy system memory map are avoided.
allocate_all_objects(Head, SizeT) ->
DTL = lists:reverse(lists:keysort(1, ets:tab2list(SizeT))),
MaxSz = element(1, hd(DTL)),
- SegSize = ?ACTUAL_SEG_SIZE,
- {Head1, HSz, HN, HA} = alloc_hole(MaxSz, Head, SegSize),
- {Head2, NL} = allocate_all(Head1, DTL, []),
+ {Head1, NL} = allocate_all(Head, DTL, []),
%% Find the position that will be the end of the file by allocating
%% a minimal object.
- {_Head, EndOfFile, _} = dets_utils:alloc(Head2, ?BUMP),
- Head3 = free_hole(Head2, HSz, HN, HA),
- NewHead = Head3#head{maxobjsize = max_objsize(Head3#head.no_collections)},
+ {_Head, EndOfFile, _} = dets_utils:alloc(Head1, ?BUMP),
+ NewHead = Head1#head{maxobjsize = max_objsize(Head1#head.no_collections)},
{NewHead, NL, MaxSz, EndOfFile}.
-alloc_hole(LSize, Head, SegSz) when ?POW(LSize-1) > SegSz ->
- Size = ?POW(LSize-1),
- {_, SegAddr, _} = dets_utils:alloc(Head, adjsz(SegSz)),
- {_, Addr, _} = dets_utils:alloc(Head, adjsz(Size)),
- N = (Addr - SegAddr) div SegSz,
- Head1 = dets_utils:alloc_many(Head, SegSz, N, SegAddr),
- {Head1, SegSz, N, SegAddr};
-alloc_hole(_MaxSz, Head, _SegSz) ->
- {Head, 0, 0, 0}.
-
-free_hole(Head, _Size, 0, _Addr) ->
- Head;
-free_hole(Head, Size, N, Addr) ->
- {Head1, _} = dets_utils:free(Head, Addr, adjsz(Size)),
- free_hole(Head1, Size, N-1, Addr+Size).
-
%% One (temporary) file for each buddy size, write all objects of that
%% size to the file.
+%%
+%% Before R15 a "hole" was needed before the first bucket if the size
+%% of the biggest bucket was greater than the size of a segment. The
+%% hole proved to be a problem with almost full tables with huge
+%% buckets. Since R15 the hole is no longer needed due to the fact
+%% that the base of the Buddy system is flexible.
allocate_all(Head, [{?FSCK_SEGMENT,_,Data,_}], L) ->
%% And one file for the segments...
%% Note that space for the array parts and the segments has
@@ -1593,23 +1596,28 @@ do_perform_save(H) ->
H1 = H#head{freelists_p = FreeListsPointer},
{FLW, FLSize} = free_lists_to_file(H1),
FileSize = FreeListsPointer + FLSize + 4,
- ok = dets_utils:write(H1, [FLW | <<FileSize:32>>]),
+ AdjustedFileSize = case H#head.base of
+ ?BASE -> FileSize;
+ Base -> FileSize - Base
+ end,
+ ok = dets_utils:write(H1, [FLW | <<AdjustedFileSize:32>>]),
FileHeader = file_header(H1, FreeListsPointer, ?CLOSED_PROPERLY),
case dets_utils:debug_mode() of
true ->
- TmpHead = H1#head{freelists = init_freelist(H1, true),
- fixed = false},
+ TmpHead0 = init_freelist(H1#head{fixed = false}, true),
+ TmpHead = TmpHead0#head{base = H1#head.base},
case
catch dets_utils:all_allocated_as_list(TmpHead)
=:= dets_utils:all_allocated_as_list(H1)
- of
+ of
true ->
dets_utils:pwrite(H1, [{0, FileHeader}]);
_ ->
+ throw(
dets_utils:corrupt_reason(H1, {failed_to_save_free_lists,
FreeListsPointer,
TmpHead#head.freelists,
- H1#head.freelists})
+ H1#head.freelists}))
end;
false ->
dets_utils:pwrite(H1, [{0, FileHeader}])
@@ -1648,7 +1656,11 @@ file_header(Head, FreeListsPointer, ClosedProperly, NoColls) ->
true -> erlang:md5(DigH);
false -> <<0:?MD5SZ/unit:8>>
end,
- [H1, DigH, MD5 | <<0:?RESERVED/unit:8>>].
+ Base = case Head#head.base of
+ ?BASE -> <<0:32>>;
+ FlBase -> <<FlBase:32>>
+ end,
+ [H1, DigH, MD5, Base | <<0:?RESERVED/unit:8>>].
%% Going through some trouble to avoid creating one single binary for
%% the free lists. If the free lists are huge, binary_to_term and
@@ -1695,8 +1707,8 @@ free_lists_from_file(H, Pos) ->
case catch bin_to_tree([], H, start, FL, -1, []) of
{'EXIT', _} ->
throw({error, {bad_freelists, H#head.filename}});
- Reply ->
- Reply
+ Ftab ->
+ H#head{freelists = Ftab, base = ?BASE}
end.
bin_to_tree(Bin, H, LastPos, Ftab, A0, L) ->
diff --git a/lib/stdlib/src/dict.erl b/lib/stdlib/src/dict.erl
index 7e51141098..2e9eba4bfa 100644
--- a/lib/stdlib/src/dict.erl
+++ b/lib/stdlib/src/dict.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -80,7 +80,9 @@ new() ->
Empty = mk_seg(?seg_size),
#dict{empty=Empty,segs={Empty}}.
--spec is_key(term(), dict()) -> boolean().
+-spec is_key(Key, Dict) -> boolean() when
+ Key :: term(),
+ Dict :: dict().
is_key(Key, D) ->
Slot = get_slot(D, Key),
@@ -91,21 +93,29 @@ find_key(K, [?kv(K,_Val)|_]) -> true;
find_key(K, [_|Bkt]) -> find_key(K, Bkt);
find_key(_, []) -> false.
--spec to_list(dict()) -> [{term(), term()}].
+-spec to_list(Dict) -> List when
+ Dict :: dict(),
+ List :: [{Key :: term(), Value :: term()}].
to_list(D) ->
fold(fun (Key, Val, List) -> [{Key,Val}|List] end, [], D).
--spec from_list([{term(), term()}]) -> dict().
+-spec from_list(List) -> Dict when
+ List :: [{Key :: term(), Value :: term()}],
+ Dict :: dict().
from_list(L) ->
lists:foldl(fun ({K,V}, D) -> store(K, V, D) end, new(), L).
--spec size(dict()) -> non_neg_integer().
+-spec size(Dict) -> non_neg_integer() when
+ Dict :: dict().
size(#dict{size=N}) when is_integer(N), N >= 0 -> N.
--spec fetch(term(), dict()) -> term().
+-spec fetch(Key, Dict) -> Value when
+ Key :: term(),
+ Dict :: dict(),
+ Value :: term().
fetch(Key, D) ->
Slot = get_slot(D, Key),
@@ -119,7 +129,10 @@ fetch_val(K, [?kv(K,Val)|_]) -> Val;
fetch_val(K, [_|Bkt]) -> fetch_val(K, Bkt);
fetch_val(_, []) -> throw(badarg).
--spec find(term(), dict()) -> {'ok', term()} | 'error'.
+-spec find(Key, Dict) -> {'ok', Value} | 'error' when
+ Key :: term(),
+ Dict :: dict(),
+ Value :: term().
find(Key, D) ->
Slot = get_slot(D, Key),
@@ -130,12 +143,17 @@ find_val(K, [?kv(K,Val)|_]) -> {ok,Val};
find_val(K, [_|Bkt]) -> find_val(K, Bkt);
find_val(_, []) -> error.
--spec fetch_keys(dict()) -> [term()].
+-spec fetch_keys(Dict) -> Keys when
+ Dict :: dict(),
+ Keys :: [term()].
fetch_keys(D) ->
fold(fun (Key, _Val, Keys) -> [Key|Keys] end, [], D).
--spec erase(term(), dict()) -> dict().
+-spec erase(Key, Dict1) -> Dict2 when
+ Key :: term(),
+ Dict1 :: dict(),
+ Dict2 :: dict().
%% Erase all elements with key Key.
erase(Key, D0) ->
@@ -150,7 +168,11 @@ erase_key(Key, [E|Bkt0]) ->
{[E|Bkt1],Dc};
erase_key(_, []) -> {[],0}.
--spec store(term(), term(), dict()) -> dict().
+-spec store(Key, Value, Dict1) -> Dict2 when
+ Key :: term(),
+ Value :: term(),
+ Dict1 :: dict(),
+ Dict2 :: dict().
store(Key, Val, D0) ->
Slot = get_slot(D0, Key),
@@ -166,7 +188,11 @@ store_bkt_val(Key, New, [Other|Bkt0]) ->
{[Other|Bkt1],Ic};
store_bkt_val(Key, New, []) -> {[?kv(Key,New)],1}.
--spec append(term(), term(), dict()) -> dict().
+-spec append(Key, Value, Dict1) -> Dict2 when
+ Key :: term(),
+ Value :: term(),
+ Dict1 :: dict(),
+ Dict2 :: dict().
append(Key, Val, D0) ->
Slot = get_slot(D0, Key),
@@ -182,7 +208,11 @@ append_bkt(Key, Val, [Other|Bkt0]) ->
{[Other|Bkt1],Ic};
append_bkt(Key, Val, []) -> {[?kv(Key,[Val])],1}.
--spec append_list(term(), [term()], dict()) -> dict().
+-spec append_list(Key, ValList, Dict1) -> Dict2 when
+ Key :: term(),
+ ValList :: [Value :: term()],
+ Dict1 :: dict(),
+ Dict2 :: dict().
append_list(Key, L, D0) ->
Slot = get_slot(D0, Key),
@@ -252,7 +282,11 @@ app_list_bkt(Key, L, []) -> {[?kv(Key,L)],1}.
%% {Bkt1,Dc} = on_key_bkt(Key, F, Bkt0),
%% {[Other|Bkt1],Dc}.
--spec update(term(), fun((term()) -> term()), dict()) -> dict().
+-spec update(Key, Fun, Dict1) -> Dict2 when
+ Key :: term(),
+ Fun :: fun((Value1 :: term()) -> Value2 :: term()),
+ Dict1 :: dict(),
+ Dict2 :: dict().
update(Key, F, D0) ->
Slot = get_slot(D0, Key),
@@ -271,7 +305,12 @@ update_bkt(Key, F, [Other|Bkt0]) ->
update_bkt(_Key, _F, []) ->
throw(badarg).
--spec update(term(), fun((term()) -> term()), term(), dict()) -> dict().
+-spec update(Key, Fun, Initial, Dict1) -> Dict2 when
+ Key :: term(),
+ Initial :: term(),
+ Fun :: fun((Value1 :: term()) -> Value2 :: term()),
+ Dict1 :: dict(),
+ Dict2 :: dict().
update(Key, F, Init, D0) ->
Slot = get_slot(D0, Key),
@@ -286,7 +325,11 @@ update_bkt(Key, F, I, [Other|Bkt0]) ->
{[Other|Bkt1],Ic};
update_bkt(Key, F, I, []) when is_function(F, 1) -> {[?kv(Key,I)],1}.
--spec update_counter(term(), number(), dict()) -> dict().
+-spec update_counter(Key, Increment, Dict1) -> Dict2 when
+ Key :: term(),
+ Increment :: number(),
+ Dict1 :: dict(),
+ Dict2 :: dict().
update_counter(Key, Incr, D0) when is_number(Incr) ->
Slot = get_slot(D0, Key),
@@ -301,20 +344,38 @@ counter_bkt(Key, I, [Other|Bkt0]) ->
{[Other|Bkt1],Ic};
counter_bkt(Key, I, []) -> {[?kv(Key,I)],1}.
--spec fold(fun((term(), term(), term()) -> term()), term(), dict()) -> term().
+-spec fold(Fun, Acc0, Dict) -> Acc1 when
+ Fun :: fun((Key, Value, AccIn) -> AccOut),
+ Key :: term(),
+ Value :: term(),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ Dict :: dict().
%% Fold function Fun over all "bags" in Table and return Accumulator.
fold(F, Acc, D) -> fold_dict(F, Acc, D).
--spec map(fun((term(), term()) -> term()), dict()) -> dict().
+-spec map(Fun, Dict1) -> Dict2 when
+ Fun :: fun((Key :: term(), Value1 :: term()) -> Value2 :: term()),
+ Dict1 :: dict(),
+ Dict2 :: dict().
map(F, D) -> map_dict(F, D).
--spec filter(fun((term(), term()) -> boolean()), dict()) -> dict().
+-spec filter(Pred, Dict1) -> Dict2 when
+ Pred :: fun((Key :: term(), Value :: term()) -> boolean()),
+ Dict1 :: dict(),
+ Dict2 :: dict().
filter(F, D) -> filter_dict(F, D).
--spec merge(fun((term(), term(), term()) -> term()), dict(), dict()) -> dict().
+-spec merge(Fun, Dict1, Dict2) -> Dict3 when
+ Fun :: fun((Key :: term(), Value1 :: term(), Value2 :: term()) -> Value :: term()),
+ Dict1 :: dict(),
+ Dict2 :: dict(),
+ Dict3 :: dict().
merge(F, D1, D2) when D1#dict.size < D2#dict.size ->
fold_dict(fun (K, V1, D) ->
diff --git a/lib/stdlib/src/digraph.erl b/lib/stdlib/src/digraph.erl
index 5edc868a94..e3f87d2c57 100644
--- a/lib/stdlib/src/digraph.erl
+++ b/lib/stdlib/src/digraph.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -53,7 +53,8 @@
-type label() :: term().
-type vertex() :: term().
--type add_edge_err_rsn() :: {'bad_edge', [vertex()]} | {'bad_vertex', vertex()}.
+-type add_edge_err_rsn() :: {'bad_edge', Path :: [vertex()]}
+ | {'bad_vertex', V :: vertex()}.
%%
%% Type is a list of
@@ -70,7 +71,8 @@
new() -> new([]).
--spec new([d_type()]) -> digraph().
+-spec new(Type) -> digraph() when
+ Type :: [d_type()].
new(Type) ->
case check_type(Type, protected, []) of
@@ -113,16 +115,20 @@ set_type([], G) -> G.
%% Data access functions
--spec delete(digraph()) -> 'true'.
+-spec delete(G) -> 'true' when
+ G :: digraph().
delete(G) ->
ets:delete(G#digraph.vtab),
ets:delete(G#digraph.etab),
ets:delete(G#digraph.ntab).
--spec info(digraph()) -> [{'cyclicity', d_cyclicity()} |
- {'memory', non_neg_integer()} |
- {'protection', d_protection()}].
+-spec info(G) -> InfoList when
+ G :: digraph(),
+ InfoList :: [{'cyclicity', Cyclicity :: d_cyclicity()} |
+ {'memory', NoWords :: non_neg_integer()} |
+ {'protection', Protection :: d_protection()}].
+
info(G) ->
VT = G#digraph.vtab,
ET = G#digraph.etab,
@@ -135,32 +141,45 @@ info(G) ->
Memory = ets:info(VT, memory) + ets:info(ET, memory) + ets:info(NT, memory),
[{cyclicity, Cyclicity}, {memory, Memory}, {protection, Protection}].
--spec add_vertex(digraph()) -> vertex().
+-spec add_vertex(G) -> vertex() when
+ G :: digraph().
add_vertex(G) ->
do_add_vertex({new_vertex_id(G), []}, G).
--spec add_vertex(digraph(), vertex()) -> vertex().
+-spec add_vertex(G, V) -> vertex() when
+ G :: digraph(),
+ V :: vertex().
add_vertex(G, V) ->
do_add_vertex({V, []}, G).
--spec add_vertex(digraph(), vertex(), label()) -> vertex().
+-spec add_vertex(G, V, Label) -> vertex() when
+ G :: digraph(),
+ V :: vertex(),
+ Label :: label().
add_vertex(G, V, D) ->
do_add_vertex({V, D}, G).
--spec del_vertex(digraph(), vertex()) -> 'true'.
+-spec del_vertex(G, V) -> 'true' when
+ G :: digraph(),
+ V :: vertex().
del_vertex(G, V) ->
do_del_vertex(V, G).
--spec del_vertices(digraph(), [vertex()]) -> 'true'.
+-spec del_vertices(G, Vertices) -> 'true' when
+ G :: digraph(),
+ Vertices :: [vertex()].
del_vertices(G, Vs) ->
do_del_vertices(Vs, G).
--spec vertex(digraph(), vertex()) -> {vertex(), label()} | 'false'.
+-spec vertex(G, V) -> {V, Label} | 'false' when
+ G :: digraph(),
+ V :: vertex(),
+ Label :: label().
vertex(G, V) ->
case ets:lookup(G#digraph.vtab, V) of
@@ -168,12 +187,15 @@ vertex(G, V) ->
[Vertex] -> Vertex
end.
--spec no_vertices(digraph()) -> non_neg_integer().
+-spec no_vertices(G) -> non_neg_integer() when
+ G :: digraph().
no_vertices(G) ->
ets:info(G#digraph.vtab, size).
--spec vertices(digraph()) -> [vertex()].
+-spec vertices(G) -> Vertices when
+ G :: digraph(),
+ Vertices :: [vertex()].
vertices(G) ->
ets:select(G#digraph.vtab, [{{'$1', '_'}, [], ['$1']}]).
@@ -188,85 +210,125 @@ source_vertices(G) ->
sink_vertices(G) ->
collect_vertices(G, out).
--spec in_degree(digraph(), vertex()) -> non_neg_integer().
+-spec in_degree(G, V) -> non_neg_integer() when
+ G :: digraph(),
+ V :: vertex().
in_degree(G, V) ->
length(ets:lookup(G#digraph.ntab, {in, V})).
--spec in_neighbours(digraph(), vertex()) -> [vertex()].
+-spec in_neighbours(G, V) -> Vertex when
+ G :: digraph(),
+ V :: vertex(),
+ Vertex :: [vertex()].
in_neighbours(G, V) ->
ET = G#digraph.etab,
NT = G#digraph.ntab,
collect_elems(ets:lookup(NT, {in, V}), ET, 2).
--spec in_edges(digraph(), vertex()) -> [edge()].
+-spec in_edges(G, V) -> Edges when
+ G :: digraph(),
+ V :: vertex(),
+ Edges :: [edge()].
in_edges(G, V) ->
ets:select(G#digraph.ntab, [{{{in, V}, '$1'}, [], ['$1']}]).
--spec out_degree(digraph(), vertex()) -> non_neg_integer().
+-spec out_degree(G, V) -> non_neg_integer() when
+ G :: digraph(),
+ V :: vertex().
out_degree(G, V) ->
length(ets:lookup(G#digraph.ntab, {out, V})).
--spec out_neighbours(digraph(), vertex()) -> [vertex()].
+-spec out_neighbours(G, V) -> Vertices when
+ G :: digraph(),
+ V :: vertex(),
+ Vertices :: [vertex()].
out_neighbours(G, V) ->
ET = G#digraph.etab,
NT = G#digraph.ntab,
collect_elems(ets:lookup(NT, {out, V}), ET, 3).
--spec out_edges(digraph(), vertex()) -> [edge()].
+-spec out_edges(G, V) -> Edges when
+ G :: digraph(),
+ V :: vertex(),
+ Edges :: [edge()].
out_edges(G, V) ->
ets:select(G#digraph.ntab, [{{{out, V}, '$1'}, [], ['$1']}]).
--spec add_edge(digraph(), vertex(), vertex()) ->
- edge() | {'error', add_edge_err_rsn()}.
+-spec add_edge(G, V1, V2) -> edge() | {'error', add_edge_err_rsn()} when
+ G :: digraph(),
+ V1 :: vertex(),
+ V2 :: vertex().
add_edge(G, V1, V2) ->
do_add_edge({new_edge_id(G), V1, V2, []}, G).
--spec add_edge(digraph(), vertex(), vertex(), label()) ->
- edge() | {'error', add_edge_err_rsn()}.
+-spec add_edge(G, V1, V2, Label) -> edge() | {'error', add_edge_err_rsn()} when
+ G :: digraph(),
+ V1 :: vertex(),
+ V2 :: vertex(),
+ Label :: label().
add_edge(G, V1, V2, D) ->
do_add_edge({new_edge_id(G), V1, V2, D}, G).
--spec add_edge(digraph(), edge(), vertex(), vertex(), label()) ->
- edge() | {'error', add_edge_err_rsn()}.
+-spec add_edge(G, E, V1, V2, Label) -> edge() | {'error', add_edge_err_rsn()} when
+ G :: digraph(),
+ E :: edge(),
+ V1 :: vertex(),
+ V2 :: vertex(),
+ Label :: label().
add_edge(G, E, V1, V2, D) ->
do_add_edge({E, V1, V2, D}, G).
--spec del_edge(digraph(), edge()) -> 'true'.
+-spec del_edge(G, E) -> 'true' when
+ G :: digraph(),
+ E :: edge().
del_edge(G, E) ->
do_del_edges([E], G).
--spec del_edges(digraph(), [edge()]) -> 'true'.
+-spec del_edges(G, Edges) -> 'true' when
+ G :: digraph(),
+ Edges :: [edge()].
del_edges(G, Es) ->
do_del_edges(Es, G).
--spec no_edges(digraph()) -> non_neg_integer().
+-spec no_edges(G) -> non_neg_integer() when
+ G :: digraph().
no_edges(G) ->
ets:info(G#digraph.etab, size).
--spec edges(digraph()) -> [edge()].
+-spec edges(G) -> Edges when
+ G :: digraph(),
+ Edges :: [edge()].
edges(G) ->
ets:select(G#digraph.etab, [{{'$1', '_', '_', '_'}, [], ['$1']}]).
--spec edges(digraph(), vertex()) -> [edge()].
+-spec edges(G, V) -> Edges when
+ G :: digraph(),
+ V :: vertex(),
+ Edges :: [edge()].
edges(G, V) ->
ets:select(G#digraph.ntab, [{{{out, V},'$1'}, [], ['$1']},
{{{in, V}, '$1'}, [], ['$1']}]).
--spec edge(digraph(), edge()) -> {edge(),vertex(),vertex(),label()} | 'false'.
+-spec edge(G, E) -> {E, V1, V2, Label} | 'false' when
+ G :: digraph(),
+ E :: edge(),
+ V1 :: vertex(),
+ V2 :: vertex(),
+ Label :: label().
edge(G, E) ->
case ets:lookup(G#digraph.etab,E) of
@@ -277,7 +339,7 @@ edge(G, E) ->
%%
%% Generate a "unique" edge identifier (relative to this graph)
%%
--spec new_edge_id(digraph()) -> nonempty_improper_list('$e', non_neg_integer()).
+-spec new_edge_id(digraph()) -> edge().
new_edge_id(G) ->
NT = G#digraph.ntab,
@@ -289,7 +351,7 @@ new_edge_id(G) ->
%%
%% Generate a "unique" vertex identifier (relative to this graph)
%%
--spec new_vertex_id(digraph()) -> nonempty_improper_list('$v', non_neg_integer()).
+-spec new_vertex_id(digraph()) -> vertex().
new_vertex_id(G) ->
NT = G#digraph.ntab,
@@ -444,7 +506,10 @@ acyclic_add_edge(E, V1, V2, Label, G) ->
%% Delete all paths from vertex V1 to vertex V2
%%
--spec del_path(digraph(), vertex(), vertex()) -> 'true'.
+-spec del_path(G, V1, V2) -> 'true' when
+ G :: digraph(),
+ V1 :: vertex(),
+ V2 :: vertex().
del_path(G, V1, V2) ->
case get_path(G, V1, V2) of
@@ -463,7 +528,10 @@ del_path(G, V1, V2) ->
%% been searched.
%%
--spec get_cycle(digraph(), vertex()) -> [vertex(),...] | 'false'.
+-spec get_cycle(G, V) -> Vertices | 'false' when
+ G :: digraph(),
+ V :: vertex(),
+ Vertices :: [vertex(),...].
get_cycle(G, V) ->
case one_path(out_neighbours(G, V), V, [], [V], [V], 2, G, 1) of
@@ -481,7 +549,11 @@ get_cycle(G, V) ->
%% if no path exists false is returned
%%
--spec get_path(digraph(), vertex(), vertex()) -> [vertex(),...] | 'false'.
+-spec get_path(G, V1, V2) -> Vertices | 'false' when
+ G :: digraph(),
+ V1 :: vertex(),
+ V2 :: vertex(),
+ Vertices :: [vertex(),...].
get_path(G, V1, V2) ->
one_path(out_neighbours(G, V1), V2, [], [V1], [V1], 1, G, 1).
@@ -516,7 +588,10 @@ one_path([], _, [], _, _, _, _, _Counter) -> false.
%% Like get_cycle/2, but a cycle of length one is preferred.
%%
--spec get_short_cycle(digraph(), vertex()) -> [vertex(),...] | 'false'.
+-spec get_short_cycle(G, V) -> Vertices | 'false' when
+ G :: digraph(),
+ V :: vertex(),
+ Vertices :: [vertex(),...].
get_short_cycle(G, V) ->
get_short_path(G, V, V).
@@ -526,7 +601,11 @@ get_short_cycle(G, V) ->
%% to find a short path.
%%
--spec get_short_path(digraph(), vertex(), vertex()) -> [vertex(),...] | 'false'.
+-spec get_short_path(G, V1, V2) -> Vertices | 'false' when
+ G :: digraph(),
+ V1 :: vertex(),
+ V2 :: vertex(),
+ Vertices :: [vertex(),...].
get_short_path(G, V1, V2) ->
T = new(),
diff --git a/lib/stdlib/src/digraph_utils.erl b/lib/stdlib/src/digraph_utils.erl
index 080cae4742..e221be15a1 100644
--- a/lib/stdlib/src/digraph_utils.erl
+++ b/lib/stdlib/src/digraph_utils.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -38,48 +38,66 @@
%% A convenient type alias
%%
--type vertices() :: [digraph:vertex()].
-
%%
%% Exported functions
%%
--spec components(digraph()) -> vertices().
+-spec components(Digraph) -> [Component] when
+ Digraph :: digraph(),
+ Component :: [digraph:vertex()].
components(G) ->
forest(G, fun inout/3).
--spec strong_components(digraph()) -> vertices().
+-spec strong_components(Digraph) -> [StrongComponent] when
+ Digraph :: digraph(),
+ StrongComponent :: [digraph:vertex()].
strong_components(G) ->
forest(G, fun in/3, revpostorder(G)).
--spec cyclic_strong_components(digraph()) -> vertices().
+-spec cyclic_strong_components(Digraph) -> [StrongComponent] when
+ Digraph :: digraph(),
+ StrongComponent :: [digraph:vertex()].
cyclic_strong_components(G) ->
remove_singletons(strong_components(G), G, []).
--spec reachable(vertices(), digraph()) -> vertices().
+-spec reachable(Vertices, Digraph) -> Reachable when
+ Digraph :: digraph(),
+ Vertices :: [digraph:vertex()],
+ Reachable :: [digraph:vertex()].
reachable(Vs, G) when is_list(Vs) ->
lists:append(forest(G, fun out/3, Vs, first)).
--spec reachable_neighbours(vertices(), digraph()) -> vertices().
+-spec reachable_neighbours(Vertices, Digraph) -> Reachable when
+ Digraph :: digraph(),
+ Vertices :: [digraph:vertex()],
+ Reachable :: [digraph:vertex()].
reachable_neighbours(Vs, G) when is_list(Vs) ->
lists:append(forest(G, fun out/3, Vs, not_first)).
--spec reaching(vertices(), digraph()) -> vertices().
+-spec reaching(Vertices, Digraph) -> Reaching when
+ Digraph :: digraph(),
+ Vertices :: [digraph:vertex()],
+ Reaching :: [digraph:vertex()].
reaching(Vs, G) when is_list(Vs) ->
lists:append(forest(G, fun in/3, Vs, first)).
--spec reaching_neighbours(vertices(), digraph()) -> vertices().
+-spec reaching_neighbours(Vertices, Digraph) -> Reaching when
+ Digraph :: digraph(),
+ Vertices :: [digraph:vertex()],
+ Reaching :: [digraph:vertex()].
reaching_neighbours(Vs, G) when is_list(Vs) ->
lists:append(forest(G, fun in/3, Vs, not_first)).
--spec topsort(digraph()) -> vertices() | 'false'.
+-spec topsort(Digraph) -> Vertices | 'false' when
+ Digraph :: digraph(),
+ Vertices :: [digraph:vertex()].
topsort(G) ->
L = revpostorder(G),
@@ -88,12 +106,15 @@ topsort(G) ->
false -> false
end.
--spec is_acyclic(digraph()) -> boolean().
+-spec is_acyclic(Digraph) -> boolean() when
+ Digraph :: digraph().
is_acyclic(G) ->
loop_vertices(G) =:= [] andalso topsort(G) =/= false.
--spec arborescence_root(digraph()) -> 'no' | {'yes', digraph:vertex()}.
+-spec arborescence_root(Digraph) -> 'no' | {'yes', Root} when
+ Digraph :: digraph(),
+ Root :: digraph:vertex().
arborescence_root(G) ->
case digraph:no_edges(G) =:= digraph:no_vertices(G) - 1 of
@@ -114,23 +135,30 @@ arborescence_root(G) ->
no
end.
--spec is_arborescence(digraph()) -> boolean().
+-spec is_arborescence(Digraph) -> boolean() when
+ Digraph :: digraph().
is_arborescence(G) ->
arborescence_root(G) =/= no.
--spec is_tree(digraph()) -> boolean().
+-spec is_tree(Digraph) -> boolean() when
+ Digraph :: digraph().
is_tree(G) ->
(digraph:no_edges(G) =:= digraph:no_vertices(G) - 1)
andalso (length(components(G)) =:= 1).
--spec loop_vertices(digraph()) -> vertices().
+-spec loop_vertices(Digraph) -> Vertices when
+ Digraph :: digraph(),
+ Vertices :: [digraph:vertex()].
loop_vertices(G) ->
[V || V <- digraph:vertices(G), is_reflexive_vertex(V, G)].
--spec subgraph(digraph(), vertices()) -> digraph().
+-spec subgraph(Digraph, Vertices) -> SubGraph when
+ Digraph :: digraph(),
+ Vertices :: [digraph:vertex()],
+ SubGraph :: digraph().
subgraph(G, Vs) ->
try
@@ -140,10 +168,12 @@ subgraph(G, Vs) ->
erlang:error(badarg)
end.
--type option() :: {'type', 'inherit' | [digraph:d_type()]}
- | {'keep_labels', boolean()}.
-
--spec subgraph(digraph(), vertices(), [option()]) -> digraph().
+-spec subgraph(Digraph, Vertices, Options) -> SubGraph when
+ Digraph :: digraph(),
+ SubGraph :: digraph(),
+ Vertices :: [digraph:vertex()],
+ Options :: [{'type', SubgraphType} | {'keep_labels', boolean()}],
+ SubgraphType :: 'inherit' | [digraph:d_type()].
subgraph(G, Vs, Opts) ->
try
@@ -153,7 +183,9 @@ subgraph(G, Vs, Opts) ->
erlang:error(badarg)
end.
--spec condensation(digraph()) -> digraph().
+-spec condensation(Digraph) -> CondensedDigraph when
+ Digraph :: digraph(),
+ CondensedDigraph :: digraph().
condensation(G) ->
SCs = strong_components(G),
@@ -176,12 +208,16 @@ condensation(G) ->
ets:delete(I2C),
SCG.
--spec preorder(digraph()) -> vertices().
+-spec preorder(Digraph) -> Vertices when
+ Digraph :: digraph(),
+ Vertices :: [digraph:vertex()].
preorder(G) ->
lists:reverse(revpreorder(G)).
--spec postorder(digraph()) -> vertices().
+-spec postorder(Digraph) -> Vertices when
+ Digraph :: digraph(),
+ Vertices :: [digraph:vertex()].
postorder(G) ->
lists:reverse(revpostorder(G)).
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index e5ccaddbb4..230a4a0612 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,6 +29,7 @@
%%------------------------------------------------------------------------
-type macros() :: [{atom(), term()}].
+-type epp_handle() :: pid().
%% Epp state record.
-record(epp, {file, %Current file
@@ -61,14 +62,23 @@
%% parse_file(FileName, IncludePath, PreDefMacros)
%% macro_defs(Epp)
--spec open(file:name(), [file:name()]) ->
- {'ok', pid()} | {'error', term()}.
+-spec open(FileName, IncludePath) ->
+ {'ok', Epp} | {'error', ErrorDescriptor} when
+ FileName :: file:name(),
+ IncludePath :: [DirectoryName :: file:name()],
+ Epp :: epp_handle(),
+ ErrorDescriptor :: term().
open(Name, Path) ->
open(Name, Path, []).
--spec open(file:name(), [file:name()], macros()) ->
- {'ok', pid()} | {'error', term()}.
+-spec open(FileName, IncludePath, PredefMacros) ->
+ {'ok', Epp} | {'error', ErrorDescriptor} when
+ FileName :: file:name(),
+ IncludePath :: [DirectoryName :: file:name()],
+ PredefMacros :: macros(),
+ Epp :: epp_handle(),
+ ErrorDescriptor :: term().
open(Name, Path, Pdm) ->
Self = self(),
@@ -80,7 +90,8 @@ open(Name, File, StartLocation, Path, Pdm) ->
Epp = spawn(fun() -> server(Self, Name, File, StartLocation,Path,Pdm) end),
epp_request(Epp).
--spec close(pid()) -> 'ok'.
+-spec close(Epp) -> 'ok' when
+ Epp :: epp_handle().
close(Epp) ->
%% Make sure that close is synchronous as a courtesy to test
@@ -93,6 +104,13 @@ close(Epp) ->
scan_erl_form(Epp) ->
epp_request(Epp, scan_erl_form).
+-spec parse_erl_form(Epp) ->
+ {'ok', AbsForm} | {'eof', Line} | {error, ErrorInfo} when
+ Epp :: epp_handle(),
+ AbsForm :: erl_parse:abstract_form(),
+ Line :: erl_scan:line(),
+ ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
+
parse_erl_form(Epp) ->
case epp_request(Epp, scan_erl_form) of
{ok,Toks} ->
@@ -107,6 +125,9 @@ macro_defs(Epp) ->
%% format_error(ErrorDescriptor) -> String
%% Return a string describing the error.
+-spec format_error(ErrorDescriptor) -> io_lib:chars() when
+ ErrorDescriptor :: term().
+
format_error(cannot_parse) ->
io_lib:format("cannot parse file, giving up", []);
format_error({bad,W}) ->
@@ -146,6 +167,16 @@ format_error(E) -> file:format_error(E).
%% parse_file(FileName, IncludePath, [PreDefMacro]) ->
%% {ok,[Form]} | {error,OpenError}
+-spec parse_file(FileName, IncludePath, PredefMacros) ->
+ {'ok', [Form]} | {error, OpenError} when
+ FileName :: file:name(),
+ IncludePath :: [DirectoryName :: file:name()],
+ Form :: erl_parse:abstract_form() | {'error', ErrorInfo} | {'eof',Line},
+ PredefMacros :: macros(),
+ Line :: erl_scan:line(),
+ ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(),
+ OpenError :: file:posix() | badarg | system_limit.
+
parse_file(Ifile, Path, Predefs) ->
case open(Ifile, Path, Predefs) of
{ok,Epp} ->
@@ -653,7 +684,7 @@ scan_include_lib([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}],
{error,_E1} ->
case catch find_lib_dir(NewName) of
{LibDir, Rest} when is_list(LibDir) ->
- LibName = filename:join([LibDir | Rest]),
+ LibName = fname_join([LibDir | Rest]),
case file:open(LibName, [read]) of
{ok,NewF} ->
ExtraPath = [filename:dirname(LibName)],
@@ -1123,7 +1154,12 @@ expand_var1(NewName) ->
[[$$ | Var] | Rest] = filename:split(NewName),
Value = os:getenv(Var),
true = Value =/= false,
- {ok, filename:join([Value | Rest])}.
+ {ok, fname_join([Value | Rest])}.
+
+fname_join(["." | [_|_]=Rest]) ->
+ fname_join(Rest);
+fname_join(Components) ->
+ filename:join(Components).
%% The line only. (Other tokens may have the column and text as well...)
loc_attr(Line) when is_integer(Line) ->
diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl
index abff37e4bc..ff032b129c 100644
--- a/lib/stdlib/src/erl_compile.erl
+++ b/lib/stdlib/src/erl_compile.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -41,7 +41,6 @@ compiler(".idl") -> {ic, compile};
compiler(".asn1") -> {asn1ct, compile_asn1};
compiler(".asn") -> {asn1ct, compile_asn};
compiler(".py") -> {asn1ct, compile_py};
-compiler(".xml") -> {xmerl_scan, process};
compiler(_) -> no.
%% Entry from command line.
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index ea1b179ee5..4f4fa16040 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -34,6 +34,37 @@
-import(lists, [reverse/1,foldl/3,member/2]).
+-export_type([binding_struct/0]).
+
+-type(expression() :: erl_parse:abstract_expr()).
+-type(expressions() :: [erl_parse:abstract_expr()]).
+-type(expression_list() :: [expression()]).
+-type(clauses() :: [erl_parse:abstract_clause()]).
+-type(name() :: term()).
+-type(value() :: term()).
+-type(bindings() :: [{name(), value()}]).
+-type(binding_struct() :: orddict:orddict()).
+
+-type(lfun_value_handler() :: fun((Name :: atom(),
+ Arguments :: [term()]) ->
+ Value :: value())).
+-type(lfun_eval_handler() :: fun((Name :: atom(),
+ Arguments :: expression_list(),
+ Bindings :: binding_struct()) ->
+ {value,
+ Value :: value(),
+ NewBindings :: binding_struct()})).
+-type(local_function_handler() :: {value, lfun_value_handler()}
+ | {eval, lfun_eval_handler()}
+ | none).
+
+-type(func_spec() :: {Module :: module(), Function :: atom()} | function()).
+-type(nlfun_handler() :: fun((FuncSpec :: func_spec(),
+ Arguments :: [term()]) ->
+ term())).
+-type(non_local_function_handler() :: {value, nlfun_handler()}
+ | none).
+
%% exprs(ExpressionSeq, Bindings)
%% exprs(ExpressionSeq, Bindings, LocalFuncHandler)
%% exprs(ExpressionSeq, Bindings, LocalFuncHandler, ExternalFuncHandler)
@@ -45,6 +76,11 @@
%% that there are valid constructs in Expression to be taken care of
%% by a function handler but considerad errors by erl_lint.
+-spec(exprs(Expressions, Bindings) -> {value, Value, NewBindings} when
+ Expressions :: expressions(),
+ Bindings :: binding_struct(),
+ Value :: value(),
+ NewBindings :: binding_struct()).
exprs(Exprs, Bs) ->
case check_command(Exprs, Bs) of
ok ->
@@ -53,9 +89,25 @@ exprs(Exprs, Bs) ->
erlang:raise(error, Error, [{?MODULE,exprs,2}])
end.
+-spec(exprs(Expressions, Bindings, LocalFunctionHandler) ->
+ {value, Value, NewBindings} when
+ Expressions :: expressions(),
+ Bindings :: binding_struct(),
+ LocalFunctionHandler :: local_function_handler(),
+ Value :: value(),
+ NewBindings :: binding_struct()).
exprs(Exprs, Bs, Lf) ->
exprs(Exprs, Bs, Lf, none, none).
+-spec(exprs(Expressions, Bindings, LocalFunctionHandler,
+ NonLocalFunctionHandler) ->
+ {value, Value, NewBindings} when
+ Expressions :: expressions(),
+ Bindings :: binding_struct(),
+ LocalFunctionHandler :: local_function_handler(),
+ NonLocalFunctionHandler :: non_local_function_handler(),
+ Value :: value(),
+ NewBindings :: binding_struct()).
exprs(Exprs, Bs, Lf, Ef) ->
exprs(Exprs, Bs, Lf, Ef, none).
@@ -75,6 +127,11 @@ exprs([E|Es], Bs0, Lf, Ef, RBs) ->
%%
%% Only expr/2 checks the command by calling erl_lint. See exprs/2.
+-spec(expr(Expression, Bindings) -> {value, Value, NewBindings} when
+ Expression :: expression(),
+ Bindings :: binding_struct(),
+ Value :: value(),
+ NewBindings :: binding_struct()).
expr(E, Bs) ->
case check_command([E], Bs) of
ok ->
@@ -83,9 +140,25 @@ expr(E, Bs) ->
erlang:raise(error, Error, [{?MODULE,expr,2}])
end.
+-spec(expr(Expression, Bindings, LocalFunctionHandler) ->
+ {value, Value, NewBindings} when
+ Expression :: expression(),
+ Bindings :: binding_struct(),
+ LocalFunctionHandler :: local_function_handler(),
+ Value :: value(),
+ NewBindings :: binding_struct()).
expr(E, Bs, Lf) ->
expr(E, Bs, Lf, none, none).
+-spec(expr(Expression, Bindings, LocalFunctionHandler,
+ NonLocalFunctionHandler) ->
+ {value, Value, NewBindings} when
+ Expression :: expression(),
+ Bindings :: binding_struct(),
+ LocalFunctionHandler :: local_function_handler(),
+ NonLocalFunctionHandler :: non_local_function_handler(),
+ Value :: value(),
+ NewBindings :: binding_struct()).
expr(E, Bs, Lf, Ef) ->
expr(E, Bs, Lf, Ef, none).
@@ -114,6 +187,16 @@ fun_data(F) when is_function(F) ->
fun_data(_T) ->
false.
+-spec(expr(Expression, Bindings, LocalFunctionHandler,
+ NonLocalFunctionHandler, ReturnFormat) ->
+ {value, Value, NewBindings} | Value when
+ Expression :: expression(),
+ Bindings :: binding_struct(),
+ LocalFunctionHandler :: local_function_handler(),
+ NonLocalFunctionHandler :: non_local_function_handler(),
+ ReturnFormat :: none | value,
+ Value :: value(),
+ NewBindings :: binding_struct()).
expr({var,_,V}, Bs, _Lf, _Ef, RBs) ->
case binding(V, Bs) of
{value,Val} ->
@@ -384,12 +467,9 @@ local_func(Func, As0, Bs0, {value,F}, value) ->
local_func(Func, As0, Bs0, {value,F}, RBs) ->
{As1,Bs1} = expr_list(As0, Bs0, {value,F}),
ret_expr(F(Func, As1), Bs1, RBs);
-local_func(Func, As0, Bs0, {value,F,Eas}, value) ->
- {As1,_Bs1} = expr_list(As0, Bs0, {value,F,Eas}),
- apply(F, [Func,As1|Eas]);
local_func(Func, As0, Bs0, {value,F,Eas}, RBs) ->
- {As1,Bs1} = expr_list(As0, Bs0, {value,F,Eas}),
- ret_expr(apply(F, [Func,As1|Eas]), Bs1, RBs);
+ Fun = fun(Name, Args) -> apply(F, [Name,Args|Eas]) end,
+ local_func(Func, As0, Bs0, {value, Fun}, RBs);
local_func(Func, As, Bs, {eval,F}, RBs) ->
local_func2(F(Func, As, Bs), RBs);
local_func(Func, As, Bs, {eval,F,Eas}, RBs) ->
@@ -541,7 +621,7 @@ eval_generate(Term, _P, _Bs0, _Lf, _Ef, _CompFun, _Acc) ->
erlang:raise(error, {bad_generator,Term}, stacktrace()).
eval_b_generate(<<_/bitstring>>=Bin, P, Bs0, Lf, Ef, CompFun, Acc) ->
- Mfun = fun(L, R, Bs) -> match1(L, R, Bs, Bs0) end,
+ Mfun = match_fun(Bs0),
Efun = fun(Exp, Bs) -> expr(Exp, Bs, Lf, Ef, none) end,
case eval_bits:bin_gen(P, Bin, new_bindings(), Bs0, Mfun, Efun) of
{match, Rest, Bs1} ->
@@ -613,12 +693,33 @@ eval_fun([], As, _Bs, _Lf, _Ef, _RBs) ->
%% expr_list(ExpressionList, Bindings, LocalFuncHandler, ExternalFuncHandler)
%% Evaluate a list of expressions "in parallel" at the same level.
+-spec(expr_list(ExpressionList, Bindings) -> {ValueList, NewBindings} when
+ ExpressionList :: expression_list(),
+ Bindings :: binding_struct(),
+ ValueList :: [value()],
+ NewBindings :: binding_struct()).
expr_list(Es, Bs) ->
expr_list(Es, Bs, none, none).
+-spec(expr_list(ExpressionList, Bindings, LocalFunctionHandler) ->
+ {ValueList, NewBindings} when
+ ExpressionList :: expression_list(),
+ Bindings :: binding_struct(),
+ LocalFunctionHandler :: local_function_handler(),
+ ValueList :: [value()],
+ NewBindings :: binding_struct()).
expr_list(Es, Bs, Lf) ->
expr_list(Es, Bs, Lf, none).
+-spec(expr_list(ExpressionList, Bindings, LocalFunctionHandler,
+ NonLocalFunctionHandler) ->
+ {ValueList, NewBindings} when
+ ExpressionList :: expression_list(),
+ Bindings :: binding_struct(),
+ LocalFunctionHandler :: local_function_handler(),
+ NonLocalFunctionHandler :: non_local_function_handler(),
+ ValueList :: [value()],
+ NewBindings :: binding_struct()).
expr_list(Es, Bs, Lf, Ef) ->
expr_list(Es, [], Bs, Bs, Lf, Ef).
@@ -757,6 +858,15 @@ send_all([], _) -> true.
%% match_clause -> {Body, Bindings} or nomatch
+-spec(match_clause(Clauses, ValueList, Bindings, LocalFunctionHandler) ->
+ {Body, NewBindings} | nomatch when
+ Clauses :: clauses(),
+ ValueList :: [value()],
+ Bindings :: binding_struct(),
+ LocalFunctionHandler :: local_function_handler(),
+ Body :: expression_list(),
+ NewBindings :: binding_struct()).
+
match_clause(Cs, Vs, Bs, Lf) ->
match_clause(Cs, Vs, Bs, Lf, none).
@@ -914,7 +1024,7 @@ match1({tuple,_,_}, _, _Bs, _BBs) ->
throw(nomatch);
match1({bin, _, Fs}, <<_/bitstring>>=B, Bs0, BBs) ->
eval_bits:match_bits(Fs, B, Bs0, BBs,
- fun(L, R, Bs) -> match1(L, R, Bs, BBs) end,
+ match_fun(BBs),
fun(E, Bs) -> expr(E, Bs, none, none, none) end);
match1({bin,_,_}, _, _Bs, _BBs) ->
throw(nomatch);
@@ -943,6 +1053,12 @@ match1({op,Line,Op,L,R}, Term, Bs, BBs) ->
match1(_, _, _Bs, _BBs) ->
throw(invalid).
+match_fun(BBs) ->
+ fun(match, {L,R,Bs}) -> match1(L, R, Bs, BBs);
+ (binding, {Name,Bs}) -> binding(Name, Bs);
+ (add_binding, {Name,Val,Bs}) -> add_binding(Name, Val, Bs)
+ end.
+
match_tuple([E|Es], Tuple, I, Bs0, BBs) ->
{match,Bs} = match1(E, element(I, Tuple), Bs0, BBs),
match_tuple(Es, Tuple, I+1, Bs, BBs);
@@ -973,18 +1089,30 @@ match_list(_, _, _Bs, _BBs) ->
%% add_binding(Name, Value, Bindings)
%% del_binding(Name, Bindings)
+-spec(new_bindings() -> binding_struct()).
new_bindings() -> orddict:new().
+-spec(bindings(BindingStruct :: binding_struct()) -> bindings()).
bindings(Bs) -> orddict:to_list(Bs).
+-spec(binding(Name, BindingStruct) -> {value, value()} | unbound when
+ Name :: name(),
+ BindingStruct :: binding_struct()).
binding(Name, Bs) ->
case orddict:find(Name, Bs) of
{ok,Val} -> {value,Val};
error -> unbound
end.
+-spec(add_binding(Name, Value, BindingStruct) -> binding_struct() when
+ Name :: name(),
+ Value :: value(),
+ BindingStruct :: binding_struct()).
add_binding(Name, Val, Bs) -> orddict:store(Name, Val, Bs).
+-spec(del_binding(Name, BindingStruct) -> binding_struct() when
+ Name :: name(),
+ BindingStruct :: binding_struct()).
del_binding(Name, Bs) -> orddict:erase(Name, Bs).
add_bindings(Bs1, Bs2) ->
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index 61ce41f714..20fd247cea 100644
--- a/lib/stdlib/src/erl_expand_records.erl
+++ b/lib/stdlib/src/erl_expand_records.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -35,9 +35,13 @@
trecords=sets:new(), % Typed records
uses_types=false, % Are there -spec or -type in the module
strict_ra=[], % strict record accesses
- checked_ra=[] % succesfully accessed records
+ checked_ra=[] % successfully accessed records
}).
+-spec(module(AbsForms, CompileOptions) -> AbsForms when
+ AbsForms :: [erl_parse:abstract_form()],
+ CompileOptions :: [compile:option()]).
+
%% Is is assumed that Fs is a valid list of forms. It should pass
%% erl_lint without errors.
module(Fs0, Opts0) ->
diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl
index b30b02a96f..cd3b531d10 100644
--- a/lib/stdlib/src/erl_internal.erl
+++ b/lib/stdlib/src/erl_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -54,7 +54,9 @@
%%---------------------------------------------------------------------------
%% Erlang builtin functions allowed in guards.
--spec guard_bif(Name::atom(), Arity::arity()) -> boolean().
+-spec guard_bif(Name, Arity) -> boolean() when
+ Name :: atom(),
+ Arity :: arity().
guard_bif(abs, 1) -> true;
guard_bif(float, 1) -> true;
@@ -92,7 +94,9 @@ guard_bif(binary_part, 3) -> true;
guard_bif(Name, A) when is_atom(Name), is_integer(A) -> false.
%% Erlang type tests.
--spec type_test(Name::atom(), Arity::arity()) -> boolean().
+-spec type_test(Name, Arity) -> boolean() when
+ Name :: atom(),
+ Arity :: arity().
type_test(Name, Arity) ->
new_type_test(Name, Arity) orelse old_type_test(Name, Arity).
@@ -135,7 +139,9 @@ old_type_test(record, 2) -> true;
old_type_test(function, 1) -> true;
old_type_test(Name, A) when is_atom(Name), is_integer(A) -> false.
--spec arith_op(Op::atom(), Arity::arity()) -> boolean().
+-spec arith_op(OpName, Arity) -> boolean() when
+ OpName :: atom(),
+ Arity :: arity().
arith_op('+', 1) -> true;
arith_op('-', 1) -> true;
@@ -153,7 +159,9 @@ arith_op('bsl', 2) -> true;
arith_op('bsr', 2) -> true;
arith_op(Op, A) when is_atom(Op), is_integer(A) -> false.
--spec bool_op(Op::atom(), Arity::arity()) -> boolean().
+-spec bool_op(OpName, Arity) -> boolean() when
+ OpName :: atom(),
+ Arity :: arity().
bool_op('not', 1) -> true;
bool_op('and', 2) -> true;
@@ -161,7 +169,9 @@ bool_op('or', 2) -> true;
bool_op('xor', 2) -> true;
bool_op(Op, A) when is_atom(Op), is_integer(A) -> false.
--spec comp_op(Op::atom(), Arity::arity()) -> boolean().
+-spec comp_op(OpName, Arity) -> boolean() when
+ OpName :: atom(),
+ Arity :: arity().
comp_op('==', 2) -> true;
comp_op('/=', 2) -> true;
@@ -173,18 +183,25 @@ comp_op('=:=', 2) -> true;
comp_op('=/=', 2) -> true;
comp_op(Op, A) when is_atom(Op), is_integer(A) -> false.
--spec list_op(Op::atom(), Arity::arity()) -> boolean().
+-spec list_op(OpName, Arity) -> boolean() when
+ OpName :: atom(),
+ Arity :: arity().
list_op('++', 2) -> true;
list_op('--', 2) -> true;
list_op(Op, A) when is_atom(Op), is_integer(A) -> false.
--spec send_op(Op::atom(), Arity::arity()) -> boolean().
+-spec send_op(OpName, Arity) -> boolean() when
+ OpName :: atom(),
+ Arity :: arity().
send_op('!', 2) -> true;
send_op(Op, A) when is_atom(Op), is_integer(A) -> false.
--spec op_type(atom(), arity()) -> 'arith' | 'bool' | 'comp' | 'list' | 'send'.
+-spec op_type(OpName, Arity) -> Type when
+ OpName :: atom(),
+ Arity :: arity(),
+ Type :: 'arith' | 'bool' | 'comp' | 'list' | 'send'.
op_type('+', 1) -> arith;
op_type('-', 1) -> arith;
@@ -221,7 +238,9 @@ op_type('!', 2) -> send.
bif(erlang, Name, Arity) -> bif(Name, Arity);
bif(M, F, A) when is_atom(M), is_atom(F), is_integer(A) -> false.
--spec bif(Name::atom(), Arity::arity()) -> boolean().
+-spec bif(Name, Arity) -> boolean() when
+ Name :: atom(),
+ Arity::arity().
%% Returns true if erlang:Name/Arity is an auto-imported BIF, false otherwise.
%% Use erlang:is_bultin(Mod, Name, Arity) to find whether a function is a BIF
%% (meaning implemented in C) or not.
@@ -243,8 +262,8 @@ bif(bitsize, 1) -> true;
bif(bit_size, 1) -> true;
bif(bitstring_to_list, 1) -> true;
bif(byte_size, 1) -> true;
+bif(check_old_code, 1) -> true;
bif(check_process_code, 2) -> true;
-bif(concat_binary, 1) -> true;
bif(date, 0) -> true;
bif(delete_module, 1) -> true;
bif(demonitor, 1) -> true;
@@ -386,7 +405,6 @@ old_bif(bit_size, 1) -> true;
old_bif(bitstring_to_list, 1) -> true;
old_bif(byte_size, 1) -> true;
old_bif(check_process_code, 2) -> true;
-old_bif(concat_binary, 1) -> true;
old_bif(date, 0) -> true;
old_bif(delete_module, 1) -> true;
old_bif(disconnect_node, 1) -> true;
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index cfb9f0ca98..78b996d94b 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -123,15 +123,21 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
called= [] :: [{fa(),line()}], %Called functions
usage = #usage{} :: #usage{},
specs = dict:new() :: dict(), %Type specifications
+ callbacks = dict:new() :: dict(), %Callback types
types = dict:new() :: dict(), %Type definitions
exp_types=gb_sets:empty():: gb_set() %Exported types
}).
-type lint_state() :: #lint{}.
+-type error_description() :: term().
+-type error_info() :: {erl_scan:line(), module(), error_description()}.
%% format_error(Error)
%% Return a string describing the error.
+-spec format_error(ErrorDescriptor) -> io_lib:chars() when
+ ErrorDescriptor :: error_description().
+
format_error(undefined_module) ->
"no module definition";
format_error({bad_module_name, M}) ->
@@ -305,8 +311,6 @@ format_error({conflicting_behaviours,{Name,Arity},B,FirstL,FirstB}) ->
format_error({undefined_behaviour_func, {Func,Arity}, Behaviour}) ->
io_lib:format("undefined callback function ~w/~w (behaviour '~w')",
[Func,Arity,Behaviour]);
-format_error({undefined_behaviour_func, {Func,Arity,_Spec}, Behaviour}) ->
- format_error({undefined_behaviour_func, {Func,Arity}, Behaviour});
format_error({undefined_behaviour,Behaviour}) ->
io_lib:format("behaviour ~w undefined", [Behaviour]);
format_error({undefined_behaviour_callbacks,Behaviour}) ->
@@ -315,6 +319,9 @@ format_error({undefined_behaviour_callbacks,Behaviour}) ->
format_error({ill_defined_behaviour_callbacks,Behaviour}) ->
io_lib:format("behaviour ~w callback functions erroneously defined",
[Behaviour]);
+format_error({behaviour_info, {_M,F,A}}) ->
+ io_lib:format("cannot define callback attibute for ~w/~w when "
+ "behaviour_info is defined",[F,A]);
%% --- types and specs ---
format_error({singleton_typevar, Name}) ->
io_lib:format("type variable ~w is only used once (is unbound)", [Name]);
@@ -343,12 +350,16 @@ format_error({type_syntax, Constr}) ->
io_lib:format("bad ~w type", [Constr]);
format_error({redefine_spec, {M, F, A}}) ->
io_lib:format("spec for ~w:~w/~w already defined", [M, F, A]);
+format_error({redefine_callback, {M, F, A}}) ->
+ io_lib:format("callback ~w:~w/~w already defined", [M, F, A]);
format_error({spec_fun_undefined, {M, F, A}}) ->
io_lib:format("spec for undefined function ~w:~w/~w", [M, F, A]);
format_error({missing_spec, {F,A}}) ->
io_lib:format("missing specification for function ~w/~w", [F, A]);
format_error(spec_wrong_arity) ->
"spec has the wrong arity";
+format_error(callback_wrong_arity) ->
+ "callback has the wrong arity";
format_error({imported_predefined_type, Name}) ->
io_lib:format("referring to built-in type ~w as a remote type; "
"please take out the module name", [Name]);
@@ -419,16 +430,39 @@ used_vars(Exprs, BindingsList) ->
%% apply_lambda/2 has been called to shut lint up. N.B. these lists are
%% really all ordsets!
+-spec(module(AbsForms) -> {ok, Warnings} | {error, Errors, Warnings} when
+ AbsForms :: [erl_parse:abstract_form()],
+ Warnings :: [{file:filename(),[ErrorInfo]}],
+ Errors :: [{FileName2 :: file:filename(),[ErrorInfo]}],
+ ErrorInfo :: error_info()).
+
module(Forms) ->
Opts = compiler_options(Forms),
St = forms(Forms, start("nofile", Opts)),
return_status(St).
+-spec(module(AbsForms, FileName) ->
+ {ok, Warnings} | {error, Errors, Warnings} when
+ AbsForms :: [erl_parse:abstract_form()],
+ FileName :: atom() | string(),
+ Warnings :: [{file:filename(),[ErrorInfo]}],
+ Errors :: [{FileName2 :: file:filename(),[ErrorInfo]}],
+ ErrorInfo :: error_info()).
+
module(Forms, FileName) ->
Opts = compiler_options(Forms),
St = forms(Forms, start(FileName, Opts)),
return_status(St).
+-spec(module(AbsForms, FileName, CompileOptions) ->
+ {ok, Warnings} | {error, Errors, Warnings} when
+ AbsForms :: [erl_parse:abstract_form()],
+ FileName :: atom() | string(),
+ CompileOptions :: [compile:option()],
+ Warnings :: [{file:filename(),[ErrorInfo]}],
+ Errors :: [{FileName2 :: file:filename(),[ErrorInfo]}],
+ ErrorInfo :: error_info()).
+
module(Forms, FileName, Opts0) ->
%% We want the options given on the command line to take
%% precedence over options in the module.
@@ -719,6 +753,8 @@ attribute_state({attribute,L,opaque,{TypeName,TypeDef,Args}}, St) ->
type_def(opaque, L, TypeName, TypeDef, Args, St);
attribute_state({attribute,L,spec,{Fun,Types}}, St) ->
spec_decl(L, Fun, Types, St);
+attribute_state({attribute,L,callback,{Fun,Types}}, St) ->
+ callback_decl(L, Fun, Types, St);
attribute_state({attribute,L,on_load,Val}, St) ->
on_load(L, Val, St);
attribute_state({attribute,_L,_Other,_Val}, St) -> % Ignore others
@@ -812,7 +848,8 @@ post_traversal_check(Forms, St0) ->
StB = check_unused_types(Forms, StA),
StC = check_untyped_records(Forms, StB),
StD = check_on_load(StC),
- check_unused_records(Forms, StD).
+ StE = check_unused_records(Forms, StD),
+ check_callback_information(StE).
%% check_behaviour(State0) -> State
%% Check that the behaviour attribute is valid.
@@ -1111,6 +1148,23 @@ check_unused_records(Forms, St0) ->
St0
end.
+check_callback_information(#lint{callbacks = Callbacks,
+ defined = Defined} = State) ->
+ case gb_sets:is_member({behaviour_info,1}, Defined) of
+ false -> State;
+ true ->
+ case dict:size(Callbacks) of
+ 0 -> State;
+ _ ->
+ CallbacksList = dict:to_list(Callbacks),
+ FoldL =
+ fun({Fa,Line},St) ->
+ add_error(Line, {behaviour_info, Fa}, St)
+ end,
+ lists:foldl(FoldL, State, CallbacksList)
+ end
+ end.
+
%% For storing the import list we use the orddict module.
%% We know an empty set is [].
@@ -1877,6 +1931,9 @@ gexpr_list(Es, Vt, St) ->
%% is_guard_test(Expression) -> boolean().
%% Test if a general expression is a guard test.
+-spec is_guard_test(Expr) -> boolean() when
+ Expr :: erl_parse:abstract_expr().
+
is_guard_test(E) ->
is_guard_test2(E, dict:new()).
@@ -2739,6 +2796,20 @@ spec_decl(Line, MFA0, TypeSpecs, St0 = #lint{specs = Specs, module = Mod}) ->
false -> check_specs(TypeSpecs, Arity, St1)
end.
+%% callback_decl(Line, Fun, Types, State) -> State.
+
+callback_decl(Line, MFA0, TypeSpecs,
+ St0 = #lint{callbacks = Callbacks, module = Mod}) ->
+ MFA = case MFA0 of
+ {F, Arity} -> {Mod, F, Arity};
+ {_M, _F, Arity} -> MFA0
+ end,
+ St1 = St0#lint{callbacks = dict:store(MFA, Line, Callbacks)},
+ case dict:is_key(MFA, Callbacks) of
+ true -> add_error(Line, {redefine_callback, MFA}, St1);
+ false -> check_specs(TypeSpecs, Arity, St1)
+ end.
+
check_specs([FunType|Left], Arity, St0) ->
{FunType1, CTypes} =
case FunType of
@@ -3244,6 +3315,8 @@ modify_line1({attribute,L,record,{Name,Fields}}, Mf) ->
{attribute,Mf(L),record,{Name,modify_line1(Fields, Mf)}};
modify_line1({attribute,L,spec,{Fun,Types}}, Mf) ->
{attribute,Mf(L),spec,{Fun,modify_line1(Types, Mf)}};
+modify_line1({attribute,L,callback,{Fun,Types}}, Mf) ->
+ {attribute,Mf(L),callback,{Fun,modify_line1(Types, Mf)}};
modify_line1({attribute,L,type,{TypeName,TypeDef,Args}}, Mf) ->
{attribute,Mf(L),type,{TypeName,modify_line1(TypeDef, Mf),
modify_line1(Args, Mf)}};
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 15b45d72f4..709bd83e6f 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -62,7 +62,7 @@ char integer float atom string var
'==' '/=' '=<' '<' '>=' '>' '=:=' '=/=' '<='
'<<' '>>'
'!' '=' '::' '..' '...'
-'spec' % helper
+'spec' 'callback' % helper
dot.
Expect 2.
@@ -77,6 +77,7 @@ attribute -> '-' atom attr_val : build_attribute('$2', '$3').
attribute -> '-' atom typed_attr_val : build_typed_attribute('$2','$3').
attribute -> '-' atom '(' typed_attr_val ')' : build_typed_attribute('$2','$4').
attribute -> '-' 'spec' type_spec : build_type_spec('$2', '$3').
+attribute -> '-' 'callback' type_spec : build_type_spec('$2', '$3').
type_spec -> spec_fun type_sigs : {'$1', '$2'}.
type_spec -> '(' spec_fun type_sigs ')' : {'$2', '$3'}.
@@ -511,6 +512,15 @@ Erlang code.
%% of the generated .erl file by the HiPE compiler. Please do not remove.
-compile([{hipe,[{regalloc,linear_scan}]}]).
+-export_type([abstract_clause/0, abstract_expr/0, abstract_form/0,
+ error_info/0]).
+
+-type abstract_clause() :: term().
+-type abstract_expr() :: term().
+-type abstract_form() :: term().
+-type error_description() :: term().
+-type error_info() :: {erl_scan:line(), module(), error_description()}.
+-type token() :: {Tag :: atom(), Line :: erl_scan:line()}.
%% mkop(Op, Arg) -> {op,Line,Op,Arg}.
%% mkop(Left, Op, Right) -> {op,Line,Op,Left,Right}.
@@ -534,11 +544,21 @@ Erlang code.
%% These really suck and are only here until Calle gets multiple
%% entry points working.
+-spec parse_form(Tokens) -> {ok, AbsForm} | {error, ErrorInfo} when
+ Tokens :: [token()],
+ AbsForm :: abstract_form(),
+ ErrorInfo :: error_info().
parse_form([{'-',L1},{atom,L2,spec}|Tokens]) ->
parse([{'-',L1},{'spec',L2}|Tokens]);
+parse_form([{'-',L1},{atom,L2,callback}|Tokens]) ->
+ parse([{'-',L1},{'callback',L2}|Tokens]);
parse_form(Tokens) ->
parse(Tokens).
+-spec parse_exprs(Tokens) -> {ok, ExprList} | {error, ErrorInfo} when
+ Tokens :: [token()],
+ ExprList :: [abstract_expr()],
+ ErrorInfo :: error_info().
parse_exprs(Tokens) ->
case parse([{atom,0,f},{'(',0},{')',0},{'->',0}|Tokens]) of
{ok,{function,_Lf,f,0,[{clause,_Lc,[],[],Exprs}]}} ->
@@ -546,6 +566,10 @@ parse_exprs(Tokens) ->
{error,_} = Err -> Err
end.
+-spec parse_term(Tokens) -> {ok, Term} | {error, ErrorInfo} when
+ Tokens :: [token()],
+ Term :: term(),
+ ErrorInfo :: error_info().
parse_term(Tokens) ->
case parse([{atom,0,f},{'(',0},{')',0},{'->',0}|Tokens]) of
{ok,{function,_Lf,f,0,[{clause,_Lc,[],[],[Expr]}]}} ->
@@ -582,7 +606,8 @@ build_typed_attribute({atom,La,Attr},_) ->
_ -> ret_err(La, "bad attribute")
end.
-build_type_spec({spec,La}, {SpecFun, TypeSpecs}) ->
+build_type_spec({Kind,La}, {SpecFun, TypeSpecs})
+ when (Kind =:= spec) or (Kind =:= callback) ->
NewSpecFun =
case SpecFun of
{atom, _, Fun} ->
@@ -596,7 +621,7 @@ build_type_spec({spec,La}, {SpecFun, TypeSpecs}) ->
%% Old style spec. Allow this for now.
{Mod,Fun,Arity}
end,
- {attribute,La,spec,{NewSpecFun, TypeSpecs}}.
+ {attribute,La,Kind,{NewSpecFun, TypeSpecs}}.
find_arity_from_specs([Spec|_]) ->
%% Use the first spec to find the arity. If all are not the same,
@@ -830,6 +855,7 @@ check_clauses(Cs, Name, Arity) ->
build_try(L,Es,Scs,{Ccs,As}) ->
{'try',L,Es,Scs,Ccs,As}.
+-spec ret_err(_, _) -> no_return().
ret_err(L, S) ->
{location,Location} = get_attribute(L, location),
return_error(Location, S).
@@ -846,10 +872,11 @@ mapl(F, [H|T]) ->
mapl(_, []) ->
[].
-%% normalise(AbsTerm)
-%% abstract(Term)
%% Convert between the abstract form of a term and a term.
+-spec normalise(AbsTerm) -> Data when
+ AbsTerm :: abstract_expr(),
+ Data :: term().
normalise({char,_,C}) -> C;
normalise({integer,_,I}) -> I;
normalise({float,_,F}) -> F;
@@ -887,6 +914,9 @@ normalise_list([H|T]) ->
normalise_list([]) ->
[].
+-spec abstract(Data) -> AbsTerm when
+ Data :: term(),
+ AbsTerm :: abstract_expr().
abstract(T) when is_integer(T) -> {integer,0,T};
abstract(T) when is_float(T) -> {float,0,T};
abstract(T) when is_atom(T) -> {atom,0,T};
@@ -955,13 +985,18 @@ abstract_list([H|T], Line) ->
abstract_list([], _Line) ->
[].
-%% tokens(AbsTerm) -> [Token]
-%% tokens(AbsTerm, More) -> [Token]
%% Generate a list of tokens representing the abstract term.
+-spec tokens(AbsTerm) -> Tokens when
+ AbsTerm :: abstract_expr(),
+ Tokens :: [token()].
tokens(Abs) ->
tokens(Abs, []).
+-spec tokens(AbsTerm, MoreTokens) -> Tokens when
+ AbsTerm :: abstract_expr(),
+ MoreTokens :: [token()],
+ Tokens :: [token()].
tokens({char,L,C}, More) -> [{char,L,C}|More];
tokens({integer,L,N}, More) -> [{integer,L,N}|More];
tokens({float,L,F}, More) -> [{float,L,F}|More];
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 66c80a45cb..7dc19f2e9b 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -31,25 +31,53 @@
-define(MAXLINE, 72).
+-type(hook_function() :: none
+ | fun((Expr :: erl_parse:abstract_expr(),
+ CurrentIndentation :: integer(),
+ CurrentPrecedence :: non_neg_integer(),
+ HookFunction :: hook_function()) ->
+ io_lib:chars())).
+
%%%
%%% Exported functions
%%%
+-spec(form(Form) -> io_lib:chars() when
+ Form :: erl_parse:abstract_form()).
+
form(Thing) ->
form(Thing, none).
+-spec(form(Form, HookFunction) -> io_lib:chars() when
+ Form :: erl_parse:abstract_form(),
+ HookFunction :: hook_function()).
+
form(Thing, Hook) ->
frmt(lform(Thing, Hook)).
+-spec(attribute(Attribute) -> io_lib:chars() when
+ Attribute :: erl_parse:abstract_form()).
+
attribute(Thing) ->
attribute(Thing, none).
+-spec(attribute(Attribute, HookFunction) -> io_lib:chars() when
+ Attribute :: erl_parse:abstract_form(),
+ HookFunction :: hook_function()).
+
attribute(Thing, Hook) ->
frmt(lattribute(Thing, Hook)).
+-spec(function(Function) -> io_lib:chars() when
+ Function :: erl_parse:abstract_form()).
+
function(F) ->
function(F, none).
+-spec(function(Function, HookFunction) -> io_lib:chars() when
+ Function :: erl_parse:abstract_form(),
+ HookFunction :: hook_function()).
+
function(F, Hook) ->
frmt(lfunction(F, Hook)).
@@ -59,30 +87,67 @@ rule(R) ->
rule(R, Hook) ->
frmt(lrule(R, Hook)).
+-spec(guard(Guard) -> io_lib:chars() when
+ Guard :: [erl_parse:abstract_expr()]).
+
guard(Gs) ->
guard(Gs, none).
+-spec(guard(Guard, HookFunction) -> io_lib:chars() when
+ Guard :: [erl_parse:abstract_expr()],
+ HookFunction :: hook_function()).
+
guard(Gs, Hook) ->
frmt(lguard(Gs, Hook)).
+-spec(exprs(Expressions) -> io_lib:chars() when
+ Expressions :: [erl_parse:abstract_expr()]).
+
exprs(Es) ->
exprs(Es, 0, none).
+-spec(exprs(Expressions, HookFunction) -> io_lib:chars() when
+ Expressions :: [erl_parse:abstract_expr()],
+ HookFunction :: hook_function()).
+
exprs(Es, Hook) ->
exprs(Es, 0, Hook).
+-spec(exprs(Expressions, Indent, HookFunction) -> io_lib:chars() when
+ Expressions :: [erl_parse:abstract_expr()],
+ Indent :: integer(),
+ HookFunction :: hook_function()).
+
exprs(Es, I, Hook) ->
frmt({seq,[],[],[$,],lexprs(Es, Hook)}, I).
+-spec(expr(Expression) -> io_lib:chars() when
+ Expression :: erl_parse:abstract_expr()).
+
expr(E) ->
frmt(lexpr(E, 0, none)).
+-spec(expr(Expression, HookFunction) -> io_lib:chars() when
+ Expression :: erl_parse:abstract_expr(),
+ HookFunction :: hook_function()).
+
expr(E, Hook) ->
frmt(lexpr(E, 0, Hook)).
+-spec(expr(Expression, Indent, HookFunction) -> io_lib:chars() when
+ Expression :: erl_parse:abstract_expr(),
+ Indent :: integer(),
+ HookFunction :: hook_function()).
+
expr(E, I, Hook) ->
frmt(lexpr(E, 0, Hook), I).
+-spec(expr(Expression, Indent, Precedence, HookFunction) -> io_lib:chars() when
+ Expression :: erl_parse:abstract_expr(),
+ Indent :: integer(),
+ Precedence :: non_neg_integer(),
+ HookFunction :: hook_function()).
+
expr(E, I, P, Hook) ->
frmt(lexpr(E, P, Hook), I).
diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl
index 18f64c46d0..10b2ed2e49 100644
--- a/lib/stdlib/src/erl_scan.erl
+++ b/lib/stdlib/src/erl_scan.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -99,7 +99,8 @@
%%----------------------------------------------------------------------------
--spec format_error(Error :: term()) -> string().
+-spec format_error(ErrorDescriptor) -> string() when
+ ErrorDescriptor :: error_description().
format_error({string,Quote,Head}) ->
lists:flatten(["unterminated " ++ string_thing(Quote) ++
" starting with " ++
@@ -112,20 +113,33 @@ format_error({base,Base}) ->
format_error(Other) ->
lists:flatten(io_lib:write(Other)).
--type string_return() :: {'ok', tokens(), location()}
- | {'error', error_info(), location()}.
-
--spec string(String :: string()) -> string_return().
+-spec string(String) -> Return when
+ String :: string(),
+ Return :: {'ok', Tokens :: tokens(), EndLocation}
+ | {'error', ErrorInfo :: error_info(), ErrorLocation},
+ EndLocation :: location(),
+ ErrorLocation :: location().
string(String) ->
string(String, 1, []).
--spec string(String :: string(), StartLocation :: location()) ->
- string_return().
+-spec string(String, StartLocation) -> Return when
+ String :: string(),
+ Return :: {'ok', Tokens :: tokens(), EndLocation}
+ | {'error', ErrorInfo :: error_info(), ErrorLocation},
+ StartLocation :: location(),
+ EndLocation :: location(),
+ ErrorLocation :: location().
string(String, StartLocation) ->
string(String, StartLocation, []).
--spec string(String :: string(), StartLocation :: location(),
- Options :: options()) -> string_return().
+-spec string(String, StartLocation, Options) -> Return when
+ String :: string(),
+ Options :: options(),
+ Return :: {'ok', Tokens :: tokens(), EndLocation}
+ | {'error', ErrorInfo :: error_info(), ErrorLocation},
+ StartLocation :: location(),
+ EndLocation :: location(),
+ ErrorLocation :: location().
string(String, Line, Options) when ?STRING(String), ?ALINE(Line) ->
string1(String, options(Options), Line, no_col, []);
string(String, {Line,Column}, Options) when ?STRING(String),
@@ -136,29 +150,37 @@ string(String, {Line,Column}, Options) when ?STRING(String),
-type char_spec() :: string() | 'eof'.
-type cont_fun() :: fun((char_spec(), #erl_scan{}, line(), column(),
tokens(), any()) -> any()).
--opaque return_cont() :: {string(), column(), tokens(), line(),
- #erl_scan{}, cont_fun(), any()}.
--type cont() :: return_cont() | [].
--type tokens_result() :: {'ok', tokens(), location()}
- | {'eof', location()}
- | {'error', error_info(), location()}.
--type tokens_return() :: {'done', tokens_result(), char_spec()}
- | {'more', return_cont()}.
-
--spec tokens(Cont :: cont(), CharSpec :: char_spec(),
- StartLocation :: location()) -> tokens_return().
+-opaque return_cont() :: {erl_scan_continuation,
+ string(), column(), tokens(), line(),
+ #erl_scan{}, any(), cont_fun()}.
+-type tokens_result() :: {'ok', Tokens :: tokens(), EndLocation :: location()}
+ | {'eof', EndLocation :: location()}
+ | {'error', ErrorInfo :: error_info(),
+ EndLocation :: location()}.
+
+-spec tokens(Continuation, CharSpec, StartLocation) -> Return when
+ Continuation :: return_cont() | [],
+ CharSpec :: char_spec(),
+ StartLocation :: location(),
+ Return :: {'done',Result :: tokens_result(),LeftOverChars :: char_spec()}
+ | {'more', Continuation1 :: return_cont()}.
tokens(Cont, CharSpec, StartLocation) ->
tokens(Cont, CharSpec, StartLocation, []).
--spec tokens(Cont :: cont(), CharSpec :: char_spec(),
- StartLocation :: location(), Options :: options()) ->
- tokens_return().
+-spec tokens(Continuation, CharSpec, StartLocation, Options) -> Return when
+ Continuation :: return_cont() | [],
+ CharSpec :: char_spec(),
+ StartLocation :: location(),
+ Options :: options(),
+ Return :: {'done',Result :: tokens_result(),LeftOverChars :: char_spec()}
+ | {'more', Continuation1 :: return_cont()}.
tokens([], CharSpec, Line, Options) when ?ALINE(Line) ->
tokens1(CharSpec, options(Options), Line, no_col, [], fun scan/6, []);
tokens([], CharSpec, {Line,Column}, Options) when ?ALINE(Line),
?COLUMN(Column) ->
tokens1(CharSpec, options(Options), Line, Column, [], fun scan/6, []);
-tokens({Cs,Col,Toks,Line,St,Any,Fun}, CharSpec, _Loc, _Opts) ->
+tokens({erl_scan_continuation,Cs,Col,Toks,Line,St,Any,Fun},
+ CharSpec, _Loc, _Opts) ->
tokens1(Cs++CharSpec, St, Line, Col, Toks, Fun, Any).
-type attribute_item() :: 'column' | 'length' | 'line'
@@ -172,13 +194,22 @@ tokens({Cs,Col,Toks,Line,St,Any,Fun}, CharSpec, _Loc, _Opts) ->
-type token_info() :: {'category', category()} | {'symbol', symbol()}
| attribute_info().
--spec token_info(token()) -> [token_info()].
+-spec token_info(Token) -> TokenInfo when
+ Token :: token(),
+ TokenInfo :: [TokenInfoTuple :: token_info()].
token_info(Token) ->
Items = [category,column,length,line,symbol,text], % undefined order
token_info(Token, Items).
--spec token_info(token(), token_item()) -> token_info() | 'undefined';
- (token(), [token_item()]) -> [token_info()].
+-spec token_info(Token, TokenItem) -> TokenInfo | 'undefined' when
+ Token :: token(),
+ TokenItem :: token_item(),
+ TokenInfo :: TokenInfoTuple :: token_info();
+ (Token, TokenItems) -> [TokenInfo] when
+ Token :: token(),
+ TokenItems :: [TokenItem],
+ TokenItem :: token_item(),
+ TokenInfo :: [TokenInfoTuple :: token_info()].
token_info(_Token, []) ->
[];
token_info(Token, [Item|Items]) when is_atom(Item) ->
@@ -201,14 +232,23 @@ token_info({_Category,Attrs}, Item) ->
token_info({_Category,Attrs,_Symbol}, Item) ->
attributes_info(Attrs, Item).
--spec attributes_info(attributes()) -> [attribute_info()].
+-spec attributes_info(Attributes) -> AttributesInfo when
+ Attributes :: attributes(),
+ AttributesInfo :: [AttributeInfoTuple :: attribute_info()].
attributes_info(Attributes) ->
Items = [column,length,line,text], % undefined order
attributes_info(Attributes, Items).
--spec attributes_info(attributes(), attribute_item()) ->
- attribute_info() | 'undefined';
- (attributes(), [attribute_item()]) -> [attribute_info()].
+-spec attributes_info(Attributes, AttributeItem) ->
+ AttributeInfo | 'undefined' when
+ Attributes :: attributes(),
+ AttributeItem :: attribute_item(),
+ AttributeInfo :: AttributeInfoTuple :: attribute_info();
+ (Attributes, AttributeItems) -> [AttributeInfo] when
+ Attributes :: attributes(),
+ AttributeItems :: [AttributeItem],
+ AttributeItem :: attribute_item(),
+ AttributeInfo :: [AttributeInfoTuple :: attribute_info()].
attributes_info(_Attrs, []) ->
[];
attributes_info(Attrs, [A|As]) when is_atom(A) ->
@@ -265,9 +305,10 @@ attributes_info(Attrs, text=Item) ->
attributes_info(T1, T2) ->
erlang:error(badarg, [T1,T2]).
--type setlineattr_fun() :: fun((info_line()) -> info_line()).
-
--spec set_attribute('line', attributes(), setlineattr_fun()) -> attributes().
+-spec set_attribute(AttributeItem, Attributes, SetAttributeFun) -> Attributes when
+ AttributeItem :: 'line',
+ Attributes :: attributes(),
+ SetAttributeFun :: fun((info_line()) -> info_line()).
set_attribute(Tag, Attributes, Fun) when ?SETATTRFUN(Fun) ->
set_attr(Tag, Attributes, Fun).
@@ -367,14 +408,19 @@ set_attr(line, {Line,Column}, Fun) when ?ALINE(Line), ?COLUMN(Column) ->
end;
set_attr(line=Tag, Attrs, Fun) when is_list(Attrs) ->
{line,Line} = lists:keyfind(Tag, 1, Attrs),
- lists:keyreplace(Tag, 1, Attrs, {line,Fun(Line)});
+ case lists:keyreplace(Tag, 1, Attrs, {line,Fun(Line)}) of
+ [{line,Ln}] when ?ALINE(Ln) ->
+ Ln;
+ As ->
+ As
+ end;
set_attr(T1, T2, T3) ->
erlang:error(badarg, [T1,T2,T3]).
tokens1(Cs, St, Line, Col, Toks, Fun, Any) when ?STRING(Cs); Cs =:= eof ->
case Fun(Cs, St, Line, Col, Toks, Any) of
{more,{Cs0,Ncol,Ntoks,Nline,Nany,Nfun}} ->
- {more,{Cs0,Ncol,Ntoks,Nline,St,Nany,Nfun}};
+ {more,{erl_scan_continuation,Cs0,Ncol,Ntoks,Nline,St,Nany,Nfun}};
{ok,Toks0,eof,Nline,Ncol} ->
Res = case Toks0 of
[] ->
@@ -1285,7 +1331,7 @@ tabs(8) -> "\t\t\t\t\t\t\t\t";
tabs(9) -> "\t\t\t\t\t\t\t\t\t";
tabs(10) -> "\t\t\t\t\t\t\t\t\t\t".
--spec reserved_word(atom()) -> boolean().
+-spec reserved_word(Atom :: atom()) -> boolean().
reserved_word('after') -> true;
reserved_word('begin') -> true;
reserved_word('case') -> true;
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index fd85c7aef5..306834e845 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -798,30 +798,10 @@ set_extracted_file_info(Name, #tar_header{mode=Mode, mtime=Mtime}) ->
%% Makes all directories leading up to the file.
-make_dirs(Name, Type) ->
- make_dirs1(filename:split(Name), Type).
-
-make_dirs1([Dir, Next|Rest], Type) ->
- case file:read_file_info(Dir) of
- {ok, #file_info{type=directory}} ->
- make_dirs1([filename:join(Dir, Next)|Rest], Type);
- {ok, #file_info{}} ->
- throw({error, enotdir});
- {error, _} ->
- case file:make_dir(Dir) of
- ok ->
- make_dirs1([filename:join(Dir, Next)|Rest], Type);
- {error, Reason} ->
- throw({error, Reason})
- end
- end;
-make_dirs1([_], file) -> ok;
-make_dirs1([Dir], dir) ->
- file:make_dir(Dir);
-make_dirs1([], _) ->
- %% There must be something wrong here. The list was not supposed
- %% to be empty.
- throw({error, enoent}).
+make_dirs(Name, file) ->
+ filelib:ensure_dir(Name);
+make_dirs(Name, dir) ->
+ filelib:ensure_dir(filename:join(Name,"*")).
%% Prints the message on if the verbose option is given (for reading).
diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl
index 435e57aa0e..fa13fbb2bd 100644
--- a/lib/stdlib/src/error_logger_tty_h.erl
+++ b/lib/stdlib/src/error_logger_tty_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -34,10 +34,12 @@
handle_event/2, handle_call/2, handle_info/2,
terminate/2, code_change/3]).
+-export([write_event/2]).
+
%% This one is used when we takeover from the simple error_logger.
init({[], {error_logger, Buf}}) ->
User = set_group_leader(),
- write_events(Buf),
+ write_events(Buf,io),
{ok, {User, error_logger}};
%% This one is used if someone took over from us, and now wants to
%% go back.
@@ -52,7 +54,7 @@ init([]) ->
handle_event({_Type, GL, _Msg}, State) when node(GL) =/= node() ->
{ok, State};
handle_event(Event, State) ->
- write_event(tag_event(Event)),
+ write_event(tag_event(Event),io),
{ok, State}.
handle_info({'EXIT', User, _Reason}, {User, PrevHandler}) ->
@@ -64,10 +66,10 @@ handle_info({'EXIT', User, _Reason}, {User, PrevHandler}) ->
PrevHandler, go_back}
end;
handle_info({emulator, GL, Chars}, State) when node(GL) == node() ->
- write_event(tag_event({emulator, GL, Chars})),
+ write_event(tag_event({emulator, GL, Chars}),io),
{ok, State};
handle_info({emulator, noproc, Chars}, State) ->
- write_event(tag_event({emulator, noproc, Chars})),
+ write_event(tag_event({emulator, noproc, Chars}),io),
{ok, State};
handle_info(_, State) ->
{ok, State}.
@@ -97,65 +99,65 @@ set_group_leader() ->
tag_event(Event) ->
{erlang:localtime(), Event}.
-write_events(Events) -> write_events1(lists:reverse(Events)).
+write_events(Events,IOMod) -> write_events1(lists:reverse(Events),IOMod).
-write_events1([Event|Es]) ->
- write_event(Event),
- write_events1(Es);
-write_events1([]) ->
+write_events1([Event|Es],IOMod) ->
+ write_event(Event,IOMod),
+ write_events1(Es,IOMod);
+write_events1([],_IOMod) ->
ok.
-write_event({Time, {error, _GL, {Pid, Format, Args}}}) ->
+write_event({Time, {error, _GL, {Pid, Format, Args}}},IOMod) ->
T = write_time(maybe_utc(Time)),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
- format(T ++ F, [Format,Args])
+ format(IOMod, T ++ F, [Format,Args])
end;
-write_event({Time, {emulator, _GL, Chars}}) ->
+write_event({Time, {emulator, _GL, Chars}},IOMod) ->
T = write_time(maybe_utc(Time)),
case catch io_lib:format(Chars, []) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
- format(T ++ "ERROR: ~p ~n", [Chars])
+ format(IOMod, T ++ "ERROR: ~p ~n", [Chars])
end;
-write_event({Time, {info, _GL, {Pid, Info, _}}}) ->
+write_event({Time, {info, _GL, {Pid, Info, _}}},IOMod) ->
T = write_time(maybe_utc(Time)),
- format(T ++ add_node("~p~n",Pid),[Info]);
-write_event({Time, {error_report, _GL, {Pid, std_error, Rep}}}) ->
+ format(IOMod, T ++ add_node("~p~n",Pid),[Info]);
+write_event({Time, {error_report, _GL, {Pid, std_error, Rep}}},IOMod) ->
T = write_time(maybe_utc(Time)),
S = format_report(Rep),
- format(T ++ S ++ add_node("", Pid));
-write_event({Time, {info_report, _GL, {Pid, std_info, Rep}}}) ->
+ format(IOMod, T ++ S ++ add_node("", Pid));
+write_event({Time, {info_report, _GL, {Pid, std_info, Rep}}},IOMod) ->
T = write_time(maybe_utc(Time), "INFO REPORT"),
S = format_report(Rep),
- format(T ++ S ++ add_node("", Pid));
-write_event({Time, {info_msg, _GL, {Pid, Format, Args}}}) ->
+ format(IOMod, T ++ S ++ add_node("", Pid));
+write_event({Time, {info_msg, _GL, {Pid, Format, Args}}},IOMod) ->
T = write_time(maybe_utc(Time), "INFO REPORT"),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
- format(T ++ F, [Format,Args])
+ format(IOMod, T ++ F, [Format,Args])
end;
-write_event({Time, {warning_report, _GL, {Pid, std_warning, Rep}}}) ->
+write_event({Time, {warning_report, _GL, {Pid, std_warning, Rep}}},IOMod) ->
T = write_time(maybe_utc(Time), "WARNING REPORT"),
S = format_report(Rep),
- format(T ++ S ++ add_node("", Pid));
-write_event({Time, {warning_msg, _GL, {Pid, Format, Args}}}) ->
+ format(IOMod, T ++ S ++ add_node("", Pid));
+write_event({Time, {warning_msg, _GL, {Pid, Format, Args}}},IOMod) ->
T = write_time(maybe_utc(Time), "WARNING REPORT"),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
- format(T ++ F, [Format,Args])
+ format(IOMod, T ++ F, [Format,Args])
end;
-write_event({_Time, _Error}) ->
+write_event({_Time, _Error},_IOMod) ->
ok.
maybe_utc(Time) ->
@@ -178,8 +180,9 @@ maybe_utc(Time) ->
Time
end.
-format(String) -> io:format(user, String, []).
-format(String, Args) -> io:format(user, String, Args).
+format(IOMod, String) -> format(IOMod, String, []).
+format(io_lib, String, Args) -> io_lib:format(String, Args);
+format(io, String, Args) -> io:format(user, String, Args).
format_report(Rep) when is_list(Rep) ->
case string_p(Rep) of
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index d67617260e..ad49d89908 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -62,10 +62,10 @@
-type zip_create_option() :: term().
-type section() ::
shebang
- | {shebang, shebang()}
+ | {shebang, shebang() | default | undefined}
| comment
- | {comment, comment()}
- | {emu_args, emu_args()}
+ | {comment, comment() | default | undefined}
+ | {emu_args, emu_args() | undefined}
| {source, file:filename() | binary()}
| {beam, file:filename() | binary()}
| {archive, file:filename() | binary()}
@@ -866,7 +866,7 @@ hidden_apply(App, M, F, Args) ->
catch
error:undef ->
case erlang:get_stacktrace() of
- [{M,F,Args} | _] ->
+ [{M,F,Args,_} | _] ->
Arity = length(Args),
Text = io_lib:format("Call to ~w:~w/~w in application ~w failed.\n",
[M, F, Arity, App]),
diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl
index 6e6e949e2c..afa914a456 100644
--- a/lib/stdlib/src/ets.erl
+++ b/lib/stdlib/src/ets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -42,7 +42,7 @@
-export([i/0, i/1, i/2, i/3]).
--export_type([tab/0, tid/0]).
+-export_type([tab/0, tid/0, match_spec/0]).
%%-----------------------------------------------------------------------------
@@ -51,22 +51,9 @@
%% a similar definition is also in erl_types
-opaque tid() :: integer().
--type ext_info() :: 'md5sum' | 'object_count'.
--type protection() :: 'private' | 'protected' | 'public'.
--type type() :: 'bag' | 'duplicate_bag' | 'ordered_set' | 'set'.
-
--type table_info() :: {'name', atom()}
- | {'type', type()}
- | {'protection', protection()}
- | {'named_table', boolean()}
- | {'keypos', non_neg_integer()}
- | {'size', non_neg_integer()}
- | {'extended_info', [ext_info()]}
- | {'version', {non_neg_integer(), non_neg_integer()}}.
-
%% these ones are also defined in erl_bif_types
-type match_pattern() :: atom() | tuple().
--type match_specs() :: [{match_pattern(), [_], [_]}].
+-type match_spec() :: [{match_pattern(), [_], [_]}].
%%-----------------------------------------------------------------------------
@@ -86,6 +73,7 @@
%% insert/2
%% is_compiled_ms/1
%% last/1
+%% member/2
%% next/2
%% prev/2
%% rename/2
@@ -101,11 +89,14 @@
%% select/1
%% select/2
%% select/3
+%% select_count/2
%% select_reverse/1
%% select_reverse/2
%% select_reverse/3
%% select_delete/2
+%% setopts/2
%% update_counter/3
+%% update_element/3
%%
-opaque comp_match_spec() :: any(). %% this one is REALLY opaque
@@ -119,7 +110,9 @@ match_spec_run(List, CompiledMS) ->
| {tab(),integer(),integer(),binary(),list(),integer()}
| {tab(),_,_,integer(),binary(),list(),integer(),integer()}.
--spec repair_continuation(continuation(), match_specs()) -> continuation().
+-spec repair_continuation(Continuation, MatchSpec) -> Continuation when
+ Continuation :: continuation(),
+ MatchSpec :: match_spec().
%% $end_of_table is an allowed continuation in ets...
repair_continuation('$end_of_table', _) ->
@@ -153,7 +146,9 @@ repair_continuation(Untouched = {Table,N1,N2,Bin,L,N3}, MS)
{Table,N1,N2,ets:match_spec_compile(MS),L,N3}
end.
--spec fun2ms(function()) -> match_specs().
+-spec fun2ms(LiteralFun) -> MatchSpec when
+ LiteralFun :: function(),
+ MatchSpec :: match_spec().
fun2ms(ShellFun) when is_function(ShellFun) ->
%% Check that this is really a shell fun...
@@ -177,7 +172,13 @@ fun2ms(ShellFun) when is_function(ShellFun) ->
shell]}})
end.
--spec foldl(fun((_, term()) -> term()), term(), tab()) -> term().
+-spec foldl(Function, Acc0, Tab) -> Acc1 when
+ Function :: fun((Element :: term(), AccIn) -> AccOut),
+ Tab :: tab(),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term().
foldl(F, Accu, T) ->
ets:safe_fixtable(T, true),
@@ -198,7 +199,13 @@ do_foldl(F, Accu0, Key, T) ->
ets:next(T, Key), T)
end.
--spec foldr(fun((_, term()) -> term()), term(), tab()) -> term().
+-spec foldr(Function, Acc0, Tab) -> Acc1 when
+ Function :: fun((Element :: term(), AccIn) -> AccOut),
+ Tab :: tab(),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term().
foldr(F, Accu, T) ->
ets:safe_fixtable(T, true),
@@ -219,7 +226,9 @@ do_foldr(F, Accu0, Key, T) ->
ets:prev(T, Key), T)
end.
--spec from_dets(tab(), dets:tab_name()) -> 'true'.
+-spec from_dets(Tab, DetsTab) -> 'true' when
+ Tab :: tab(),
+ DetsTab :: dets:tab_name().
from_dets(EtsTable, DetsTable) ->
case (catch dets:to_ets(DetsTable, EtsTable)) of
@@ -235,7 +244,9 @@ from_dets(EtsTable, DetsTable) ->
erlang:error(Unexpected,[EtsTable,DetsTable])
end.
--spec to_dets(tab(), dets:tab_name()) -> dets:tab_name().
+-spec to_dets(Tab, DetsTab) -> DetsTab when
+ Tab :: tab(),
+ DetsTab :: dets:tab_name().
to_dets(EtsTable, DetsTable) ->
case (catch dets:from_ets(DetsTable, EtsTable)) of
@@ -251,8 +262,11 @@ to_dets(EtsTable, DetsTable) ->
erlang:error(Unexpected,[EtsTable,DetsTable])
end.
--spec test_ms(tuple(), match_specs()) ->
- {'ok', term()} | {'error', [{'warning'|'error', string()}]}.
+-spec test_ms(Tuple, MatchSpec) -> {'ok', Result} | {'error', Errors} when
+ Tuple :: tuple(),
+ MatchSpec :: match_spec(),
+ Result :: term(),
+ Errors :: [{'warning'|'error', string()}].
test_ms(Term, MS) ->
case erlang:match_spec_test(Term, MS, table) of
@@ -262,7 +276,11 @@ test_ms(Term, MS) ->
Error
end.
--spec init_table(tab(), fun(('read' | 'close') -> term())) -> 'true'.
+-spec init_table(Tab, InitFun) -> 'true' when
+ Tab :: tab(),
+ InitFun :: fun((Arg) -> Res),
+ Arg :: 'read' | 'close',
+ Res :: 'end_of_input' | {Objects :: [term()], InitFun} | term().
init_table(Table, Fun) ->
ets:delete_all_objects(Table),
@@ -287,7 +305,9 @@ init_table_sub(Table, [H|T]) ->
ets:insert(Table, H),
init_table_sub(Table, T).
--spec match_delete(tab(), match_pattern()) -> 'true'.
+-spec match_delete(Tab, Pattern) -> 'true' when
+ Tab :: tab(),
+ Pattern :: match_pattern().
match_delete(Table, Pattern) ->
ets:select_delete(Table, [{Pattern,[],[true]}]),
@@ -295,7 +315,9 @@ match_delete(Table, Pattern) ->
%% Produce a list of tuples from a table
--spec tab2list(tab()) -> [tuple()].
+-spec tab2list(Tab) -> [Object] when
+ Tab :: tab(),
+ Object :: tuple().
tab2list(T) ->
ets:match_object(T, '_').
@@ -334,15 +356,21 @@ do_filter(Tab, Key, F, A, Ack) ->
md5sum = false :: boolean()
}).
--type fname() :: string() | atom().
--type t2f_option() :: {'extended_info', [ext_info()]}.
-
--spec tab2file(tab(), fname()) -> 'ok' | {'error', term()}.
+-spec tab2file(Tab, Filename) -> 'ok' | {'error', Reason} when
+ Tab :: tab(),
+ Filename :: file:name(),
+ Reason :: term().
tab2file(Tab, File) ->
tab2file(Tab, File, []).
--spec tab2file(tab(), fname(), [t2f_option()]) -> 'ok' | {'error', term()}.
+-spec tab2file(Tab, Filename, Options) -> 'ok' | {'error', Reason} when
+ Tab :: tab(),
+ Filename :: file:name(),
+ Options :: [Option],
+ Option :: {'extended_info', [ExtInfo]},
+ ExtInfo :: 'md5sum' | 'object_count',
+ Reason :: term().
tab2file(Tab, File, Options) ->
try
@@ -501,14 +529,20 @@ parse_ft_info_options(_,Malformed) ->
%% Opt := {verify,boolean()}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--type f2t_option() :: {'verify', boolean()}.
-
--spec file2tab(fname()) -> {'ok', tab()} | {'error', term()}.
+-spec file2tab(Filename) -> {'ok', Tab} | {'error', Reason} when
+ Filename :: file:name(),
+ Tab :: tab(),
+ Reason :: term().
file2tab(File) ->
file2tab(File, []).
--spec file2tab(fname(), [f2t_option()]) -> {'ok', tab()} | {'error', term()}.
+-spec file2tab(Filename, Options) -> {'ok', Tab} | {'error', Reason} when
+ Filename :: file:name(),
+ Tab :: tab(),
+ Options :: [Option],
+ Option :: {'verify', boolean()},
+ Reason :: term().
file2tab(File, Opts) ->
try
@@ -895,7 +929,22 @@ named_table(false) -> [].
%% information
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec tabfile_info(fname()) -> {'ok', [table_info()]} | {'error', term()}.
+-spec tabfile_info(Filename) -> {'ok', TableInfo} | {'error', Reason} when
+ Filename :: file:name(),
+ TableInfo :: [InfoItem],
+ InfoItem :: {'name', atom()}
+ | {'type', Type}
+ | {'protection', Protection}
+ | {'named_table', boolean()}
+ | {'keypos', non_neg_integer()}
+ | {'size', non_neg_integer()}
+ | {'extended_info', [ExtInfo]}
+ | {'version', {Major :: non_neg_integer(),
+ Minor :: non_neg_integer()}},
+ ExtInfo :: 'md5sum' | 'object_count',
+ Type :: 'bag' | 'duplicate_bag' | 'ordered_set' | 'set',
+ Protection :: 'private' | 'protected' | 'public',
+ Reason :: term().
tabfile_info(File) when is_list(File) ; is_atom(File) ->
try
@@ -932,20 +981,22 @@ tabfile_info(File) when is_list(File) ; is_atom(File) ->
{error,ExReason}
end.
--type qlc__query_handle() :: term(). %% XXX: belongs in 'qlc'
-
--type num_objects() :: 'default' | pos_integer().
--type trav_method() :: 'first_next' | 'last_prev'
- | 'select' | {'select', match_specs()}.
--type table_option() :: {'n_objects', num_objects()}
- | {'traverse', trav_method()}.
-
--spec table(tab()) -> qlc__query_handle().
+-spec table(Tab) -> QueryHandle when
+ Tab :: tab(),
+ QueryHandle :: qlc:query_handle().
table(Tab) ->
table(Tab, []).
--spec table(tab(), table_option() | [table_option()]) -> qlc__query_handle().
+-spec table(Tab, Options) -> QueryHandle when
+ Tab :: tab(),
+ QueryHandle :: qlc:query_handle(),
+ Options :: [Option] | Option,
+ Option :: {'n_objects', NObjects}
+ | {'traverse', TraverseMethod},
+ NObjects :: 'default' | pos_integer(),
+ TraverseMethod :: 'first_next' | 'last_prev'
+ | 'select' | {'select', MatchSpec :: match_spec()}.
table(Tab, Opts) ->
case options(Opts, [traverse, n_objects]) of
@@ -1135,7 +1186,8 @@ to_string(X) ->
lists:flatten(io_lib:format("~p", [X])).
%% view a specific table
--spec i(tab()) -> 'ok'.
+-spec i(Tab) -> 'ok' when
+ Tab :: tab().
i(Tab) ->
i(Tab, 40).
diff --git a/lib/stdlib/src/eval_bits.erl b/lib/stdlib/src/eval_bits.erl
index 2cbd6cdae7..f40904df1c 100644
--- a/lib/stdlib/src/eval_bits.erl
+++ b/lib/stdlib/src/eval_bits.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,15 +31,16 @@
%% @type evalfun(). A closure which evaluates an expression given an
%% environment
%%
-%% @type matchfun(). A closure which performs a match given a value, a
-%% pattern and an environment
+%% @type matchfun(). A closure which depending on its first argument
+%% can perform a match (given a value, a pattern and an environment),
+%% lookup a variable in the bindings, or add a new binding
%%
-%% @type field() represents a field in a "bin"
+%% @type field(). Represents a field in a "bin".
%%% Part 1: expression evaluation (binary construction)
%% @spec expr_grp(Fields::[field()], Bindings::bindings(),
-%% EvalFun::evalfun()) ->
+%% EvalFun::evalfun(), term(), term()) ->
%% {value, binary(), bindings()}
%%
%% @doc Returns a tuple with {value,Bin,Bs} where Bin is the binary
@@ -144,7 +145,8 @@ eval_exp_field(Val, Size, Unit, binary, _, _) ->
bin_gen({bin,_,Fs}, Bin, Bs0, BBs0, Mfun, Efun) ->
bin_gen(Fs, Bin, Bs0, BBs0, Mfun, Efun, true).
-bin_gen([F|Fs], Bin, Bs0, BBs0, Mfun, Efun, Flag) ->
+bin_gen([F|Fs], Bin, Bs0, BBs0, Mfun, Efun, Flag)
+ when is_function(Mfun, 2), is_function(Efun, 2) ->
case bin_gen_field(F, Bin, Bs0, BBs0, Mfun, Efun) of
{match,Bs,BBs,Rest} ->
bin_gen(Fs, Rest, Bs, BBs, Mfun, Efun, Flag);
@@ -175,14 +177,14 @@ bin_gen_field({bin_element,Line,VE,Size0,Options0},
{Size1, [Type,{unit,Unit},Sign,Endian]} =
make_bit_type(Line, Size0, Options0),
V = erl_eval:partial_eval(VE),
- match_check_size(Size1, BBs0),
+ match_check_size(Mfun, Size1, BBs0),
{value, Size, _BBs} = Efun(Size1, BBs0),
case catch get_value(Bin, Type, Size, Unit, Sign, Endian) of
{Val,<<_/bitstring>>=Rest} ->
NewV = coerce_to_float(V, Type),
- case catch Mfun(NewV, Val, Bs0) of
+ case catch Mfun(match, {NewV,Val,Bs0}) of
{match,Bs} ->
- BBs = add_bin_binding(NewV, Bs, BBs0),
+ BBs = add_bin_binding(Mfun, NewV, Bs, BBs0),
{match,Bs,BBs,Rest};
_ ->
{nomatch,Rest}
@@ -192,9 +194,9 @@ bin_gen_field({bin_element,Line,VE,Size0,Options0},
end.
%%% Part 3: binary pattern matching
-%% @spec match_bits(Fields::[field()], Bin::binary()
+%% @spec match_bits(Fields::[field()], Bin::binary(),
%% GlobalEnv::bindings(), LocalEnv::bindings(),
-%% MatchFun::matchfun(),EvalFun::evalfun()) ->
+%% MatchFun::matchfun(),EvalFun::evalfun(), term()) ->
%% {match, bindings()}
%% @doc Used to perform matching. If the match succeeds a new
%% environment is returned. If the match have some syntactic or
@@ -205,7 +207,8 @@ bin_gen_field({bin_element,Line,VE,Size0,Options0},
match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun, _) ->
match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun).
-match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun) ->
+match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun)
+ when is_function(Mfun, 2), is_function(Efun, 2) ->
case catch match_bits_1(Fs, Bin, Bs0, BBs, Mfun, Efun) of
{match,Bs} -> {match,Bs};
invalid -> throw(invalid);
@@ -230,12 +233,12 @@ match_field_1({bin_element,Line,VE,Size0,Options0},
make_bit_type(Line, Size0, Options0),
V = erl_eval:partial_eval(VE),
Size2 = erl_eval:partial_eval(Size1),
- match_check_size(Size2, BBs0),
+ match_check_size(Mfun, Size2, BBs0),
{value, Size, _BBs} = Efun(Size2, BBs0),
{Val,Rest} = get_value(Bin, Type, Size, Unit, Sign, Endian),
NewV = coerce_to_float(V, Type),
- {match,Bs} = Mfun(NewV, Val, Bs0),
- BBs = add_bin_binding(NewV, Bs, BBs0),
+ {match,Bs} = Mfun(match, {NewV,Val,Bs0}),
+ BBs = add_bin_binding(Mfun, NewV, Bs, BBs0),
{Bs,BBs,Rest}.
%% Almost identical to the one in sys_pre_expand.
@@ -249,12 +252,12 @@ coerce_to_float({integer,L,I}=E, float) ->
coerce_to_float(E, _Type) ->
E.
-add_bin_binding({var,_,'_'}, _Bs, BBs) ->
+add_bin_binding(_, {var,_,'_'}, _Bs, BBs) ->
BBs;
-add_bin_binding({var,_,Name}, Bs, BBs) ->
- {value,Value} = erl_eval:binding(Name, Bs),
- erl_eval:add_binding(Name, Value, BBs);
-add_bin_binding(_, _Bs, BBs) ->
+add_bin_binding(Mfun, {var,_,Name}, Bs, BBs) ->
+ {value,Value} = Mfun(binding, {Name,Bs}),
+ Mfun(add_binding, {Name,Value,BBs});
+add_bin_binding(_, _, _Bs, BBs) ->
BBs.
get_value(Bin, integer, Size, Unit, Sign, Endian) ->
@@ -327,20 +330,20 @@ make_bit_type(_Line, Size, Type0) -> %Size evaluates to an integer or 'all'
{error,Reason} -> error(Reason)
end.
-match_check_size({var,_,V}, Bs) ->
- case erl_eval:binding(V, Bs) of
+match_check_size(Mfun, {var,_,V}, Bs) ->
+ case Mfun(binding, {V,Bs}) of
{value,_} -> ok;
unbound -> throw(invalid) % or, rather, error({unbound,V})
end;
-match_check_size({atom,_,all}, _Bs) ->
+match_check_size(_, {atom,_,all}, _Bs) ->
ok;
-match_check_size({atom,_,undefined}, _Bs) ->
+match_check_size(_, {atom,_,undefined}, _Bs) ->
ok;
-match_check_size({integer,_,_}, _Bs) ->
+match_check_size(_, {integer,_,_}, _Bs) ->
ok;
-match_check_size({value,_,_}, _Bs) ->
+match_check_size(_, {value,_,_}, _Bs) ->
ok; %From the debugger.
-match_check_size(_, _Bs) ->
+match_check_size(_, _, _Bs) ->
throw(invalid).
%% error(Reason) -> exception thrown
diff --git a/lib/stdlib/src/file_sorter.erl b/lib/stdlib/src/file_sorter.erl
index 2a5b08b581..3f31852afc 100644
--- a/lib/stdlib/src/file_sorter.erl
+++ b/lib/stdlib/src/file_sorter.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -50,12 +50,68 @@
%%% Exported functions
%%%
+-export_type([reason/0]).
+
+-type(file_name() :: file:name()).
+-type(file_names() :: [file:name()]).
+-type(i_command() :: read | close).
+-type(i_reply() :: end_of_input | {end_of_input, value()}
+ | {[object()], infun()} | input_reply()).
+-type(infun() :: fun((i_command()) -> i_reply())).
+-type(input() :: file_names() | infun()).
+-type(input_reply() :: term()).
+-type(o_command() :: {value, value()} | [object()] | close).
+-type(o_reply() :: outfun() | output_reply()).
+-type(object() :: term() | binary()).
+-type(outfun() :: fun((o_command()) -> o_reply())).
+-type(output() :: file_name() | outfun()).
+-type(output_reply() :: term()).
+-type(value() :: term()).
+
+-type(options() :: [option()] | option()).
+-type(option() :: {compressed, boolean()}
+ | {header, header_length()}
+ | {format, format()}
+ | {no_files, no_files()}
+ | {order, order()}
+ | {size, size()}
+ | {tmpdir, tmp_directory()}
+ | {unique, boolean()}).
+-type(format() :: binary_term | term | binary | format_fun()).
+-type(format_fun() :: fun((binary()) -> term())).
+-type(header_length() :: pos_integer()).
+-type(key_pos() :: pos_integer() | [pos_integer()]).
+-type(no_files() :: pos_integer()). % > 1
+-type(order() :: ascending | descending | order_fun()).
+-type(order_fun() :: fun((term(), term()) -> boolean())).
+-type(size() :: non_neg_integer()).
+-type(tmp_directory() :: [] | file:name()).
+
+-type(reason() :: bad_object
+ | {bad_object, file_name()}
+ | {bad_term, file_name()}
+ | {file_error, file_name(),
+ file:posix() | badarg | system_limit}
+ | {premature_eof, file_name()}).
+
+-spec(sort(FileName) -> Reply when
+ FileName :: file_name(),
+ Reply :: ok | {error, reason()} | input_reply() | output_reply()).
sort(FileName) ->
sort([FileName], FileName).
+-spec(sort(Input, Output) -> Reply when
+ Input :: input(),
+ Output :: output(),
+ Reply :: ok | {error, reason()} | input_reply() | output_reply()).
sort(Input, Output) ->
sort(Input, Output, []).
+-spec(sort(Input, Output, Options) -> Reply when
+ Input :: input(),
+ Output :: output(),
+ Options :: options(),
+ Reply :: ok | {error, reason()} | input_reply() | output_reply()).
sort(Input0, Output0, Options) ->
case {is_input(Input0), maybe_output(Output0), options(Options)} of
{{true,Input}, {true,Output}, #opts{}=Opts} ->
@@ -64,12 +120,27 @@ sort(Input0, Output0, Options) ->
badarg(culprit(tuple_to_list(T)), [Input0, Output0, Options])
end.
+-spec(keysort(KeyPos, FileName) -> Reply when
+ KeyPos :: key_pos(),
+ FileName :: file_name(),
+ Reply :: ok | {error, reason()} | input_reply() | output_reply()).
keysort(KeyPos, FileName) ->
keysort(KeyPos, [FileName], FileName).
+-spec(keysort(KeyPos, Input, Output) -> Reply when
+ KeyPos :: key_pos(),
+ Input :: input(),
+ Output :: output(),
+ Reply :: ok | {error, reason()} | input_reply() | output_reply()).
keysort(KeyPos, Input, Output) ->
keysort(KeyPos, Input, Output, []).
+-spec(keysort(KeyPos, Input, Output, Options) -> Reply when
+ KeyPos :: key_pos(),
+ Input :: input(),
+ Output :: output(),
+ Options :: options(),
+ Reply :: ok | {error, reason()} | input_reply() | output_reply()).
keysort(KeyPos, Input0, Output0, Options) ->
R = case {is_keypos(KeyPos), is_input(Input0),
maybe_output(Output0), options(Options)} of
@@ -89,9 +160,18 @@ keysort(KeyPos, Input0, Output0, Options) ->
badarg(culprit(O), [KeyPos, Input0, Output0, Options])
end.
+-spec(merge(FileNames, Output) -> Reply when
+ FileNames :: file_names(),
+ Output :: output(),
+ Reply :: ok | {error, reason()} | output_reply()).
merge(Files, Output) ->
merge(Files, Output, []).
+-spec(merge(FileNames, Output, Options) -> Reply when
+ FileNames :: file_names(),
+ Output :: output(),
+ Options :: options(),
+ Reply :: ok | {error, reason()} | output_reply()).
merge(Files0, Output0, Options) ->
case {is_files(Files0), maybe_output(Output0), options(Options)} of
%% size not used
@@ -101,9 +181,20 @@ merge(Files0, Output0, Options) ->
badarg(culprit(tuple_to_list(T)), [Files0, Output0, Options])
end.
+-spec(keymerge(KeyPos, FileNames, Output) -> Reply when
+ KeyPos :: key_pos(),
+ FileNames :: file_names(),
+ Output :: output(),
+ Reply :: ok | {error, reason()} | output_reply()).
keymerge(KeyPos, Files, Output) ->
keymerge(KeyPos, Files, Output, []).
+-spec(keymerge(KeyPos, FileNames, Output, Options) -> Reply when
+ KeyPos :: key_pos(),
+ FileNames :: file_names(),
+ Output :: output(),
+ Options :: options(),
+ Reply :: ok | {error, reason()} | output_reply()).
keymerge(KeyPos, Files0, Output0, Options) ->
R = case {is_keypos(KeyPos), is_files(Files0),
maybe_output(Output0), options(Options)} of
@@ -123,9 +214,21 @@ keymerge(KeyPos, Files0, Output0, Options) ->
badarg(culprit(O), [KeyPos, Files0, Output0, Options])
end.
+-spec(check(FileName) -> Reply when
+ FileName :: file_name(),
+ Reply :: {ok, [Result]} | {error, reason()},
+ Result :: {FileName, TermPosition, term()},
+ TermPosition :: pos_integer()).
check(FileName) ->
check([FileName], []).
+-spec(check(FileNames, Options) -> Reply when
+ FileNames :: file_names(),
+ Options :: options(),
+ Reply :: {ok, [Result]} | {error, reason()},
+ Result :: {FileName, TermPosition, term()},
+ FileName :: file_name(),
+ TermPosition :: pos_integer()).
check(Files0, Options) ->
case {is_files(Files0), options(Options)} of
{{true,Files}, #opts{}=Opts} ->
@@ -134,9 +237,23 @@ check(Files0, Options) ->
badarg(culprit(tuple_to_list(T)), [Files0, Options])
end.
+-spec(keycheck(KeyPos, FileName) -> Reply when
+ KeyPos :: key_pos(),
+ FileName :: file_name(),
+ Reply :: {ok, [Result]} | {error, reason()},
+ Result :: {FileName, TermPosition, term()},
+ TermPosition :: pos_integer()).
keycheck(KeyPos, FileName) ->
keycheck(KeyPos, [FileName], []).
+-spec(keycheck(KeyPos, FileNames, Options) -> Reply when
+ KeyPos :: key_pos(),
+ FileNames :: file_names(),
+ Options :: options(),
+ Reply :: {ok, [Result]} | {error, reason()},
+ Result :: {FileName, TermPosition, term()},
+ FileName :: file_name(),
+ TermPosition :: pos_integer()).
keycheck(KeyPos, Files0, Options) ->
R = case {is_keypos(KeyPos), is_files(Files0), options(Options)} of
{_, _, #opts{format = binary}} ->
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl
index c845b61204..d532cea187 100644
--- a/lib/stdlib/src/filelib.erl
+++ b/lib/stdlib/src/filelib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -40,13 +40,19 @@
erlang:error(UnUsUalVaRiAbLeNaMe)
end).
+-type filename() :: file:name().
+-type dirname() :: filename().
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec wildcard(file:name()) -> [file:filename()].
+-spec wildcard(Wildcard) -> [file:filename()] when
+ Wildcard :: filename() | dirname().
wildcard(Pattern) when is_list(Pattern) ->
?HANDLE_ERROR(do_wildcard(Pattern, file)).
--spec wildcard(file:name(), file:name() | atom()) -> [file:filename()].
+-spec wildcard(Wildcard, Cwd) -> [file:filename()] when
+ Wildcard :: filename() | dirname(),
+ Cwd :: dirname().
wildcard(Pattern, Cwd) when is_list(Pattern), (is_list(Cwd) or is_binary(Cwd)) ->
?HANDLE_ERROR(do_wildcard(Pattern, Cwd, file));
wildcard(Pattern, Mod) when is_list(Pattern), is_atom(Mod) ->
@@ -57,7 +63,8 @@ wildcard(Pattern, Cwd, Mod)
when is_list(Pattern), (is_list(Cwd) or is_binary(Cwd)), is_atom(Mod) ->
?HANDLE_ERROR(do_wildcard(Pattern, Cwd, Mod)).
--spec is_dir(file:name()) -> boolean().
+-spec is_dir(Name) -> boolean() when
+ Name :: filename() | dirname().
is_dir(Dir) ->
do_is_dir(Dir, file).
@@ -65,7 +72,8 @@ is_dir(Dir) ->
is_dir(Dir, Mod) when is_atom(Mod) ->
do_is_dir(Dir, Mod).
--spec is_file(file:name()) -> boolean().
+-spec is_file(Name) -> boolean() when
+ Name :: filename() | dirname().
is_file(File) ->
do_is_file(File, file).
@@ -73,7 +81,8 @@ is_file(File) ->
is_file(File, Mod) when is_atom(Mod) ->
do_is_file(File, Mod).
--spec is_regular(file:name()) -> boolean().
+-spec is_regular(Name) -> boolean() when
+ Name :: filename().
is_regular(File) ->
do_is_regular(File, file).
@@ -81,7 +90,13 @@ is_regular(File) ->
is_regular(File, Mod) when is_atom(Mod) ->
do_is_regular(File, Mod).
--spec fold_files(file:name(), string(), boolean(), fun((_,_) -> _), _) -> _.
+-spec fold_files(Dir, RegExp, Recursive, Fun, AccIn) -> AccOut when
+ Dir :: dirname(),
+ RegExp :: string(),
+ Recursive :: boolean(),
+ Fun :: fun((F :: file:filename(), AccIn) -> AccOut),
+ AccIn :: term(),
+ AccOut :: term().
fold_files(Dir, RegExp, Recursive, Fun, Acc) ->
do_fold_files(Dir, RegExp, Recursive, Fun, Acc, file).
@@ -89,7 +104,8 @@ fold_files(Dir, RegExp, Recursive, Fun, Acc) ->
fold_files(Dir, RegExp, Recursive, Fun, Acc, Mod) when is_atom(Mod) ->
do_fold_files(Dir, RegExp, Recursive, Fun, Acc, Mod).
--spec last_modified(file:name()) -> file:date_time() | 0.
+-spec last_modified(Name) -> file:date_time() | 0 when
+ Name :: filename() | dirname().
last_modified(File) ->
do_last_modified(File, file).
@@ -97,7 +113,8 @@ last_modified(File) ->
last_modified(File, Mod) when is_atom(Mod) ->
do_last_modified(File, Mod).
--spec file_size(file:name()) -> non_neg_integer().
+-spec file_size(Filename) -> non_neg_integer() when
+ Filename :: filename().
file_size(File) ->
do_file_size(File, file).
@@ -237,7 +254,9 @@ do_file_size(File, Mod) ->
%% +type X = filename() | dirname()
%% ensures that the directory name required to create D exists
--spec ensure_dir(file:name()) -> 'ok' | {'error', file:posix()}.
+-spec ensure_dir(Name) -> 'ok' | {'error', Reason} when
+ Name :: filename() | dirname(),
+ Reason :: file:posix().
ensure_dir("/") ->
ok;
ensure_dir(F) ->
diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index 24abf1e977..1cb9e4a25e 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -61,12 +61,15 @@
%% (for WIN32): absname("/") -> "D:/"
--spec absname(file:name()) -> file:filename().
+-spec absname(Filename) -> file:filename() when
+ Filename :: file:name().
absname(Name) ->
{ok, Cwd} = file:get_cwd(),
absname(Name, Cwd).
--spec absname(file:name(), file:filename()) -> file:filename().
+-spec absname(Filename, Dir) -> file:filename() when
+ Filename :: file:name(),
+ Dir :: file:filename().
absname(Name, AbsBase) when is_binary(Name), is_list(AbsBase) ->
absname(Name,filename_string_to_binary(AbsBase));
absname(Name, AbsBase) when is_list(Name), is_binary(AbsBase) ->
@@ -119,7 +122,9 @@ absname_vr([[X, $:]|Name], _, _AbsBase) ->
%% This is just a join/2, but assumes that
%% AbsBase must be absolute and Name must be relative.
--spec absname_join(file:filename(), file:name()) -> file:filename().
+-spec absname_join(Dir, Filename) -> file:filename() when
+ Dir :: file:filename(),
+ Filename :: file:name().
absname_join(AbsBase, Name) ->
join(AbsBase, flatten(Name)).
@@ -131,7 +136,8 @@ absname_join(AbsBase, Name) ->
%% basename("/usr/foo/") -> "foo" (trailing slashes ignored)
%% basename("/") -> []
--spec basename(file:name()) -> file:filename().
+-spec basename(Filename) -> file:filename() when
+ Filename :: file:name().
basename(Name) when is_binary(Name) ->
case os:type() of
{win32,_} ->
@@ -192,7 +198,9 @@ skip_prefix(Name, _) ->
%% rootname(basename("xxx.jam")) -> "xxx"
%% rootname(basename("xxx.erl")) -> "xxx"
--spec basename(file:name(), file:name()) -> file:filename().
+-spec basename(Filename, Ext) -> file:filename() when
+ Filename :: file:name(),
+ Ext :: file:name().
basename(Name, Ext) when is_binary(Name), is_list(Ext) ->
basename(Name,filename_string_to_binary(Ext));
basename(Name, Ext) when is_list(Name), is_binary(Ext) ->
@@ -240,7 +248,8 @@ basename([], _Ext, Tail, _DrvSep2) ->
%% Example: dirname("/usr/src/kalle.erl") -> "/usr/src",
%% dirname("kalle.erl") -> "."
--spec dirname(file:name()) -> file:filename().
+-spec dirname(Filename) -> file:filename() when
+ Filename :: file:name().
dirname(Name) when is_binary(Name) ->
{Dsep,Drivesep} = separators(),
SList = case Dsep of
@@ -332,7 +341,8 @@ dirjoin1([H|T],Acc,Sep) ->
%%
%% On Windows: fn:dirname("\\usr\\src/kalle.erl") -> "/usr/src"
--spec extension(file:name()) -> file:filename().
+-spec extension(Filename) -> file:filename() when
+ Filename :: file:name().
extension(Name) when is_binary(Name) ->
{Dsep,_} = separators(),
SList = case Dsep of
@@ -374,7 +384,8 @@ extension([], Result, _OsType) ->
%% Joins a list of filenames with directory separators.
--spec join([file:filename()]) -> file:filename().
+-spec join(Components) -> file:filename() when
+ Components :: [file:filename()].
join([Name1, Name2|Rest]) ->
join([join(Name1, Name2)|Rest]);
join([Name]) when is_list(Name) ->
@@ -386,7 +397,9 @@ join([Name]) when is_atom(Name) ->
%% Joins two filenames with directory separators.
--spec join(file:filename(), file:filename()) -> file:filename().
+-spec join(Name1, Name2) -> file:filename() when
+ Name1 :: file:filename(),
+ Name2 :: file:filename().
join(Name1, Name2) when is_list(Name1), is_list(Name2) ->
OsType = major_os_type(),
case pathtype(Name2) of
@@ -494,7 +507,8 @@ append(Dir, Name) ->
%% current working volume. (Windows only)
%% Example: a:bar.erl, /temp/foo.erl
--spec pathtype(file:name()) -> 'absolute' | 'relative' | 'volumerelative'.
+-spec pathtype(Path) -> 'absolute' | 'relative' | 'volumerelative' when
+ Path :: file:name().
pathtype(Atom) when is_atom(Atom) ->
pathtype(atom_to_list(Atom));
pathtype(Name) when is_list(Name) or is_binary(Name) ->
@@ -547,7 +561,8 @@ win32_pathtype(_) -> relative.
%% Examples: rootname("/jam.src/kalle") -> "/jam.src/kalle"
%% rootname("/jam.src/foo.erl") -> "/jam.src/foo"
--spec rootname(file:name()) -> file:filename().
+-spec rootname(Filename) -> file:filename() when
+ Filename :: file:name().
rootname(Name) when is_binary(Name) ->
list_to_binary(rootname(binary_to_list(Name))); % No need to handle unicode, . is < 128
rootname(Name0) ->
@@ -576,7 +591,9 @@ rootname([], Root, _Ext, _OsType) ->
%% Examples: rootname("/jam.src/kalle.jam", ".erl") -> "/jam.src/kalle.jam"
%% rootname("/jam.src/foo.erl", ".erl") -> "/jam.src/foo"
--spec rootname(file:name(), file:name()) -> file:filename().
+-spec rootname(Filename, Ext) -> file:filename() when
+ Filename :: file:name(),
+ Ext :: file:name().
rootname(Name, Ext) when is_binary(Name), is_binary(Ext) ->
list_to_binary(rootname(binary_to_list(Name),binary_to_list(Ext)));
rootname(Name, Ext) when is_binary(Name) ->
@@ -602,7 +619,9 @@ rootname2([Char|Rest], Ext, Result) when is_integer(Char) ->
%% split("foo/bar") -> ["foo", "bar"]
%% split("a:\\msdev\\include") -> ["a:/", "msdev", "include"]
--spec split(file:name()) -> [file:filename()].
+-spec split(Filename) -> Components when
+ Filename :: file:name(),
+ Components :: [file:filename()].
split(Name) when is_binary(Name) ->
case os:type() of
{win32, _} -> win32_splitb(Name);
@@ -695,7 +714,8 @@ split([], Comp, Components, OsType) ->
%% will be converted to backslashes. On all platforms, the
%% name will be normalized as done by join/1.
--spec nativename(file:filename()) -> file:filename().
+-spec nativename(Path) -> file:filename() when
+ Path :: file:filename().
nativename(Name0) ->
Name = join([Name0]), %Normalize.
case os:type() of
@@ -747,12 +767,17 @@ separators() ->
%% The paths in the {outdir, Path} and {i, Path} options are guaranteed
%% to be absolute.
--type rule() :: {string(), string()}.
--type ecode() :: 'non_existing' | 'preloaded' | 'interpreted'.
--type option() :: {'i', string()} | {'outdir', string()} | {'d', atom()}.
-
--spec find_src(atom() | string()) ->
- {string(), [option()]} | {'error', {ecode(), atom()}}.
+-spec find_src(Beam) -> {SourceFile, Options}
+ | {error, {ErrorReason, Module}} when
+ Beam :: Module | Filename,
+ Filename :: atom() | string(),
+ Module :: module(),
+ SourceFile :: string(),
+ Options :: [Option],
+ Option :: {'i', Path :: string()}
+ | {'outdir', Path :: string()}
+ | {'d', atom()},
+ ErrorReason :: 'non_existing' | 'preloaded' | 'interpreted'.
find_src(Mod) ->
Default = [{"", ""}, {"ebin", "src"}, {"ebin", "esrc"}],
Rules =
@@ -763,8 +788,18 @@ find_src(Mod) ->
end,
find_src(Mod, Rules).
--spec find_src(atom() | string(), [rule()]) ->
- {string(), [option()]} | {'error', {ecode(), atom()}}.
+-spec find_src(Beam, Rules) -> {SourceFile, Options}
+ | {error, {ErrorReason, Module}} when
+ Beam :: Module | Filename,
+ Filename :: atom() | string(),
+ Rules :: [{BinSuffix :: string(), SourceSuffix :: string()}],
+ Module :: module(),
+ SourceFile :: string(),
+ Options :: [Option],
+ Option :: {'i', Path :: string()}
+ | {'outdir', Path :: string()}
+ | {'d', atom()},
+ ErrorReason :: 'non_existing' | 'preloaded' | 'interpreted'.
find_src(Mod, Rules) when is_atom(Mod) ->
find_src(atom_to_list(Mod), Rules);
find_src(File0, Rules) when is_list(File0) ->
@@ -890,7 +925,8 @@ major_os_type() ->
%% flatten(List)
%% Flatten a list, also accepting atoms.
--spec flatten(file:name()) -> file:filename().
+-spec flatten(Filename) -> file:filename() when
+ Filename :: file:name().
flatten(Bin) when is_binary(Bin) ->
Bin;
flatten(List) ->
diff --git a/lib/stdlib/src/gb_sets.erl b/lib/stdlib/src/gb_sets.erl
index fc5beb28b0..91d21d869c 100644
--- a/lib/stdlib/src/gb_sets.erl
+++ b/lib/stdlib/src/gb_sets.erl
@@ -197,6 +197,7 @@
%% Some types.
-type gb_set_node() :: 'nil' | {term(), _, _}.
+-opaque iter() :: [gb_set_node()].
%% A declaration equivalent to the following is currently hard-coded
%% in erl_types.erl
@@ -205,38 +206,47 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec empty() -> gb_set().
+-spec empty() -> Set when
+ Set :: gb_set().
empty() ->
{0, nil}.
--spec new() -> gb_set().
+-spec new() -> Set when
+ Set :: gb_set().
new() -> empty().
--spec is_empty(gb_set()) -> boolean().
+-spec is_empty(Set) -> boolean() when
+ Set :: gb_set().
is_empty({0, nil}) ->
true;
is_empty(_) ->
false.
--spec size(gb_set()) -> non_neg_integer().
+-spec size(Set) -> non_neg_integer() when
+ Set :: gb_set().
size({Size, _}) ->
Size.
--spec singleton(term()) -> gb_set().
+-spec singleton(Element) -> gb_set() when
+ Element :: term().
singleton(Key) ->
{1, {Key, nil, nil}}.
--spec is_element(term(), gb_set()) -> boolean().
+-spec is_element(Element, Set) -> boolean() when
+ Element :: term(),
+ Set :: gb_set().
is_element(Key, S) ->
is_member(Key, S).
--spec is_member(term(), gb_set()) -> boolean().
+-spec is_member(Element, Set) -> boolean() when
+ Element :: term(),
+ Set :: gb_set().
is_member(Key, {_, T}) ->
is_member_1(Key, T).
@@ -250,7 +260,10 @@ is_member_1(_, {_, _, _}) ->
is_member_1(_, nil) ->
false.
--spec insert(term(), gb_set()) -> gb_set().
+-spec insert(Element, Set1) -> Set2 when
+ Element :: term(),
+ Set1 :: gb_set(),
+ Set2 :: gb_set().
insert(Key, {S, T}) ->
S1 = S + 1,
@@ -306,7 +319,9 @@ count({_, Sm, Bi}) ->
count(nil) ->
{1, 0}.
--spec balance(gb_set()) -> gb_set().
+-spec balance(Set1) -> Set2 when
+ Set1 :: gb_set(),
+ Set2 :: gb_set().
balance({S, T}) ->
{S, balance(T, S)}.
@@ -331,12 +346,18 @@ balance_list_1([Key | L], 1) ->
balance_list_1(L, 0) ->
{nil, L}.
--spec add_element(term(), gb_set()) -> gb_set().
+-spec add_element(Element, Set1) -> Set2 when
+ Element :: term(),
+ Set1 :: gb_set(),
+ Set2 :: gb_set().
add_element(X, S) ->
add(X, S).
--spec add(term(), gb_set()) -> gb_set().
+-spec add(Element, Set1) -> Set2 when
+ Element :: term(),
+ Set1 :: gb_set(),
+ Set2 :: gb_set().
add(X, S) ->
case is_member(X, S) of
@@ -346,23 +367,33 @@ add(X, S) ->
insert(X, S)
end.
--spec from_list([term()]) -> gb_set().
+-spec from_list(List) -> Set when
+ List :: [term()],
+ Set :: gb_set().
from_list(L) ->
from_ordset(ordsets:from_list(L)).
--spec from_ordset([term()]) -> gb_set().
+-spec from_ordset(List) -> Set when
+ List :: [term()],
+ Set :: gb_set().
from_ordset(L) ->
S = length(L),
{S, balance_list(L, S)}.
--spec del_element(term(), gb_set()) -> gb_set().
+-spec del_element(Element, Set1) -> Set2 when
+ Element :: term(),
+ Set1 :: gb_set(),
+ Set2 :: gb_set().
del_element(Key, S) ->
delete_any(Key, S).
--spec delete_any(term(), gb_set()) -> gb_set().
+-spec delete_any(Element, Set1) -> Set2 when
+ Element :: term(),
+ Set1 :: gb_set(),
+ Set2 :: gb_set().
delete_any(Key, S) ->
case is_member(Key, S) of
@@ -372,7 +403,10 @@ delete_any(Key, S) ->
S
end.
--spec delete(term(), gb_set()) -> gb_set().
+-spec delete(Element, Set1) -> Set2 when
+ Element :: term(),
+ Set1 :: gb_set(),
+ Set2 :: gb_set().
delete(Key, {S, T}) ->
{S - 1, delete_1(Key, T)}.
@@ -394,7 +428,10 @@ merge(Smaller, Larger) ->
{Key, Larger1} = take_smallest1(Larger),
{Key, Smaller, Larger1}.
--spec take_smallest(gb_set()) -> {term(), gb_set()}.
+-spec take_smallest(Set1) -> {Element, Set2} when
+ Set1 :: gb_set(),
+ Set2 :: gb_set(),
+ Element :: term().
take_smallest({S, T}) ->
{Key, Larger} = take_smallest1(T),
@@ -406,7 +443,8 @@ take_smallest1({Key, Smaller, Larger}) ->
{Key1, Smaller1} = take_smallest1(Smaller),
{Key1, {Key, Smaller1, Larger}}.
--spec smallest(gb_set()) -> term().
+-spec smallest(Set) -> term() when
+ Set :: gb_set().
smallest({_, T}) ->
smallest_1(T).
@@ -416,7 +454,10 @@ smallest_1({Key, nil, _Larger}) ->
smallest_1({_Key, Smaller, _Larger}) ->
smallest_1(Smaller).
--spec take_largest(gb_set()) -> {term(), gb_set()}.
+-spec take_largest(Set1) -> {Element, Set2} when
+ Set1 :: gb_set(),
+ Set2 :: gb_set(),
+ Element :: term().
take_largest({S, T}) ->
{Key, Smaller} = take_largest1(T),
@@ -428,7 +469,8 @@ take_largest1({Key, Smaller, Larger}) ->
{Key1, Larger1} = take_largest1(Larger),
{Key1, {Key, Smaller, Larger1}}.
--spec largest(gb_set()) -> term().
+-spec largest(Set) -> term() when
+ Set :: gb_set().
largest({_, T}) ->
largest_1(T).
@@ -438,7 +480,9 @@ largest_1({Key, _Smaller, nil}) ->
largest_1({_Key, _Smaller, Larger}) ->
largest_1(Larger).
--spec to_list(gb_set()) -> [term()].
+-spec to_list(Set) -> List when
+ Set :: gb_set(),
+ List :: [term()].
to_list({_, T}) ->
to_list(T, []).
@@ -449,7 +493,9 @@ to_list({Key, Small, Big}, L) ->
to_list(Small, [Key | to_list(Big, L)]);
to_list(nil, L) -> L.
--spec iterator(gb_set()) -> [term()].
+-spec iterator(Set) -> Iter when
+ Set :: gb_set(),
+ Iter :: iter().
iterator({_, T}) ->
iterator(T, []).
@@ -464,7 +510,10 @@ iterator({_, L, _} = T, As) ->
iterator(nil, As) ->
As.
--spec next([term()]) -> {term(), [term()]} | 'none'.
+-spec next(Iter1) -> {Element, Iter2} | 'none' when
+ Iter1 :: iter(),
+ Iter2 :: iter(),
+ Element :: term().
next([{X, _, T} | As]) ->
{X, iterator(T, As)};
@@ -494,7 +543,10 @@ next([]) ->
%% traversing the elements can be devised, but they all have higher
%% overhead.
--spec union(gb_set(), gb_set()) -> gb_set().
+-spec union(Set1, Set2) -> Set3 when
+ Set1 :: gb_set(),
+ Set2 :: gb_set(),
+ Set3 :: gb_set().
union({N1, T1}, {N2, T2}) when N2 < N1 ->
union(to_list_1(T2), N2, T1, N1);
@@ -596,7 +648,9 @@ balance_revlist_1([Key | L], 1) ->
balance_revlist_1(L, 0) ->
{nil, L}.
--spec union([gb_set()]) -> gb_set().
+-spec union(SetList) -> Set when
+ SetList :: [gb_set(),...],
+ Set :: gb_set().
union([S | Ss]) ->
union_list(S, Ss);
@@ -609,7 +663,10 @@ union_list(S, []) -> S.
%% The rest is modelled on the above.
--spec intersection(gb_set(), gb_set()) -> gb_set().
+-spec intersection(Set1, Set2) -> Set3 when
+ Set1 :: gb_set(),
+ Set2 :: gb_set(),
+ Set3 :: gb_set().
intersection({N1, T1}, {N2, T2}) when N2 < N1 ->
intersection(to_list_1(T2), N2, T1, N1);
@@ -657,7 +714,9 @@ intersection_2([], _, As, S) ->
intersection_2(_, [], As, S) ->
{S, balance_revlist(As, S)}.
--spec intersection([gb_set(),...]) -> gb_set().
+-spec intersection(SetList) -> Set when
+ SetList :: [gb_set(),...],
+ Set :: gb_set().
intersection([S | Ss]) ->
intersection_list(S, Ss).
@@ -666,7 +725,9 @@ intersection_list(S, [S1 | Ss]) ->
intersection_list(intersection(S, S1), Ss);
intersection_list(S, []) -> S.
--spec is_disjoint(gb_set(), gb_set()) -> boolean().
+-spec is_disjoint(Set1, Set2) -> boolean() when
+ Set1 :: gb_set(),
+ Set2 :: gb_set().
is_disjoint({N1, T1}, {N2, T2}) when N1 < N2 ->
is_disjoint_1(T1, T2);
@@ -694,12 +755,18 @@ is_disjoint_1(_, nil) ->
%% the sets. Therefore, we always build a new tree, and thus we need to
%% traverse the whole element list of the left operand.
--spec subtract(gb_set(), gb_set()) -> gb_set().
+-spec subtract(Set1, Set2) -> Set3 when
+ Set1 :: gb_set(),
+ Set2 :: gb_set(),
+ Set3 :: gb_set().
subtract(S1, S2) ->
difference(S1, S2).
--spec difference(gb_set(), gb_set()) -> gb_set().
+-spec difference(Set1, Set2) -> Set3 when
+ Set1 :: gb_set(),
+ Set2 :: gb_set(),
+ Set3 :: gb_set().
difference({N1, T1}, {N2, T2}) ->
difference(to_list_1(T1), N1, T2, N2).
@@ -747,7 +814,9 @@ difference_2(Xs, [], As, S) ->
%% Subset testing is much the same thing as set difference, but
%% without the construction of a new set.
--spec is_subset(gb_set(), gb_set()) -> boolean().
+-spec is_subset(Set1, Set2) -> boolean() when
+ Set1 :: gb_set(),
+ Set2 :: gb_set().
is_subset({N1, T1}, {N2, T2}) ->
is_subset(to_list_1(T1), N1, T2, N2).
@@ -788,18 +857,28 @@ is_subset_2(_, []) ->
%% For compatibility with `sets':
--spec is_set(term()) -> boolean().
+-spec is_set(Term) -> boolean() when
+ Term :: term().
is_set({0, nil}) -> true;
is_set({N, {_, _, _}}) when is_integer(N), N >= 0 -> true;
is_set(_) -> false.
--spec filter(fun((term()) -> boolean()), gb_set()) -> gb_set().
+-spec filter(Pred, Set1) -> Set2 when
+ Pred :: fun((E :: term()) -> boolean()),
+ Set1 :: gb_set(),
+ Set2 :: gb_set().
filter(F, S) ->
from_ordset([X || X <- to_list(S), F(X)]).
--spec fold(fun((term(), term()) -> term()), term(), gb_set()) -> term().
+-spec fold(Function, Acc0, Set) -> Acc1 when
+ Function :: fun((E :: term(), AccIn) -> AccOut),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ Set :: gb_set().
fold(F, A, {_, T}) when is_function(F, 2) ->
fold_1(F, A, T).
diff --git a/lib/stdlib/src/gb_trees.erl b/lib/stdlib/src/gb_trees.erl
index d37786a100..6ad861ff5b 100644
--- a/lib/stdlib/src/gb_trees.erl
+++ b/lib/stdlib/src/gb_trees.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -153,6 +153,7 @@
%% Some types.
-type gb_tree_node() :: 'nil' | {_, _, _, _}.
+-opaque iter() :: [gb_tree_node()].
%% A declaration equivalent to the following is currently hard-coded
%% in erl_types.erl
@@ -166,21 +167,26 @@
empty() ->
{0, nil}.
--spec is_empty(gb_tree()) -> boolean().
+-spec is_empty(Tree) -> boolean() when
+ Tree :: gb_tree().
is_empty({0, nil}) ->
true;
is_empty(_) ->
false.
--spec size(gb_tree()) -> non_neg_integer().
+-spec size(Tree) -> non_neg_integer() when
+ Tree :: gb_tree().
size({Size, _}) when is_integer(Size), Size >= 0 ->
Size.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec lookup(term(), gb_tree()) -> 'none' | {'value', term()}.
+-spec lookup(Key, Tree) -> 'none' | {'value', Val} when
+ Key :: term(),
+ Val :: term(),
+ Tree :: gb_tree().
lookup(Key, {_, T}) ->
lookup_1(Key, T).
@@ -205,7 +211,9 @@ lookup_1(_, nil) ->
%% This is a specialized version of `lookup'.
--spec is_defined(term(), gb_tree()) -> boolean().
+-spec is_defined(Key, Tree) -> boolean() when
+ Key :: term(),
+ Tree :: gb_tree().
is_defined(Key, {_, T}) ->
is_defined_1(Key, T).
@@ -223,7 +231,10 @@ is_defined_1(_, nil) ->
%% This is a specialized version of `lookup'.
--spec get(term(), gb_tree()) -> term().
+-spec get(Key, Tree) -> Val when
+ Key :: term(),
+ Tree :: gb_tree(),
+ Val :: term().
get(Key, {_, T}) ->
get_1(Key, T).
@@ -237,7 +248,11 @@ get_1(_, {_, Value, _, _}) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec update(term(), term(), gb_tree()) -> gb_tree().
+-spec update(Key, Val, Tree1) -> Tree2 when
+ Key :: term(),
+ Val :: term(),
+ Tree1 :: gb_tree(),
+ Tree2 :: gb_tree().
update(Key, Val, {S, T}) ->
T1 = update_1(Key, Val, T),
@@ -254,7 +269,11 @@ update_1(Key, Value, {_, _, Smaller, Bigger}) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec insert(term(), term(), gb_tree()) -> gb_tree().
+-spec insert(Key, Val, Tree1) -> Tree2 when
+ Key :: term(),
+ Val :: term(),
+ Tree1 :: gb_tree(),
+ Tree2 :: gb_tree().
insert(Key, Val, {S, T}) when is_integer(S) ->
S1 = S+1,
@@ -303,7 +322,11 @@ insert_1(Key, _, _, _) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec enter(term(), term(), gb_tree()) -> gb_tree().
+-spec enter(Key, Val, Tree1) -> Tree2 when
+ Key :: term(),
+ Val :: term(),
+ Tree1 :: gb_tree(),
+ Tree2 :: gb_tree().
enter(Key, Val, T) ->
case is_defined(Key, T) of
@@ -326,7 +349,9 @@ count(nil) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec balance(gb_tree()) -> gb_tree().
+-spec balance(Tree1) -> Tree2 when
+ Tree1 :: gb_tree(),
+ Tree2 :: gb_tree().
balance({S, T}) ->
{S, balance(T, S)}.
@@ -351,7 +376,9 @@ balance_list_1([{Key, Val} | L], 1) ->
balance_list_1(L, 0) ->
{nil, L}.
--spec from_orddict([{_,_}]) -> gb_tree().
+-spec from_orddict(List) -> Tree when
+ List :: [{Key :: term(), Val :: term()}],
+ Tree :: gb_tree().
from_orddict(L) ->
S = length(L),
@@ -359,7 +386,10 @@ from_orddict(L) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec delete_any(term(), gb_tree()) -> gb_tree().
+-spec delete_any(Key, Tree1) -> Tree2 when
+ Key :: term(),
+ Tree1 :: gb_tree(),
+ Tree2 :: gb_tree().
delete_any(Key, T) ->
case is_defined(Key, T) of
@@ -371,7 +401,10 @@ delete_any(Key, T) ->
%%% delete. Assumes that key is present.
--spec delete(term(), gb_tree()) -> gb_tree().
+-spec delete(Key, Tree1) -> Tree2 when
+ Key :: term(),
+ Tree1 :: gb_tree(),
+ Tree2 :: gb_tree().
delete(Key, {S, T}) when is_integer(S), S >= 0 ->
{S - 1, delete_1(Key, T)}.
@@ -397,7 +430,11 @@ merge(Smaller, Larger) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec take_smallest(gb_tree()) -> {term(), term(), gb_tree()}.
+-spec take_smallest(Tree1) -> {Key, Val, Tree2} when
+ Tree1 :: gb_tree(),
+ Tree2 :: gb_tree(),
+ Key :: term(),
+ Val :: term().
take_smallest({Size, Tree}) when is_integer(Size), Size >= 0 ->
{Key, Value, Larger} = take_smallest1(Tree),
@@ -409,7 +446,10 @@ take_smallest1({Key, Value, Smaller, Larger}) ->
{Key1, Value1, Smaller1} = take_smallest1(Smaller),
{Key1, Value1, {Key, Value, Smaller1, Larger}}.
--spec smallest(gb_tree()) -> {term(), term()}.
+-spec smallest(Tree) -> {Key, Val} when
+ Tree :: gb_tree(),
+ Key :: term(),
+ Val :: term().
smallest({_, Tree}) ->
smallest_1(Tree).
@@ -419,7 +459,11 @@ smallest_1({Key, Value, nil, _Larger}) ->
smallest_1({_Key, _Value, Smaller, _Larger}) ->
smallest_1(Smaller).
--spec take_largest(gb_tree()) -> {term(), term(), gb_tree()}.
+-spec take_largest(Tree1) -> {Key, Val, Tree2} when
+ Tree1 :: gb_tree(),
+ Tree2 :: gb_tree(),
+ Key :: term(),
+ Val :: term().
take_largest({Size, Tree}) when is_integer(Size), Size >= 0 ->
{Key, Value, Smaller} = take_largest1(Tree),
@@ -431,7 +475,10 @@ take_largest1({Key, Value, Smaller, Larger}) ->
{Key1, Value1, Larger1} = take_largest1(Larger),
{Key1, Value1, {Key, Value, Smaller, Larger1}}.
--spec largest(gb_tree()) -> {term(), term()}.
+-spec largest(Tree) -> {Key, Val} when
+ Tree :: gb_tree(),
+ Key :: term(),
+ Val :: term().
largest({_, Tree}) ->
largest_1(Tree).
@@ -443,7 +490,10 @@ largest_1({_Key, _Value, _Smaller, Larger}) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec to_list(gb_tree()) -> [{term(), term()}].
+-spec to_list(Tree) -> [{Key, Val}] when
+ Tree :: gb_tree(),
+ Key :: term(),
+ Val :: term().
to_list({_, T}) ->
to_list(T, []).
@@ -456,7 +506,9 @@ to_list(nil, L) -> L.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec keys(gb_tree()) -> [term()].
+-spec keys(Tree) -> [Key] when
+ Tree :: gb_tree(),
+ Key :: term().
keys({_, T}) ->
keys(T, []).
@@ -467,7 +519,9 @@ keys(nil, L) -> L.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec values(gb_tree()) -> [term()].
+-spec values(Tree) -> [Val] when
+ Tree :: gb_tree(),
+ Val :: term().
values({_, T}) ->
values(T, []).
@@ -478,7 +532,9 @@ values(nil, L) -> L.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec iterator(gb_tree()) -> [gb_tree_node()].
+-spec iterator(Tree) -> Iter when
+ Tree :: gb_tree(),
+ Iter :: iter().
iterator({_, T}) ->
iterator_1(T).
@@ -496,7 +552,11 @@ iterator({_, _, L, _} = T, As) ->
iterator(nil, As) ->
As.
--spec next([gb_tree_node()]) -> 'none' | {term(), term(), [gb_tree_node()]}.
+-spec next(Iter1) -> 'none' | {Key, Val, Iter2} when
+ Iter1 :: iter(),
+ Iter2 :: iter(),
+ Key :: term(),
+ Val :: term().
next([{X, V, _, T} | As]) ->
{X, V, iterator(T, As)};
@@ -505,7 +565,10 @@ next([]) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec map(fun((term(), term()) -> term()), gb_tree()) -> gb_tree().
+-spec map(Function, Tree1) -> Tree2 when
+ Function :: fun((K :: term(), V1 :: term()) -> V2 :: term()),
+ Tree1 :: gb_tree(),
+ Tree2 :: gb_tree().
map(F, {Size, Tree}) when is_function(F, 2) ->
{Size, map_1(F, Tree)}.
diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl
index 43df6f621d..574146b1cd 100644
--- a/lib/stdlib/src/gen.erl
+++ b/lib/stdlib/src/gen.erl
@@ -29,6 +29,8 @@
-export([init_it/6, init_it/7]).
+-export([format_status_header/2]).
+
-define(default_timeout, 5000).
%%-----------------------------------------------------------------
@@ -315,3 +317,10 @@ debug_options(Opts) ->
{ok, Options} -> sys:debug_options(Options);
_ -> []
end.
+
+format_status_header(TagLine, Pid) when is_pid(Pid) ->
+ lists:concat([TagLine, " ", pid_to_list(Pid)]);
+format_status_header(TagLine, RegName) when is_atom(RegName) ->
+ lists:concat([TagLine, " ", RegName]);
+format_status_header(TagLine, Name) ->
+ {TagLine, Name}.
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index b1e9e3a02f..9879b76391 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -36,14 +36,15 @@
add_handler/3, add_sup_handler/3, delete_handler/3, swap_handler/3,
swap_sup_handler/3, which_handlers/1, call/3, call/4, wake_hib/4]).
--export([behaviour_info/1]).
-
-export([init_it/6,
system_continue/3,
system_terminate/4,
system_code_change/4,
format_status/2]).
+-export_type([handler/0, handler_args/0, add_handler_ret/0,
+ del_handler_ret/0]).
+
-import(error_logger, [error_msg/2]).
-define(reply(X), From ! {element(2,Tag), X}).
@@ -57,14 +58,6 @@
%%% API
%%%=========================================================================
--spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}].
-
-behaviour_info(callbacks) ->
- [{init,1},{handle_event,2},{handle_call,2},{handle_info,2},
- {terminate,2},{code_change,3}];
-behaviour_info(_Other) ->
- undefined.
-
%% gen_event:start(Handler) -> {ok, Pid} | {error, What}
%% gen_event:add_handler(Handler, Mod, Args) -> ok | Other
%% gen_event:notify(Handler, Event) -> ok
@@ -75,45 +68,44 @@ behaviour_info(_Other) ->
%% gen_event:which_handler(Handler) -> [Mod]
%% gen_event:stop(Handler) -> ok
-
-%% handlers must export
-%% Mod:init(Args) -> {ok, State} | Other
-%% Mod:handle_event(Event, State) ->
-%% {ok, State'} | remove_handler | {swap_handler,Args1,State1,Mod2,Args2}
-%% Mod:handle_info(Info, State) ->
-%% {ok, State'} | remove_handler | {swap_handler,Args1,State1,Mod2,Args2}
-%% Mod:handle_call(Query, State) ->
-%% {ok, Reply, State'} | {remove_handler, Reply} |
-%% {swap_handler, Reply, Args1,State1,Mod2,Args2}
-%% Mod:terminate(Args, State) -> Val
-
-
-%% add_handler(H, Mod, Args) -> ok | Other
-%% Mod:init(Args) -> {ok, State} | Other
-
-%% delete_handler(H, Mod, Args) -> Val
-%% Mod:terminate(Args, State) -> Val
-
-%% notify(H, Event)
-%% Mod:handle_event(Event, State) ->
-%% {ok, State1}
-%% remove_handler
-%% Mod:terminate(remove_handler, State) is called
-%% the return value is ignored
-%% {swap_handler, Args1, State1, Mod2, Args2}
-%% State2 = Mod:terminate(Args1, State1) is called
-%% the return value is chained into the new module and
-%% Mod2:init({Args2, State2}) is called
-%% Other
-%% Mod:terminate({error, Other}, State) is called
-%% The return value is ignored
-%% call(H, Mod, Query) -> Val
-%% call(H, Mod, Query, Timeout) -> Val
-%% Mod:handle_call(Query, State) -> as above
+-callback init(InitArgs :: term()) ->
+ {ok, State :: term()} |
+ {ok, State :: term(), hibernate}.
+-callback handle_event(Event :: term(), State :: term()) ->
+ {ok, NewState :: term()} |
+ {ok, NewState :: term(), hibernate} |
+ {swap_handler, Args1 :: term(), NewState :: term(),
+ Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} |
+ remove_handler.
+-callback handle_call(Request :: term(), State :: term()) ->
+ {ok, Reply :: term(), NewState :: term()} |
+ {ok, Reply :: term(), NewState :: term(), hibernate} |
+ {swap_handler, Reply :: term(), Args1 :: term(), NewState :: term(),
+ Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} |
+ {remove_handler, Reply :: term()}.
+-callback handle_info(Info :: term(), State :: term()) ->
+ {ok, NewState :: term()} |
+ {ok, NewState :: term(), hibernate} |
+ {swap_handler, Args1 :: term(), NewState :: term(),
+ Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} |
+ remove_handler.
+-callback terminate(Args :: (term() | {stop, Reason :: term()} |
+ stop | remove_handler |
+ {error, {'EXIT', Reason :: term()}} |
+ {error, term()}),
+ State :: term()) ->
+ term().
+-callback code_change(OldVsn :: (term() | {down, term()}),
+ State :: term(), Extra :: term()) ->
+ {ok, NewState :: term()}.
%%---------------------------------------------------------------------------
--type handler() :: atom() | {atom(), term()}.
+-type handler() :: atom() | {atom(), term()}.
+-type handler_args() :: term().
+-type add_handler_ret() :: ok | term() | {'EXIT',term()}.
+-type del_handler_ret() :: ok | term() | {'EXIT',term()}.
+
-type emgr_name() :: {'local', atom()} | {'global', atom()}.
-type emgr_ref() :: atom() | {atom(), atom()} | {'global', atom()} | pid().
-type start_ret() :: {'ok', pid()} | {'error', term()}.
@@ -660,16 +652,16 @@ report_error(_Handler, {swapped,_,_}, _, _, _) -> ok;
report_error(Handler, Reason, State, LastIn, SName) ->
Reason1 =
case Reason of
- {'EXIT',{undef,[{M,F,A}|MFAs]}} ->
+ {'EXIT',{undef,[{M,F,A,L}|MFAs]}} ->
case code:is_loaded(M) of
false ->
- {'module could not be loaded',[{M,F,A}|MFAs]};
+ {'module could not be loaded',[{M,F,A,L}|MFAs]};
_ ->
case erlang:function_exported(M, F, length(A)) of
true ->
- {undef,[{M,F,A}|MFAs]};
+ {undef,[{M,F,A,L}|MFAs]};
false ->
- {'function not exported',[{M,F,A}|MFAs]}
+ {'function not exported',[{M,F,A,L}|MFAs]}
end
end;
{'EXIT',Why} ->
@@ -724,7 +716,8 @@ get_modules(MSL) ->
%%-----------------------------------------------------------------
format_status(Opt, StatusData) ->
[PDict, SysState, Parent, _Debug, [ServerName, MSL, _Hib]] = StatusData,
- Header = lists:concat(["Status for event handler ", ServerName]),
+ Header = gen:format_status_header("Status for event handler",
+ ServerName),
FmtMSL = [case erlang:function_exported(Mod, format_status, 2) of
true ->
Args = [PDict, State],
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index 7d9960b912..3db8c9f4f2 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -113,8 +113,6 @@
start_timer/2,send_event_after/2,cancel_timer/1,
enter_loop/4, enter_loop/5, enter_loop/6, wake_hib/6]).
--export([behaviour_info/1]).
-
%% Internal exports
-export([init_it/6,
system_continue/3,
@@ -128,13 +126,38 @@
%%% Interface functions.
%%% ---------------------------------------------------
--spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}].
-
-behaviour_info(callbacks) ->
- [{init,1},{handle_event,3},{handle_sync_event,4},{handle_info,3},
- {terminate,3},{code_change,4}];
-behaviour_info(_Other) ->
- undefined.
+-callback init(Args :: term()) ->
+ {ok, StateName :: atom(), StateData :: term()} |
+ {ok, StateName :: atom(), StateData :: term(), timeout() | hibernate} |
+ {stop, Reason :: term()} | ignore.
+-callback handle_event(Event :: term(), StateName :: atom(),
+ StateData :: term()) ->
+ {next_state, NextStateName :: atom(), NewStateData :: term()} |
+ {next_state, NextStateName :: atom(), NewStateData :: term(),
+ timeout() | hibernate} |
+ {stop, Reason :: term(), NewStateData :: term()}.
+-callback handle_sync_event(Event :: term(), From :: {pid(), Tag :: term()},
+ StateName :: atom(), StateData :: term()) ->
+ {reply, Reply :: term(), NextStateName :: atom(), NewStateData :: term()} |
+ {reply, Reply :: term(), NextStateName :: atom(), NewStateData :: term(),
+ timeout() | hibernate} |
+ {next_state, NextStateName :: atom(), NewStateData :: term()} |
+ {next_state, NextStateName :: atom(), NewStateData :: term(),
+ timeout() | hibernate} |
+ {stop, Reason :: term(), Reply :: term(), NewStateData :: term()} |
+ {stop, Reason :: term(), NewStateData :: term()}.
+-callback handle_info(Info :: term(), StateName :: atom(),
+ StateData :: term()) ->
+ {next_state, NextStateName :: atom(), NewStateData :: term()} |
+ {next_state, NextStateName :: atom(), NewStateData :: term(),
+ timeout() | hibernate} |
+ {stop, Reason :: normal | term(), NewStateData :: term()}.
+-callback terminate(Reason :: normal | shutdown | {shutdown, term()}
+ | term(), StateName :: atom(), StateData :: term()) ->
+ term().
+-callback code_change(OldVsn :: term() | {down, term()}, StateName :: atom(),
+ StateData :: term(), Extra :: term()) ->
+ {ok, NextStateName :: atom(), NewStateData :: term()}.
%%% ---------------------------------------------------
%%% Starts a generic state machine.
@@ -561,16 +584,16 @@ terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) ->
error_info(Reason, Name, Msg, StateName, StateData, Debug) ->
Reason1 =
case Reason of
- {undef,[{M,F,A}|MFAs]} ->
+ {undef,[{M,F,A,L}|MFAs]} ->
case code:is_loaded(M) of
false ->
- {'module could not be loaded',[{M,F,A}|MFAs]};
+ {'module could not be loaded',[{M,F,A,L}|MFAs]};
_ ->
case erlang:function_exported(M, F, length(A)) of
true ->
Reason;
false ->
- {'function not exported',[{M,F,A}|MFAs]}
+ {'function not exported',[{M,F,A,L}|MFAs]}
end
end;
_ ->
@@ -614,15 +637,8 @@ get_msg(Msg) -> Msg.
format_status(Opt, StatusData) ->
[PDict, SysState, Parent, Debug, [Name, StateName, StateData, Mod, _Time]] =
StatusData,
- StatusHdr = "Status for state machine",
- Header = if
- is_pid(Name) ->
- lists:concat([StatusHdr, " ", pid_to_list(Name)]);
- is_atom(Name); is_list(Name) ->
- lists:concat([StatusHdr, " ", Name]);
- true ->
- {StatusHdr, Name}
- end,
+ Header = gen:format_status_header("Status for state machine",
+ Name),
Log = sys:get_debug(log, Debug, []),
DefaultStatus = [{data, [{"StateData", StateData}]}],
Specfic =
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index ac81df9cab..dd0ef74f30 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -94,8 +94,6 @@
multi_call/2, multi_call/3, multi_call/4,
enter_loop/3, enter_loop/4, enter_loop/5, wake_hib/5]).
--export([behaviour_info/1]).
-
%% System exports
-export([system_continue/3,
system_terminate/4,
@@ -111,13 +109,32 @@
%%% API
%%%=========================================================================
--spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}].
-
-behaviour_info(callbacks) ->
- [{init,1},{handle_call,3},{handle_cast,2},{handle_info,2},
- {terminate,2},{code_change,3}];
-behaviour_info(_Other) ->
- undefined.
+-callback init(Args :: term()) ->
+ {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} |
+ {stop, Reason :: term()} | ignore.
+-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()},
+ State :: term()) ->
+ {reply, Reply :: term(), NewState :: term()} |
+ {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} |
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), Reply :: term(), NewState :: term()} |
+ {stop, Reason :: term(), NewState :: term()}.
+-callback handle_cast(Request :: term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+-callback handle_info(Info :: timeout() | term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} |
+ term()),
+ State :: term()) ->
+ term().
+-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(),
+ Extra :: term()) ->
+ {ok, NewState :: term()}.
%%% -----------------------------------------------------------------
%%% Starts a generic server.
@@ -729,16 +746,16 @@ error_info(_Reason, application_controller, _Msg, _State, _Debug) ->
error_info(Reason, Name, Msg, State, Debug) ->
Reason1 =
case Reason of
- {undef,[{M,F,A}|MFAs]} ->
+ {undef,[{M,F,A,L}|MFAs]} ->
case code:is_loaded(M) of
false ->
- {'module could not be loaded',[{M,F,A}|MFAs]};
+ {'module could not be loaded',[{M,F,A,L}|MFAs]};
_ ->
case erlang:function_exported(M, F, length(A)) of
true ->
Reason;
false ->
- {'function not exported',[{M,F,A}|MFAs]}
+ {'function not exported',[{M,F,A,L}|MFAs]}
end
end;
_ ->
@@ -840,15 +857,8 @@ name_to_pid(Name) ->
%%-----------------------------------------------------------------
format_status(Opt, StatusData) ->
[PDict, SysState, Parent, Debug, [Name, State, Mod, _Time]] = StatusData,
- StatusHdr = "Status for generic server",
- Header = if
- is_pid(Name) ->
- lists:concat([StatusHdr, " ", pid_to_list(Name)]);
- is_atom(Name); is_list(Name) ->
- lists:concat([StatusHdr, " ", Name]);
- true ->
- {StatusHdr, Name}
- end,
+ Header = gen:format_status_header("Status for generic server",
+ Name),
Log = sys:get_debug(log, Debug, []),
DefaultStatus = [{data, [{"State", State}]}],
Specfic =
diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl
index 6aeb076a0b..9f65bbfa3a 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -41,6 +41,7 @@
-type error_description() :: term(). % Whatever the io-server sends.
-type request_error() :: {'error',error_description()}.
+
%% XXX: Some uses of line() in this file may need to read erl_scan:location()
-type line() :: pos_integer().
@@ -66,12 +67,15 @@ o_request(Io, Request, Func) ->
end.
%% Put chars takes mixed *unicode* list from R13 onwards.
--spec put_chars(iodata()) -> 'ok'.
+-spec put_chars(CharData) -> 'ok' when
+ CharData :: unicode:chardata().
put_chars(Chars) ->
put_chars(default_output(), Chars).
--spec put_chars(device(), iodata()) -> 'ok'.
+-spec put_chars(IoDevice, IoData) -> 'ok' when
+ IoDevice :: device(),
+ IoData :: unicode:chardata().
put_chars(Io, Chars) ->
o_request(Io, {put_chars,unicode,Chars}, put_chars).
@@ -81,7 +85,8 @@ put_chars(Io, Chars) ->
nl() ->
nl(default_output()).
--spec nl(device()) -> 'ok'.
+-spec nl(IoDevice) -> 'ok' when
+ IoDevice :: device().
nl(Io) ->
% o_request(Io, {put_chars,io_lib:nl()}).
@@ -92,7 +97,8 @@ nl(Io) ->
columns() ->
columns(default_output()).
--spec columns(device()) -> {'ok', pos_integer()} | {'error', 'enotsup'}.
+-spec columns(IoDevice) -> {'ok', pos_integer()} | {'error', 'enotsup'} when
+ IoDevice :: device().
columns(Io) ->
case request(Io, {get_geometry,columns}) of
@@ -107,7 +113,8 @@ columns(Io) ->
rows() ->
rows(default_output()).
--spec rows(device()) -> {'ok', pos_integer()} | {'error', 'enotsup'}.
+-spec rows(IoDevice) -> {'ok', pos_integer()} | {'error', 'enotsup'} when
+ IoDevice :: device().
rows(Io) ->
case request(Io,{get_geometry,rows}) of
@@ -117,22 +124,36 @@ rows(Io) ->
{error,enotsup}
end.
--spec get_chars(prompt(), non_neg_integer()) -> iodata() | 'eof'.
+-spec get_chars(Prompt, Count) -> Data | 'eof' when
+ Prompt :: prompt(),
+ Count :: non_neg_integer(),
+ Data :: [unicode:unicode_char()] | unicode:unicode_binary().
get_chars(Prompt, N) ->
get_chars(default_input(), Prompt, N).
--spec get_chars(device(), prompt(), non_neg_integer()) -> iodata() | 'eof'.
+-spec get_chars(IoDevice, Prompt, Count) -> Data | 'eof' | {error, Reason} when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ Count :: non_neg_integer(),
+ Reason :: term(),
+ Data :: [unicode:unicode_char()] | unicode:unicode_binary().
get_chars(Io, Prompt, N) when is_integer(N), N >= 0 ->
request(Io, {get_chars,unicode,Prompt,N}).
--spec get_line(prompt()) -> iodata() | 'eof' | {'error', term()}.
+-spec get_line(Prompt) -> Data | 'eof' | {'error', Reason} when
+ Prompt :: prompt(),
+ Reason :: term(),
+ Data :: [unicode:unicode_char()] | unicode:unicode_binary().
get_line(Prompt) ->
get_line(default_input(), Prompt).
--spec get_line(device(), prompt()) -> iodata() | 'eof' | {'error', term()}.
+-spec get_line(IoDevice, Prompt) -> Data | 'eof' | {'error', term()} when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ Data :: [unicode:unicode_char()] | unicode:unicode_binary().
get_line(Io, Prompt) ->
request(Io, {get_line,unicode,Prompt}).
@@ -156,46 +177,62 @@ get_password(Io) ->
getopts() ->
getopts(default_input()).
--spec getopts(device()) -> [opt_pair()].
+-spec getopts(IoDevice) -> [opt_pair()] when
+ IoDevice :: device().
getopts(Io) ->
request(Io, getopts).
-type setopt() :: 'binary' | 'list' | opt_pair().
--spec setopts([setopt()]) -> 'ok' | {'error', term()}.
+-spec setopts(Opts) -> 'ok' | {'error', Reason} when
+ Opts :: [setopt()],
+ Reason :: term().
setopts(Opts) ->
setopts(default_input(), Opts).
--spec setopts(device(), [setopt()]) -> 'ok' | {'error', term()}.
+-spec setopts(IoDevice, Opts) -> 'ok' | {'error', Reason} when
+ IoDevice :: device(),
+ Opts :: [setopt()],
+ Reason :: term().
setopts(Io, Opts) ->
request(Io, {setopts, Opts}).
%% Writing and reading Erlang terms.
--spec write(term()) -> 'ok'.
+-spec write(Term) -> 'ok' when
+ Term :: term().
write(Term) ->
write(default_output(), Term).
--spec write(device(), term()) -> 'ok'.
+-spec write(IoDevice, Term) -> 'ok' when
+ IoDevice :: device(),
+ Term :: term().
write(Io, Term) ->
o_request(Io, {write,Term}, write).
--spec read(prompt()) ->
- {'ok', term()} | 'eof' | {'error', erl_scan:error_info()}.
+-spec read(Prompt) -> Result when
+ Prompt :: prompt(),
+ Result :: {'ok', Term :: term()}
+ | 'eof'
+ | {'error', ErrorInfo :: erl_scan:error_info()}.
% Read does not use get_until as erl_scan does not work with unicode
% XXX:PaN fixme?
read(Prompt) ->
read(default_input(), Prompt).
--spec read(device(), prompt()) ->
- {'ok', term()} | 'eof' | {'error', erl_scan:error_info()}.
+-spec read(IoDevice, Prompt) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ Result :: {'ok', Term :: term()}
+ | 'eof'
+ | {'error', ErrorInfo :: erl_scan:error_info()}.
read(Io, Prompt) ->
case request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[1]}) of
@@ -211,9 +248,13 @@ read(Io, Prompt) ->
Other
end.
--spec read(device(), prompt(), line()) ->
- {'ok', term(), line()} | {'eof', line()} |
- {'error', erl_scan:error_info(), line()}.
+-spec read(IoDevice, Prompt, StartLine) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ StartLine :: line(),
+ Result :: {'ok', Term :: term(), EndLine :: line()}
+ | {'eof', EndLine :: line()}
+ | {'error', ErrorInfo :: erl_scan:error_info(), ErrorLine :: line()}.
read(Io, Prompt, StartLine) when is_integer(StartLine) ->
case request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[StartLine]}) of
@@ -239,28 +280,40 @@ conv_reason(_, _Reason) -> badarg.
-type format() :: atom() | string() | binary().
--spec fwrite(format()) -> 'ok'.
+-spec fwrite(Format) -> 'ok' when
+ Format :: format().
fwrite(Format) ->
format(Format).
--spec fwrite(format(), [term()]) -> 'ok'.
+-spec fwrite(Format, Data) -> 'ok' when
+ Format :: format(),
+ Data :: [term()].
fwrite(Format, Args) ->
format(Format, Args).
--spec fwrite(device(), format(), [term()]) -> 'ok'.
+-spec fwrite(IoDevice, Format, Data) -> 'ok' when
+ IoDevice :: device(),
+ Format :: format(),
+ Data :: [term()].
fwrite(Io, Format, Args) ->
format(Io, Format, Args).
--spec fread(prompt(), format()) -> {'ok', [term()]} | 'eof' | {'error',term()}.
+-spec fread(Prompt, Format) -> Result when
+ Prompt :: prompt(),
+ Format :: format(),
+ Result :: {'ok', Terms :: [term()]} | 'eof' | {'error', What :: term()}.
fread(Prompt, Format) ->
fread(default_input(), Prompt, Format).
--spec fread(device(), prompt(), format()) ->
- {'ok', [term()]} | 'eof' | {'error',term()}.
+-spec fread(IoDevice, Prompt, Format) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ Format :: format(),
+ Result :: {'ok', Terms :: [term()]} | 'eof' | {'error', What :: term()}.
fread(Io, Prompt, Format) ->
case request(Io, {fread,Prompt,Format}) of
@@ -270,73 +323,104 @@ fread(Io, Prompt, Format) ->
Other
end.
--spec format(format()) -> 'ok'.
+-spec format(Format) -> 'ok' when
+ Format :: format().
format(Format) ->
format(Format, []).
--spec format(format(), [term()]) -> 'ok'.
+-spec format(Format, Data) -> 'ok' when
+ Format :: format(),
+ Data :: [term()].
format(Format, Args) ->
format(default_output(), Format, Args).
--spec format(device(), format(), [term()]) -> 'ok'.
+-spec format(IoDevice, Format, Data) -> 'ok' when
+ IoDevice :: device(),
+ Format :: format(),
+ Data :: [term()].
format(Io, Format, Args) ->
o_request(Io, {format,Format,Args}, format).
%% Scanning Erlang code.
--spec scan_erl_exprs(prompt()) -> erl_scan:tokens_result() | request_error().
+-spec scan_erl_exprs(Prompt) -> Result when
+ Prompt :: prompt(),
+ Result :: erl_scan:tokens_result() | request_error().
scan_erl_exprs(Prompt) ->
scan_erl_exprs(default_input(), Prompt, 1).
--spec scan_erl_exprs(device(), prompt()) -> erl_scan:tokens_result() | request_error().
+-spec scan_erl_exprs(Device, Prompt) -> Result when
+ Device :: device(),
+ Prompt :: prompt(),
+ Result :: erl_scan:tokens_result() | request_error().
scan_erl_exprs(Io, Prompt) ->
scan_erl_exprs(Io, Prompt, 1).
--spec scan_erl_exprs(device(), prompt(), line()) -> erl_scan:tokens_result() | request_error().
+-spec scan_erl_exprs(Device, Prompt, StartLine) -> Result when
+ Device :: device(),
+ Prompt :: prompt(),
+ StartLine :: line(),
+ Result :: erl_scan:tokens_result() | request_error().
scan_erl_exprs(Io, Prompt, Pos0) ->
request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0]}).
--spec scan_erl_form(prompt()) -> erl_scan:tokens_result() | request_error().
+-spec scan_erl_form(Prompt) -> Result when
+ Prompt :: prompt(),
+ Result :: erl_scan:tokens_result() | request_error().
scan_erl_form(Prompt) ->
scan_erl_form(default_input(), Prompt, 1).
--spec scan_erl_form(device(), prompt()) -> erl_scan:tokens_result() | request_error().
+-spec scan_erl_form(IoDevice, Prompt) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ Result :: erl_scan:tokens_result() | request_error().
scan_erl_form(Io, Prompt) ->
scan_erl_form(Io, Prompt, 1).
--spec scan_erl_form(device(), prompt(), line()) -> erl_scan:tokens_result() | request_error().
+-spec scan_erl_form(IoDevice, Prompt, StartLine) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ StartLine :: line(),
+ Result :: erl_scan:tokens_result() | request_error().
scan_erl_form(Io, Prompt, Pos0) ->
request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0]}).
%% Parsing Erlang code.
--type erl_parse_expr_list() :: [_]. %% XXX: should be imported from erl_parse
-
--type parse_ret() :: {'ok', erl_parse_expr_list(), line()}
- | {'eof', line()}
- | {'error', erl_scan:error_info(), line()}
+-type parse_ret() :: {'ok', ExprList :: erl_parse:abstract_expr(), EndLine :: line()}
+ | {'eof', EndLine :: line()}
+ | {'error', ErrorInfo :: erl_scan:error_info(), ErrorLine :: line()}
| request_error().
--spec parse_erl_exprs(prompt()) -> parse_ret().
+-spec parse_erl_exprs(Prompt) -> Result when
+ Prompt :: prompt(),
+ Result :: parse_ret().
parse_erl_exprs(Prompt) ->
parse_erl_exprs(default_input(), Prompt, 1).
--spec parse_erl_exprs(device(), prompt()) -> parse_ret().
+-spec parse_erl_exprs(IoDevice, Prompt) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ Result :: parse_ret().
parse_erl_exprs(Io, Prompt) ->
parse_erl_exprs(Io, Prompt, 1).
--spec parse_erl_exprs(device(), prompt(), line()) -> parse_ret().
+-spec parse_erl_exprs(IoDevice, Prompt, StartLine) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ StartLine :: line(),
+ Result :: parse_ret().
parse_erl_exprs(Io, Prompt, Pos0) ->
case request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0]}) of
@@ -349,24 +433,31 @@ parse_erl_exprs(Io, Prompt, Pos0) ->
Other
end.
--type erl_parse_absform() :: _. %% XXX: should be imported from erl_parse
-
--type parse_form_ret() :: {'ok', erl_parse_absform(), line()}
- | {'eof', line()}
- | {'error', erl_scan:error_info(), line()}
+-type parse_form_ret() :: {'ok', AbsForm :: erl_parse:abstract_form(), EndLine :: line()}
+ | {'eof', EndLine :: line()}
+ | {'error', ErrorInfo :: erl_scan:error_info(), ErrorLine :: line()}
| request_error().
--spec parse_erl_form(prompt()) -> parse_form_ret().
+-spec parse_erl_form(Prompt) -> Result when
+ Prompt :: prompt(),
+ Result :: parse_form_ret().
parse_erl_form(Prompt) ->
parse_erl_form(default_input(), Prompt, 1).
--spec parse_erl_form(device(), prompt()) -> parse_form_ret().
+-spec parse_erl_form(IoDevice, Prompt) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ Result :: parse_form_ret().
parse_erl_form(Io, Prompt) ->
parse_erl_form(Io, Prompt, 1).
--spec parse_erl_form(device(), prompt(), line()) -> parse_form_ret().
+-spec parse_erl_form(IoDevice, Prompt, StartLine) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ StartLine :: line(),
+ Result :: parse_form_ret().
parse_erl_form(Io, Prompt, Pos0) ->
case request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0]}) of
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 4ca9d079b7..0252cdf742 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -75,35 +75,57 @@
collect_line/2, collect_line/3, collect_line/4,
get_until/3, get_until/4]).
--export_type([chars/0]).
+-export_type([chars/0, continuation/0]).
%%----------------------------------------------------------------------
- %% XXX: overapproximates a deep list of (unicode) characters
--type chars() :: [_].
+-type chars() :: [char() | chars()].
-type depth() :: -1 | non_neg_integer().
+-opaque continuation() :: {_, _, _, _}. % XXX: refine
+
%%----------------------------------------------------------------------
%% Interface calls to sub-modules.
--spec fwrite(io:format(), [term()]) -> chars().
+-spec fwrite(Format, Data) -> chars() | UnicodeList when
+ Format :: io:format(),
+ Data :: [term()],
+ UnicodeList :: [unicode:unicode_char()],
+ Data :: [term()].
fwrite(Format, Args) ->
format(Format, Args).
--spec fread(string(), string()) -> io_lib_fread:fread_2_ret().
+-spec fread(Format, String) -> Result when
+ Format :: string(),
+ String :: string(),
+ Result :: {'ok', InputList :: [term()], LeftOverChars :: string()}
+ | {'more', RestFormat :: string(),
+ Nchars :: non_neg_integer(),
+ InputStack :: chars()}
+ | {'error', What :: term()}.
fread(Chars, Format) ->
io_lib_fread:fread(Chars, Format).
--spec fread(io_lib_fread:continuation(), string(), string()) ->
- io_lib_fread:fread_3_ret().
+-spec fread(Continuation, CharSpec, Format) -> Return when
+ Continuation :: continuation() | [],
+ CharSpec :: string() | eof,
+ Format :: string(),
+ Return :: {'more', Continuation1 :: continuation()}
+ | {'done', Result, LeftOverChars :: string()},
+ Result :: {'ok', InputList :: [term()]}
+ | 'eof'
+ | {'error', What :: term()}.
fread(Cont, Chars, Format) ->
io_lib_fread:fread(Cont, Chars, Format).
--spec format(io:format(), [term()]) -> chars().
+-spec format(Format, Data) -> chars() | UnicodeList when
+ Format :: io:format(),
+ Data :: [term()],
+ UnicodeList :: [unicode:unicode_char()].
format(Format, Args) ->
case catch io_lib_format:fwrite(Format, Args) of
@@ -113,17 +135,24 @@ format(Format, Args) ->
Other
end.
--spec print(term()) -> chars().
+-spec print(Term) -> chars() when
+ Term :: term().
print(Term) ->
io_lib_pretty:print(Term).
--spec print(term(), non_neg_integer(), non_neg_integer(), depth()) -> chars().
+-spec print(Term, Column, LineLength, Depth) -> chars() when
+ Term :: term(),
+ Column :: non_neg_integer(),
+ LineLength :: non_neg_integer(),
+ Depth :: depth().
print(Term, Column, LineLength, Depth) ->
io_lib_pretty:print(Term, Column, LineLength, Depth).
--spec indentation(string(), integer()) -> integer().
+-spec indentation(String, StartIndent) -> integer() when
+ String :: string(),
+ StartIndent :: integer().
indentation(Chars, Current) ->
io_lib_format:indentation(Chars, Current).
@@ -158,7 +187,8 @@ format_prompt(Format, Args) ->
%% Return a (non-flattened) list of characters giving a printed
%% representation of the term. write/3 is for backward compatibility.
--spec write(term()) -> chars().
+-spec write(Term) -> chars() when
+ Term :: term().
write(Term) -> write(Term, -1).
@@ -169,7 +199,9 @@ write(Term, D, true) ->
write(Term, D, false) ->
write(Term, D).
--spec write(term(), depth()) -> chars().
+-spec write(Term, Depth) -> chars() when
+ Term :: term(),
+ Depth :: depth().
write(_Term, 0) -> "...";
write(Term, _D) when is_integer(Term) -> integer_to_list(Term);
@@ -234,7 +266,8 @@ write_binary_body(B, _D) ->
%% write_atom(Atom) -> [Char]
%% Generate the list of characters needed to print an atom.
--spec write_atom(atom()) -> chars().
+-spec write_atom(Atom) -> chars() when
+ Atom :: atom().
write_atom(Atom) ->
Chars = atom_to_list(Atom),
@@ -283,7 +316,8 @@ name_char(_) -> false.
%% write_string([Char]) -> [Char]
%% Generate the list of characters needed to print a string.
--spec write_string(string()) -> chars().
+-spec write_string(String) -> chars() when
+ String :: string().
write_string(S) ->
write_string(S, $"). %"
@@ -330,7 +364,8 @@ string_char(_,C, _, Tail) when C < $\240-> %Other control characters.
%% Generate the list of characters needed to print a character constant.
%% Must special case SPACE, $\s, here.
--spec write_char(char()) -> chars().
+-spec write_char(Char) -> chars() when
+ Char :: char().
write_char($\s) -> "$\\s"; %Must special case this.
write_char(C) when is_integer(C), C >= $\000, C =< $\377 ->
@@ -346,7 +381,8 @@ write_unicode_char(Uni) ->
%% Return true if CharList is a (possibly deep) list of characters, else
%% false.
--spec char_list(term()) -> boolean().
+-spec char_list(Term) -> boolean() when
+ Term :: term().
char_list([C|Cs]) when is_integer(C), C >= $\000, C =< $\377 ->
char_list(Cs);
@@ -362,7 +398,8 @@ unicode_char_list([C|Cs]) when is_integer(C), C >= 0, C < 16#D800;
unicode_char_list([]) -> true;
unicode_char_list(_) -> false. %Everything else is false
--spec deep_char_list(term()) -> boolean().
+-spec deep_char_list(Term) -> boolean() when
+ Term :: term().
deep_char_list(Cs) ->
deep_char_list(Cs, []).
@@ -399,7 +436,8 @@ deep_unicode_char_list(_, _More) -> %Everything else is false
%% Return true if CharList is a list of printable characters, else
%% false.
--spec printable_list(term()) -> boolean().
+-spec printable_list(Term) -> boolean() when
+ Term :: term().
printable_list([C|Cs]) when is_integer(C), C >= $\040, C =< $\176 ->
printable_list(Cs);
diff --git a/lib/stdlib/src/io_lib_fread.erl b/lib/stdlib/src/io_lib_fread.erl
index 33553692bc..ded1346097 100644
--- a/lib/stdlib/src/io_lib_fread.erl
+++ b/lib/stdlib/src/io_lib_fread.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,27 +22,11 @@
-export([fread/2,fread/3]).
--export_type([continuation/0, fread_2_ret/0, fread_3_ret/0]).
-
-import(lists, [reverse/1,reverse/2]).
-%%-----------------------------------------------------------------------
-%% Local types
-%%-----------------------------------------------------------------------
-
--type done_arg2() :: {'ok', io_lib:chars()} | 'eof' | {'error', term()}.
-
-%%-----------------------------------------------------------------------
-%% Types also used in other files
-%%-----------------------------------------------------------------------
-
--type continuation() :: [] | {_, _, _, _}. % XXX: refine
-
--type fread_2_ret() :: {'ok', io_lib:chars(), string()}
- | {'more', string(), non_neg_integer(), io_lib:chars()}
- | {'error', term()}.
--type fread_3_ret() :: {'more', continuation()}
- | {'done', done_arg2(), string()}.
+-define(is_whitespace(C),
+ ((C) =:= $\s orelse (C) =:= $\t
+ orelse (C) =:= $\r orelse (C) =:= $\n)).
%%-----------------------------------------------------------------------
@@ -51,7 +35,15 @@
%% repeatedly collects lines and calls fread/2 to format the input until
%% all the format string has been used. And it counts the characters.
--spec fread(io_lib_fread:continuation(), string(), string()) -> fread_3_ret().
+-spec fread(Continuation, String, Format) -> Return when
+ Continuation :: io_lib:continuation() | [],
+ String :: string(),
+ Format :: string(),
+ Return :: {'more', Continuation1 :: io_lib:continuation()}
+ | {'done', Result, LeftOverChars :: string()},
+ Result :: {'ok', InputList :: io_lib:chars()}
+ | 'eof'
+ | {'error', What :: term()}.
fread([], Chars, Format) ->
%%io:format("FREAD: ~w `~s'~n", [Format,Chars]),
@@ -106,36 +98,39 @@ fread_line(Format0, Line, N0, Results0, More, Newline) ->
%% WHITE Skip white space
%% X Literal X
--spec fread(string(), string()) -> fread_2_ret().
+-spec fread(Format, String) -> Result when
+ Format :: string(),
+ String :: string(),
+ Result :: {'ok', InputList :: io_lib:chars(), LeftOverChars :: string()}
+ | {'more', RestFormat :: string(),
+ Nchars :: non_neg_integer(),
+ InputStack :: io_lib:chars()}
+ | {'error', What :: term()}.
fread(Format, Line) ->
fread(Format, Line, 0, []).
-fread([$~|Format0], Line, N, Results) ->
+fread([$~|Format0]=AllFormat, Line, N, Results) ->
{Format,F,Sup,Unicode} = fread_field(Format0),
- fread1(Format, F, Sup, Unicode, Line, N, Results, Format0);
-fread([$\s|Format], Line, N, Results) ->
- fread_skip_white(Format, Line, N, Results);
-fread([$\t|Format], Line, N, Results) ->
- fread_skip_white(Format, Line, N, Results);
-fread([$\r|Format], Line, N, Results) ->
- fread_skip_white(Format, Line, N, Results);
-fread([$\n|Format], Line, N, Results) ->
+ fread1(Format, F, Sup, Unicode, Line, N, Results, AllFormat);
+fread([C|Format], Line, N, Results) when ?is_whitespace(C) ->
fread_skip_white(Format, Line, N, Results);
fread([C|Format], [C|Line], N, Results) ->
fread(Format, Line, N+1, Results);
fread([_F|_Format], [_C|_Line], _N, _Results) ->
fread_error(input);
+fread([_|_]=Format, [], N, Results) ->
+ {more,Format,N,Results};
+fread([_|_], eof, 0, []) ->
+ %% This is at start of input so no error.
+ eof;
+fread([_|_], eof, _N, _Results) ->
+ %% This is an error as there is no more input.
+ fread_error(input);
fread([], Line, _N, Results) ->
{ok,reverse(Results),Line}.
-fread_skip_white(Format, [$\s|Line], N, Results) ->
- fread_skip_white(Format, Line, N+1, Results);
-fread_skip_white(Format, [$\t|Line], N, Results) ->
- fread_skip_white(Format, Line, N+1, Results);
-fread_skip_white(Format, [$\r|Line], N, Results) ->
- fread_skip_white(Format, Line, N+1, Results);
-fread_skip_white(Format, [$\n|Line], N, Results) ->
+fread_skip_white(Format, [C|Line], N, Results) when ?is_whitespace(C) ->
fread_skip_white(Format, Line, N+1, Results);
fread_skip_white(Format, Line, N, Results) ->
fread(Format, Line, N, Results).
@@ -171,9 +166,9 @@ fread1([$l|Format], _F, Sup, _U, Line, N, Res, _AllFormat) ->
fread(Format, Line, N, fread_result(Sup, N, Res));
fread1(_Format, _F, _Sup, _U, [], N, Res, AllFormat) ->
%% Need more input here.
- {more,[$~|AllFormat],N,Res};
-fread1(_Format, _F, _Sup, _U, eof, _N, [], _AllFormat) ->
- %% This is at start of format string so no error.
+ {more,AllFormat,N,Res};
+fread1(_Format, _F, _Sup, _U, eof, 0, [], _AllFormat) ->
+ %% This is at start of input so no error.
eof;
fread1(_Format, _F, _Sup, _U, eof, _N, _Res, _AllFormat) ->
%% This is an error as there is no more input.
@@ -391,26 +386,16 @@ fread_string_cs(Line0, N0, true) ->
%% fread_digits(Line, N, Base, Characters)
%% Read segments of things, return "thing" characters in reverse order.
-fread_skip_white([$\s|Line]) -> fread_skip_white(Line);
-fread_skip_white([$\t|Line]) -> fread_skip_white(Line);
-fread_skip_white([$\r|Line]) -> fread_skip_white(Line);
-fread_skip_white([$\n|Line]) -> fread_skip_white(Line);
+fread_skip_white([C|Line]) when ?is_whitespace(C) ->
+ fread_skip_white(Line);
fread_skip_white(Line) -> Line.
-fread_skip_white([$\s|Line], N) ->
- fread_skip_white(Line, N+1);
-fread_skip_white([$\t|Line], N) ->
- fread_skip_white(Line, N+1);
-fread_skip_white([$\r|Line], N) ->
- fread_skip_white(Line, N+1);
-fread_skip_white([$\n|Line], N) ->
+fread_skip_white([C|Line], N) when ?is_whitespace(C) ->
fread_skip_white(Line, N+1);
fread_skip_white(Line, N) -> {Line,N}.
-fread_skip_latin1_nonwhite([$\s|Line], N, Cs) -> {[$\s|Line],N,Cs};
-fread_skip_latin1_nonwhite([$\t|Line], N, Cs) -> {[$\t|Line],N,Cs};
-fread_skip_latin1_nonwhite([$\r|Line], N, Cs) -> {[$\r|Line],N,Cs};
-fread_skip_latin1_nonwhite([$\n|Line], N, Cs) -> {[$\n|Line],N,Cs};
+fread_skip_latin1_nonwhite([C|Line], N, Cs) when ?is_whitespace(C) ->
+ {[C|Line],N,Cs};
fread_skip_latin1_nonwhite([C|Line], N, []) when C > 255 ->
{[C|Line],N,error};
fread_skip_latin1_nonwhite([C|Line], N, Cs) when C > 255 ->
@@ -419,10 +404,8 @@ fread_skip_latin1_nonwhite([C|Line], N, Cs) ->
fread_skip_latin1_nonwhite(Line, N+1, [C|Cs]);
fread_skip_latin1_nonwhite([], N, Cs) -> {[],N,Cs}.
-fread_skip_nonwhite([$\s|Line], N, Cs) -> {[$\s|Line],N,Cs};
-fread_skip_nonwhite([$\t|Line], N, Cs) -> {[$\t|Line],N,Cs};
-fread_skip_nonwhite([$\r|Line], N, Cs) -> {[$\r|Line],N,Cs};
-fread_skip_nonwhite([$\n|Line], N, Cs) -> {[$\n|Line],N,Cs};
+fread_skip_nonwhite([C|Line], N, Cs) when ?is_whitespace(C) ->
+ {[C|Line],N,Cs};
fread_skip_nonwhite([C|Line], N, Cs) ->
fread_skip_nonwhite(Line, N+1, [C|Cs]);
fread_skip_nonwhite([], N, Cs) -> {[],N,Cs}.
diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl
index b2cfb00de9..314fd60903 100644
--- a/lib/stdlib/src/lib.erl
+++ b/lib/stdlib/src/lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -38,7 +38,9 @@ flush_receive() ->
%%
%% Functions for doing standard system format i/o.
%%
--spec error_message(atom() | string() | binary(), [term()]) -> 'ok'.
+-spec error_message(Format, Args) -> 'ok' when
+ Format :: io:format(),
+ Args :: [term()].
error_message(Format, Args) ->
io:format(<<"** ~s **\n">>, [io_lib:format(Format, Args)]).
@@ -55,17 +57,23 @@ progname() ->
no_prog_name
end.
--spec nonl(string()) -> string().
+-spec nonl(String1) -> String2 when
+ String1 :: string(),
+ String2 :: string().
nonl([10]) -> [];
nonl([]) -> [];
nonl([H|T]) -> [H|nonl(T)].
--spec send(pid() | atom() | {atom(), node()}, term()) -> term().
+-spec send(To, Msg) -> Msg when
+ To :: pid() | atom() | {atom(), node()},
+ Msg :: term().
send(To, Msg) -> To ! Msg.
--spec sendw(pid() | atom() | {atom(), node()}, term()) -> term().
+-spec sendw(To, Msg) -> Msg when
+ To :: pid() | atom() | {atom(), node()},
+ Msg :: term().
sendw(To, Msg) ->
To ! {self(), Msg},
@@ -89,7 +97,7 @@ eval_str(Str) when is_list(Str) ->
true ->
case erl_parse:parse_exprs(Toks) of
{ok, Exprs} ->
- case catch erl_eval:exprs(Exprs, []) of
+ case catch erl_eval:exprs(Exprs, erl_eval:new_bindings()) of
{value, Val, _} ->
{ok, Val};
Other ->
@@ -165,12 +173,12 @@ format_fun(Fun) when is_function(Fun) ->
analyze_exception(error, Term, Stack) ->
case {is_stacktrace(Stack), Stack, Term} of
- {true, [{_M,_F,As}=MFA|MFAs], function_clause} when is_list(As) ->
- {Term,[MFA],MFAs};
- {true, [{shell,F,A}], function_clause} when is_integer(A) ->
+ {true, [{_,_,As,_}=MFAL|MFAs], function_clause} when is_list(As) ->
+ {Term,[MFAL],MFAs};
+ {true, [{shell,F,A,_}], function_clause} when is_integer(A) ->
{Term, [{F,A}], []};
- {true, [{_M,_F,_AorAs}=MFA|MFAs], undef} ->
- {Term,[MFA],MFAs};
+ {true, [{_,_,_,_}=MFAL|MFAs], undef} ->
+ {Term,[MFAL],MFAs};
{true, _, _} ->
{Term,[],Stack};
{false, _, _} ->
@@ -186,9 +194,11 @@ analyze_exception(_Class, Term, Stack) ->
is_stacktrace([]) ->
true;
-is_stacktrace([{M,F,A}|Fs]) when is_atom(M), is_atom(F), is_integer(A) ->
+is_stacktrace([{M,F,A,I}|Fs])
+ when is_atom(M), is_atom(F), is_integer(A), is_list(I) ->
is_stacktrace(Fs);
-is_stacktrace([{M,F,As}|Fs]) when is_atom(M), is_atom(F), length(As) >= 0 ->
+is_stacktrace([{M,F,As,I}|Fs])
+ when is_atom(M), is_atom(F), length(As) >= 0, is_list(I) ->
is_stacktrace(Fs);
is_stacktrace(_) ->
false.
@@ -217,9 +227,9 @@ explain_reason(function_clause, error, [{F,A}], _PF, _S) ->
%% Shell commands
FAs = io_lib:fwrite(<<"~w/~w">>, [F, A]),
[<<"no function clause matching call to ">> | FAs];
-explain_reason(function_clause, error=Cl, [{M,F,As}], PF, S) ->
+explain_reason(function_clause, error=Cl, [{M,F,As,Loc}], PF, S) ->
Str = <<"no function clause matching ">>,
- format_errstr_call(Str, Cl, {M,F}, As, PF, S);
+ [format_errstr_call(Str, Cl, {M,F}, As, PF, S),$\s|location(Loc)];
explain_reason(if_clause, error, [], _PF, _S) ->
<<"no true branch found when evaluating an if expression">>;
explain_reason(noproc, error, [], _PF, _S) ->
@@ -234,11 +244,11 @@ explain_reason({try_clause,V}, error=Cl, [], PF, S) ->
%% "there is no try clause with a true guard sequence and a
%% pattern matching..."
format_value(V, <<"no try clause matching ">>, Cl, PF, S);
-explain_reason(undef, error, [{M,F,A}], _PF, _S) ->
+explain_reason(undef, error, [{M,F,A,_}], _PF, _S) ->
%% Only the arity is displayed, not the arguments, if there are any.
io_lib:fwrite(<<"undefined function ~s">>,
[mfa_to_string(M, F, n_args(A))]);
-explain_reason({shell_undef,F,A}, error, [], _PF, _S) ->
+explain_reason({shell_undef,F,A,_}, error, [], _PF, _S) ->
%% Give nicer reports for undefined shell functions
%% (but not when the user actively calls shell_default:F(...)).
io_lib:fwrite(<<"undefined shell command ~s/~w">>, [F, n_args(A)]);
@@ -284,17 +294,19 @@ argss(I) ->
io_lib:fwrite(<<"~w arguments">>, [I]).
format_stacktrace1(S0, Stack0, PF, SF) ->
- Stack1 = lists:dropwhile(fun({M,F,A}) -> SF(M, F, A)
+ Stack1 = lists:dropwhile(fun({M,F,A,_}) -> SF(M, F, A)
end, lists:reverse(Stack0)),
S = [" " | S0],
Stack = lists:reverse(Stack1),
format_stacktrace2(S, Stack, 1, PF).
-format_stacktrace2(S, [{M,F,A}|Fs], N, PF) when is_integer(A) ->
- [io_lib:fwrite(<<"~s~s ~s">>,
- [sep(N, S), origin(N, M, F, A), mfa_to_string(M, F, A)])
+format_stacktrace2(S, [{M,F,A,L}|Fs], N, PF) when is_integer(A) ->
+ [io_lib:fwrite(<<"~s~s ~s ~s">>,
+ [sep(N, S), origin(N, M, F, A),
+ mfa_to_string(M, F, A),
+ location(L)])
| format_stacktrace2(S, Fs, N + 1, PF)];
-format_stacktrace2(S, [{M,F,As}|Fs], N, PF) when is_list(As) ->
+format_stacktrace2(S, [{M,F,As,_}|Fs], N, PF) when is_list(As) ->
A = length(As),
CalledAs = [S,<<" called as ">>],
C = format_call("", CalledAs, {M,F}, As, PF),
@@ -305,6 +317,16 @@ format_stacktrace2(S, [{M,F,As}|Fs], N, PF) when is_list(As) ->
format_stacktrace2(_S, [], _N, _PF) ->
"".
+location(L) ->
+ File = proplists:get_value(file, L),
+ Line = proplists:get_value(line, L),
+ if
+ File =/= undefined, Line =/= undefined ->
+ io_lib:format("(~s, line ~w)", [File, Line]);
+ true ->
+ ""
+ end.
+
sep(1, S) -> S;
sep(_, S) -> [$\n | S].
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index c669c1f7c1..e73c087753 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -54,13 +54,21 @@
%% append(X, Y) appends lists X and Y
--spec append([T], [T]) -> [T].
+-spec append(List1, List2) -> List3 when
+ List1 :: [T],
+ List2 :: [T],
+ List3 :: [T],
+ T :: term().
append(L1, L2) -> L1 ++ L2.
%% append(L) appends the list of lists L
--spec append([[T]]) -> [T].
+-spec append(ListOfLists) -> List1 when
+ ListOfLists :: [List],
+ List :: [T],
+ List1 :: [T],
+ T :: term().
append([E]) -> E;
append([H|T]) -> H ++ append(T);
@@ -68,13 +76,20 @@ append([]) -> [].
%% subtract(List1, List2) subtract elements in List2 form List1.
--spec subtract([T], [T]) -> [T].
+-spec subtract(List1, List2) -> List3 when
+ List1 :: [T],
+ List2 :: [T],
+ List3 :: [T],
+ T :: term().
subtract(L1, L2) -> L1 -- L2.
%% reverse(L) reverse all elements in the list L. Is now a BIF!
--spec reverse([T]) -> [T].
+-spec reverse(List1) -> List2 when
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
reverse([] = L) ->
L;
@@ -93,13 +108,21 @@ reverse([A, B | L]) ->
%% nth(N, L) returns the N`th element of the list L
%% nthtail(N, L) returns the N`th tail of the list L
--spec nth(pos_integer(), [T,...]) -> T.
+-spec nth(N, List) -> Elem when
+ N :: pos_integer(),
+ List :: [T,...],
+ Elem :: T,
+ T :: term().
nth(1, [H|_]) -> H;
nth(N, [_|T]) when N > 1 ->
nth(N - 1, T).
--spec nthtail(non_neg_integer(), [T,...]) -> [T].
+-spec nthtail(N, List) -> Tail when
+ N :: non_neg_integer(),
+ List :: [T,...],
+ Tail :: [T],
+ T :: term().
nthtail(1, [_|T]) -> T;
nthtail(N, [_|T]) when N > 1 ->
@@ -108,7 +131,10 @@ nthtail(0, L) when is_list(L) -> L.
%% prefix(Prefix, List) -> (true | false)
--spec prefix([T], [T]) -> boolean().
+-spec prefix(List1, List2) -> boolean() when
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
prefix([X|PreTail], [X|Tail]) ->
prefix(PreTail, Tail);
@@ -117,7 +143,10 @@ prefix([_|_], List) when is_list(List) -> false.
%% suffix(Suffix, List) -> (true | false)
--spec suffix([T], [T]) -> boolean().
+-spec suffix(List1, List2) -> boolean() when
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
suffix(Suffix, List) ->
Delta = length(List) - length(Suffix),
@@ -125,7 +154,10 @@ suffix(Suffix, List) ->
%% last(List) returns the last element in a list.
--spec last([T,...]) -> T.
+-spec last(List) -> Last when
+ List :: [T,...],
+ Last :: T,
+ T :: term().
last([E|Es]) -> last(E, Es).
@@ -137,7 +169,10 @@ last(E, []) -> E.
%% returns the sequence Min..Max
%% Min <= Max and Min and Max must be integers
--spec seq(integer(), integer()) -> [integer()].
+-spec seq(From, To) -> Seq when
+ From :: integer(),
+ To :: integer(),
+ Seq :: [integer()].
seq(First, Last)
when is_integer(First), is_integer(Last), First-1 =< Last ->
@@ -152,7 +187,11 @@ seq_loop(1, X, L) ->
seq_loop(0, _, L) ->
L.
--spec seq(integer(), integer(), integer()) -> [integer()].
+-spec seq(From, To, Incr) -> Seq when
+ From :: integer(),
+ To :: integer(),
+ Incr :: integer(),
+ Seq :: [integer()].
seq(First, Last, Inc)
when is_integer(First), is_integer(Last), is_integer(Inc) ->
@@ -178,7 +217,8 @@ seq_loop(0, _, _, L) ->
%% sum(L) returns the sum of the elements in L
--spec sum([number()]) -> number().
+-spec sum(List) -> number() when
+ List :: [number()].
sum(L) -> sum(L, 0).
@@ -188,7 +228,11 @@ sum([], Sum) -> Sum.
%% duplicate(N, X) -> [X,X,X,.....,X] (N times)
%% return N copies of X
--spec duplicate(non_neg_integer(), T) -> [T].
+-spec duplicate(N, Elem) -> List when
+ N :: non_neg_integer(),
+ Elem :: T,
+ List :: [T],
+ T :: term().
duplicate(N, X) when is_integer(N), N >= 0 -> duplicate(N, X, []).
@@ -197,7 +241,10 @@ duplicate(N, X, L) -> duplicate(N-1, X, [X|L]).
%% min(L) -> returns the minimum element of the list L
--spec min([T,...]) -> T.
+-spec min(List) -> Min when
+ List :: [T,...],
+ Min :: T,
+ T :: term().
min([H|T]) -> min(T, H).
@@ -207,7 +254,10 @@ min([], Min) -> Min.
%% max(L) -> returns the maximum element of the list L
--spec max([T,...]) -> T.
+-spec max(List) -> Max when
+ List :: [T,...],
+ Max :: T,
+ T :: term().
max([H|T]) -> max(T, H).
@@ -218,12 +268,21 @@ max([], Max) -> Max.
%% sublist(List, Start, Length)
%% Returns the sub-list starting at Start of length Length.
--spec sublist([T], pos_integer(), non_neg_integer()) -> [T].
+-spec sublist(List1, Start, Len) -> List2 when
+ List1 :: [T],
+ List2 :: [T],
+ Start :: pos_integer(),
+ Len :: non_neg_integer(),
+ T :: term().
sublist(List, S, L) when is_integer(L), L >= 0 ->
sublist(nthtail(S-1, List), L).
--spec sublist([T], non_neg_integer()) -> [T].
+-spec sublist(List1, Len) -> List2 when
+ List1 :: [T],
+ List2 :: [T],
+ Len :: non_neg_integer(),
+ T :: term().
sublist(List, L) when is_integer(L), is_list(List) ->
sublist_2(List, L).
@@ -238,7 +297,11 @@ sublist_2(List, L) when is_list(List), L > 0 ->
%% delete(Item, List) -> List'
%% Delete the first occurrence of Item from the list L.
--spec delete(T, [T]) -> [T].
+-spec delete(Elem, List1) -> List2 when
+ Elem :: T,
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
delete(Item, [Item|Rest]) -> Rest;
delete(Item, [H|Rest]) ->
@@ -248,7 +311,12 @@ delete(_, []) -> [].
%% Return [{X0, Y0}, {X1, Y1}, ..., {Xn, Yn}] for lists [X0, X1, ...,
%% Xn] and [Y0, Y1, ..., Yn].
--spec zip([A], [B]) -> [{A, B}].
+-spec zip(List1, List2) -> List3 when
+ List1 :: [A],
+ List2 :: [B],
+ List3 :: [{A, B}],
+ A :: term(),
+ B :: term().
zip([X | Xs], [Y | Ys]) -> [{X, Y} | zip(Xs, Ys)];
zip([], []) -> [].
@@ -256,7 +324,12 @@ zip([], []) -> [].
%% Return {[X0, X1, ..., Xn], [Y0, Y1, ..., Yn]}, for a list [{X0, Y0},
%% {X1, Y1}, ..., {Xn, Yn}].
--spec unzip([{A, B}]) -> {[A], [B]}.
+-spec unzip(List1) -> {List2, List3} when
+ List1 :: [{A, B}],
+ List2 :: [A],
+ List3 :: [B],
+ A :: term(),
+ B :: term().
unzip(Ts) -> unzip(Ts, [], []).
@@ -266,7 +339,14 @@ unzip([], Xs, Ys) -> {reverse(Xs), reverse(Ys)}.
%% Return [{X0, Y0, Z0}, {X1, Y1, Z1}, ..., {Xn, Yn, Zn}] for lists [X0,
%% X1, ..., Xn], [Y0, Y1, ..., Yn] and [Z0, Z1, ..., Zn].
--spec zip3([A], [B], [C]) -> [{A, B, C}].
+-spec zip3(List1, List2, List3) -> List4 when
+ List1 :: [A],
+ List2 :: [B],
+ List3 :: [C],
+ List4 :: [{A, B, C}],
+ A :: term(),
+ B :: term(),
+ C :: term().
zip3([X | Xs], [Y | Ys], [Z | Zs]) -> [{X, Y, Z} | zip3(Xs, Ys, Zs)];
zip3([], [], []) -> [].
@@ -274,7 +354,14 @@ zip3([], [], []) -> [].
%% Return {[X0, X1, ..., Xn], [Y0, Y1, ..., Yn], [Z0, Z1, ..., Zn]}, for
%% a list [{X0, Y0, Z0}, {X1, Y1, Z1}, ..., {Xn, Yn, Zn}].
--spec unzip3([{A, B, C}]) -> {[A], [B], [C]}.
+-spec unzip3(List1) -> {List2, List3, List4} when
+ List1 :: [{A, B, C}],
+ List2 :: [A],
+ List3 :: [B],
+ List4 :: [C],
+ A :: term(),
+ B :: term(),
+ C :: term().
unzip3(Ts) -> unzip3(Ts, [], [], []).
@@ -286,7 +373,14 @@ unzip3([], Xs, Ys, Zs) ->
%% Return [F(X0, Y0), F(X1, Y1), ..., F(Xn, Yn)] for lists [X0, X1, ...,
%% Xn] and [Y0, Y1, ..., Yn].
--spec zipwith(fun((X, Y) -> R), [X], [Y]) -> [R].
+-spec zipwith(Combine, List1, List2) -> List3 when
+ Combine :: fun((X, Y) -> T),
+ List1 :: [X],
+ List2 :: [Y],
+ List3 :: [T],
+ X :: term(),
+ Y :: term(),
+ T :: term().
zipwith(F, [X | Xs], [Y | Ys]) -> [F(X, Y) | zipwith(F, Xs, Ys)];
zipwith(F, [], []) when is_function(F, 2) -> [].
@@ -294,7 +388,16 @@ zipwith(F, [], []) when is_function(F, 2) -> [].
%% Return [F(X0, Y0, Z0), F(X1, Y1, Z1), ..., F(Xn, Yn, Zn)] for lists
%% [X0, X1, ..., Xn], [Y0, Y1, ..., Yn] and [Z0, Z1, ..., Zn].
--spec zipwith3(fun((X, Y, Z) -> R), [X], [Y], [Z]) -> [R].
+-spec zipwith3(Combine, List1, List2, List3) -> List4 when
+ Combine :: fun((X, Y, Z) -> T),
+ List1 :: [X],
+ List2 :: [Y],
+ List3 :: [Z],
+ List4 :: [T],
+ X :: term(),
+ Y :: term(),
+ Z :: term(),
+ T :: term().
zipwith3(F, [X | Xs], [Y | Ys], [Z | Zs]) ->
[F(X, Y, Z) | zipwith3(F, Xs, Ys, Zs)];
@@ -303,7 +406,10 @@ zipwith3(F, [], [], []) when is_function(F, 3) -> [].
%% sort(List) -> L
%% sorts the list L
--spec sort([T]) -> [T].
+-spec sort(List1) -> List2 when
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
sort([X, Y | L] = L0) when X =< Y ->
case L of
@@ -350,7 +456,11 @@ sort_1(X, [], R) ->
%% merge(List) -> L
%% merges a list of sorted lists
--spec merge([[T]]) -> [T].
+-spec merge(ListOfLists) -> List1 when
+ ListOfLists :: [List],
+ List :: [T],
+ List1 :: [T],
+ T :: term().
merge(L) ->
mergel(L, []).
@@ -358,7 +468,14 @@ merge(L) ->
%% merge3(X, Y, Z) -> L
%% merges three sorted lists X, Y and Z
--spec merge3([X], [Y], [Z]) -> [(X | Y | Z)].
+-spec merge3(List1, List2, List3) -> List4 when
+ List1 :: [X],
+ List2 :: [Y],
+ List3 :: [Z],
+ List4 :: [(X | Y | Z)],
+ X :: term(),
+ Y :: term(),
+ Z :: term().
merge3(L1, [], L3) ->
merge(L1, L3);
@@ -382,7 +499,12 @@ rmerge3(L1, [H2 | T2], [H3 | T3]) ->
%% merge(X, Y) -> L
%% merges two sorted lists X and Y
--spec merge([X], [Y]) -> [(X | Y)].
+-spec merge(List1, List2) -> List3 when
+ List1 :: [X],
+ List2 :: [Y],
+ List3 :: [(X | Y)],
+ X :: term(),
+ Y :: term().
merge(T1, []) ->
T1;
@@ -405,8 +527,9 @@ rmerge(T1, [H2 | T2]) ->
%% in L - the elements in L can be atoms, numbers of strings.
%% Returns a list of characters.
--type concat_thing() :: atom() | integer() | float() | string().
--spec concat([concat_thing()]) -> string().
+-spec concat(Things) -> string() when
+ Things :: [Thing],
+ Thing :: atom() | integer() | float() | string().
concat(List) ->
flatmap(fun thing_to_list/1, List).
@@ -420,12 +543,17 @@ thing_to_list(X) when is_list(X) -> X. %Assumed to be a string
%% flatten(List, Tail)
%% Flatten a list, adding optional tail.
--spec flatten([term()]) -> [term()].
+-spec flatten(DeepList) -> List when
+ DeepList :: [term() | DeepList],
+ List :: [term()].
flatten(List) when is_list(List) ->
do_flatten(List, []).
--spec flatten([term()], [term()]) -> [term()].
+-spec flatten(DeepList, Tail) -> List when
+ DeepList :: [term() | DeepList],
+ Tail :: [term()],
+ List :: [term()].
flatten(List, Tail) when is_list(List), is_list(Tail) ->
do_flatten(List, Tail).
@@ -440,7 +568,8 @@ do_flatten([], Tail) ->
%% flatlength(List)
%% Calculate the length of a list of lists.
--spec flatlength([term()]) -> non_neg_integer().
+-spec flatlength(DeepList) -> non_neg_integer() when
+ DeepList :: [term() | DeepList].
flatlength(List) ->
flatlength(List, 0).
@@ -481,7 +610,12 @@ flatlength([], L) -> L.
% keysearch3(Key, N, T);
%keysearch3(Key, N, []) -> false.
--spec keydelete(term(), pos_integer(), [T]) -> [T] when T :: tuple().
+-spec keydelete(Key, N, TupleList1) -> TupleList2 when
+ Key :: term(),
+ N :: pos_integer(),
+ TupleList1 :: [Tuple],
+ TupleList2 :: [Tuple],
+ Tuple :: tuple().
keydelete(K, N, L) when is_integer(N), N > 0 ->
keydelete3(K, N, L).
@@ -491,7 +625,13 @@ keydelete3(Key, N, [H|T]) ->
[H|keydelete3(Key, N, T)];
keydelete3(_, _, []) -> [].
--spec keyreplace(term(), pos_integer(), [tuple()], tuple()) -> [tuple()].
+-spec keyreplace(Key, N, TupleList1, NewTuple) -> TupleList2 when
+ Key :: term(),
+ N :: pos_integer(),
+ TupleList1 :: [Tuple],
+ TupleList2 :: [Tuple],
+ NewTuple :: Tuple,
+ Tuple :: tuple().
keyreplace(K, N, L, New) when is_integer(N), N > 0, is_tuple(New) ->
keyreplace3(K, N, L, New).
@@ -502,8 +642,12 @@ keyreplace3(Key, Pos, [H|T], New) ->
[H|keyreplace3(Key, Pos, T, New)];
keyreplace3(_, _, [], _) -> [].
--spec keytake(term(), pos_integer(), [tuple()]) ->
- {'value', tuple(), [tuple()]} | 'false'.
+-spec keytake(Key, N, TupleList1) -> {value, Tuple, TupleList2} | false when
+ Key :: term(),
+ N :: pos_integer(),
+ TupleList1 :: [tuple()],
+ TupleList2 :: [tuple()],
+ Tuple :: tuple().
keytake(Key, N, L) when is_integer(N), N > 0 ->
keytake(Key, N, L, []).
@@ -514,7 +658,13 @@ keytake(Key, N, [H|T], L) ->
keytake(Key, N, T, [H|L]);
keytake(_K, _N, [], _L) -> false.
--spec keystore(term(), pos_integer(), [tuple()], tuple()) -> [tuple(),...].
+-spec keystore(Key, N, TupleList1, NewTuple) -> TupleList2 when
+ Key :: term(),
+ N :: pos_integer(),
+ TupleList1 :: [Tuple],
+ TupleList2 :: [Tuple, ...],
+ NewTuple :: Tuple,
+ Tuple :: tuple().
keystore(K, N, L, New) when is_integer(N), N > 0, is_tuple(New) ->
keystore2(K, N, L, New).
@@ -526,7 +676,11 @@ keystore2(Key, N, [H|T], New) ->
keystore2(_Key, _N, [], New) ->
[New].
--spec keysort(pos_integer(), [T]) -> [T] when T :: tuple().
+-spec keysort(N, TupleList1) -> TupleList2 when
+ N :: pos_integer(),
+ TupleList1 :: [Tuple],
+ TupleList2 :: [Tuple],
+ Tuple :: tuple().
keysort(I, L) when is_integer(I), I > 0 ->
case L of
@@ -583,8 +737,14 @@ keysort_1(I, X, EX, [Y | L], R) ->
keysort_1(_I, X, _EX, [], R) ->
lists:reverse(R, [X]).
--spec keymerge(pos_integer(), [X], [Y]) ->
- [R] when X :: tuple(), Y :: tuple(), R :: tuple().
+-spec keymerge(N, TupleList1, TupleList2) -> TupleList3 when
+ N :: pos_integer(),
+ TupleList1 :: [T1],
+ TupleList2 :: [T2],
+ TupleList3 :: [(T1 | T2)],
+ T1 :: Tuple,
+ T2 :: Tuple,
+ Tuple :: tuple().
keymerge(Index, T1, L2) when is_integer(Index), Index > 0 ->
case L2 of
@@ -611,7 +771,11 @@ rkeymerge(Index, T1, L2) when is_integer(Index), Index > 0 ->
lists:reverse(M, [])
end.
--spec ukeysort(pos_integer(), [T]) -> [T] when T :: tuple().
+-spec ukeysort(N, TupleList1) -> TupleList2 when
+ N :: pos_integer(),
+ TupleList1 :: [Tuple],
+ TupleList2 :: [Tuple],
+ Tuple :: tuple().
ukeysort(I, L) when is_integer(I), I > 0 ->
case L of
@@ -676,8 +840,14 @@ ukeysort_1(I, X, EX, [Y | L]) ->
ukeysort_1(_I, X, _EX, []) ->
[X].
--spec ukeymerge(pos_integer(), [X], [Y]) ->
- [(X | Y)] when X :: tuple(), Y :: tuple().
+-spec ukeymerge(N, TupleList1, TupleList2) -> TupleList3 when
+ N :: pos_integer(),
+ TupleList1 :: [T1],
+ TupleList2 :: [T2],
+ TupleList3 :: [(T1 | T2)],
+ T1 :: Tuple,
+ T2 :: Tuple,
+ Tuple :: tuple().
ukeymerge(Index, L1, T2) when is_integer(Index), Index > 0 ->
case L1 of
@@ -704,7 +874,12 @@ rukeymerge(Index, T1, L2) when is_integer(Index), Index > 0 ->
lists:reverse(M, [])
end.
--spec keymap(fun((term()) -> term()), pos_integer(), [tuple()]) -> [tuple()].
+-spec keymap(Fun, N, TupleList1) -> TupleList2 when
+ Fun :: fun((Term1 :: term()) -> Term2 :: term()),
+ N :: pos_integer(),
+ TupleList1 :: [Tuple],
+ TupleList2 :: [Tuple],
+ Tuple :: tuple().
keymap(Fun, Index, [Tup|Tail]) ->
[setelement(Index, Tup, Fun(element(Index, Tup)))|keymap(Fun, Index, Tail)];
@@ -713,7 +888,11 @@ keymap(Fun, Index, []) when is_integer(Index), Index >= 1,
%%% Suggestion from OTP-2948: sort and merge with Fun.
--spec sort(fun((T, T) -> boolean()), [T]) -> [T].
+-spec sort(Fun, List1) -> List2 when
+ Fun :: fun((A :: T, B :: T) -> boolean()),
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
sort(Fun, []) when is_function(Fun, 2) ->
[];
@@ -727,7 +906,13 @@ sort(Fun, [X, Y | T]) ->
fsplit_2(Y, X, Fun, T, [], [])
end.
--spec merge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)].
+-spec merge(Fun, List1, List2) -> List3 when
+ Fun :: fun((A, B) -> boolean()),
+ List1 :: [A],
+ List2 :: [B],
+ List3 :: [(A | B)],
+ A :: term(),
+ B :: term().
merge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) ->
lists:reverse(fmerge2_1(T1, H2, Fun, T2, []), []);
@@ -743,7 +928,11 @@ rmerge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) ->
rmerge(Fun, T1, []) when is_function(Fun, 2) ->
T1.
--spec usort(fun((T, T) -> boolean()), [T]) -> [T].
+-spec usort(Fun, List1) -> List2 when
+ Fun :: fun((T, T) -> boolean()),
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
usort(Fun, [_] = L) when is_function(Fun, 2) ->
L;
@@ -770,7 +959,13 @@ usort_1(Fun, X, [Y | L]) ->
ufsplit_2(Y, L, Fun, [X])
end.
--spec umerge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)].
+-spec umerge(Fun, List1, List2) -> List3 when
+ Fun :: fun((A, B) -> boolean()),
+ List1 :: [A],
+ List2 :: [B],
+ List3 :: [(A | B)],
+ A :: term(),
+ B :: term().
umerge(Fun, [], T2) when is_function(Fun, 2) ->
T2;
@@ -789,7 +984,10 @@ rumerge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) ->
%% usort(List) -> L
%% sorts the list L, removes duplicates
--spec usort([T]) -> [T].
+-spec usort(List1) -> List2 when
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
usort([X, Y | L] = L0) when X < Y ->
case L of
@@ -844,7 +1042,11 @@ usort_1(X, []) ->
%% umerge(List) -> L
%% merges a list of sorted lists without duplicates, removes duplicates
--spec umerge([[T]]) -> [T].
+-spec umerge(ListOfLists) -> List1 when
+ ListOfLists :: [List],
+ List :: [T],
+ List1 :: [T],
+ T :: term().
umerge(L) ->
umergel(L).
@@ -853,7 +1055,14 @@ umerge(L) ->
%% merges three sorted lists X, Y and Z without duplicates,
%% removes duplicates
--spec umerge3([X], [Y], [Z]) -> [(X | Y | Z)].
+-spec umerge3(List1, List2, List3) -> List4 when
+ List1 :: [X],
+ List2 :: [Y],
+ List3 :: [Z],
+ List4 :: [(X | Y | Z)],
+ X :: term(),
+ Y :: term(),
+ Z :: term().
umerge3(L1, [], L3) ->
umerge(L1, L3);
@@ -878,7 +1087,12 @@ rumerge3(L1, [H2 | T2], [H3 | T3]) ->
%% umerge(X, Y) -> L
%% merges two sorted lists X and Y without duplicates, removes duplicates
--spec umerge([X], [Y]) -> [(X | Y)].
+-spec umerge(List1, List2) -> List3 when
+ List1 :: [X],
+ List2 :: [Y],
+ List3 :: [(X | Y)],
+ X :: term(),
+ Y :: term().
umerge([], T2) ->
T2;
@@ -924,7 +1138,10 @@ rumerge(T1, [H2 | T2]) ->
%% There are also versions with an extra argument, ExtraArgs, which is a
%% list of extra arguments to each call.
--spec all(fun((T) -> boolean()), [T]) -> boolean().
+-spec all(Pred, List) -> boolean() when
+ Pred :: fun((Elem :: T) -> boolean()),
+ List :: [T],
+ T :: term().
all(Pred, [Hd|Tail]) ->
case Pred(Hd) of
@@ -933,7 +1150,10 @@ all(Pred, [Hd|Tail]) ->
end;
all(Pred, []) when is_function(Pred, 1) -> true.
--spec any(fun((T) -> boolean()), [T]) -> boolean().
+-spec any(Pred, List) -> boolean() when
+ Pred :: fun((Elem :: T) -> boolean()),
+ List :: [T],
+ T :: term().
any(Pred, [Hd|Tail]) ->
case Pred(Hd) of
@@ -942,31 +1162,59 @@ any(Pred, [Hd|Tail]) ->
end;
any(Pred, []) when is_function(Pred, 1) -> false.
--spec map(fun((D) -> R), [D]) -> [R].
+-spec map(Fun, List1) -> List2 when
+ Fun :: fun((A) -> B),
+ List1 :: [A],
+ List2 :: [B],
+ A :: term(),
+ B :: term().
map(F, [H|T]) ->
[F(H)|map(F, T)];
map(F, []) when is_function(F, 1) -> [].
--spec flatmap(fun((D) -> [R]), [D]) -> [R].
+-spec flatmap(Fun, List1) -> List2 when
+ Fun :: fun((A) -> [B]),
+ List1 :: [A],
+ List2 :: [B],
+ A :: term(),
+ B :: term().
flatmap(F, [Hd|Tail]) ->
F(Hd) ++ flatmap(F, Tail);
flatmap(F, []) when is_function(F, 1) -> [].
--spec foldl(fun((T, term()) -> term()), term(), [T]) -> term().
+-spec foldl(Fun, Acc0, List) -> Acc1 when
+ Fun :: fun((Elem :: T, AccIn) -> AccOut),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ List :: [T],
+ T :: term().
foldl(F, Accu, [Hd|Tail]) ->
foldl(F, F(Hd, Accu), Tail);
foldl(F, Accu, []) when is_function(F, 2) -> Accu.
--spec foldr(fun((T, term()) -> term()), term(), [T]) -> term().
+-spec foldr(Fun, Acc0, List) -> Acc1 when
+ Fun :: fun((Elem :: T, AccIn) -> AccOut),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ List :: [T],
+ T :: term().
foldr(F, Accu, [Hd|Tail]) ->
F(Hd, foldr(F, Accu, Tail));
foldr(F, Accu, []) when is_function(F, 2) -> Accu.
--spec filter(Pred :: fun((T) -> boolean()), List :: [T]) -> [T].
+-spec filter(Pred, List1) -> List2 when
+ Pred :: fun((Elem :: T) -> boolean()),
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
filter(Pred, List) when is_function(Pred, 1) ->
[ E || E <- List, Pred(E) ].
@@ -974,7 +1222,12 @@ filter(Pred, List) when is_function(Pred, 1) ->
%% Equivalent to {filter(F, L), filter(NotF, L)}, if NotF = 'fun(X) ->
%% not F(X) end'.
--spec partition(Pred :: fun((T) -> boolean()), List :: [T]) -> {[T], [T]}.
+-spec partition(Pred, List) -> {Satisfying, NotSatisfying} when
+ Pred :: fun((Elem :: T) -> boolean()),
+ List :: [T],
+ Satisfying :: [T],
+ NotSatisfying :: [T],
+ T :: term().
partition(Pred, L) ->
partition(Pred, L, [], []).
@@ -1000,14 +1253,26 @@ zf(F, [Hd|Tail]) ->
end;
zf(F, []) when is_function(F, 1) -> [].
--spec foreach(F :: fun((T) -> term()), List :: [T]) -> 'ok'.
+-spec foreach(Fun, List) -> ok when
+ Fun :: fun((Elem :: T) -> term()),
+ List :: [T],
+ T :: term().
foreach(F, [Hd|Tail]) ->
F(Hd),
foreach(F, Tail);
foreach(F, []) when is_function(F, 1) -> ok.
--spec mapfoldl(fun((A, term()) -> {B, term()}), term(), [A]) -> {[B], term()}.
+-spec mapfoldl(Fun, Acc0, List1) -> {List2, Acc1} when
+ Fun :: fun((A, AccIn) -> {B, AccOut}),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ List1 :: [A],
+ List2 :: [B],
+ A :: term(),
+ B :: term().
mapfoldl(F, Accu0, [Hd|Tail]) ->
{R,Accu1} = F(Hd, Accu0),
@@ -1015,7 +1280,16 @@ mapfoldl(F, Accu0, [Hd|Tail]) ->
{[R|Rs],Accu2};
mapfoldl(F, Accu, []) when is_function(F, 2) -> {[],Accu}.
--spec mapfoldr(fun((A, term()) -> {B, term()}), term(), [A]) -> {[B], term()}.
+-spec mapfoldr(Fun, Acc0, List1) -> {List2, Acc1} when
+ Fun :: fun((A, AccIn) -> {B, AccOut}),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ List1 :: [A],
+ List2 :: [B],
+ A :: term(),
+ B :: term().
mapfoldr(F, Accu0, [Hd|Tail]) ->
{Rs,Accu1} = mapfoldr(F, Accu0, Tail),
@@ -1023,7 +1297,11 @@ mapfoldr(F, Accu0, [Hd|Tail]) ->
{[R|Rs],Accu2};
mapfoldr(F, Accu, []) when is_function(F, 2) -> {[],Accu}.
--spec takewhile(fun((T) -> boolean()), [T]) -> [T].
+-spec takewhile(Pred, List1) -> List2 when
+ Pred :: fun((Elem :: T) -> boolean()),
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
takewhile(Pred, [Hd|Tail]) ->
case Pred(Hd) of
@@ -1032,7 +1310,11 @@ takewhile(Pred, [Hd|Tail]) ->
end;
takewhile(Pred, []) when is_function(Pred, 1) -> [].
--spec dropwhile(fun((T) -> boolean()), [T]) -> [T].
+-spec dropwhile(Pred, List1) -> List2 when
+ Pred :: fun((Elem :: T) -> boolean()),
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
dropwhile(Pred, [Hd|Tail]=Rest) ->
case Pred(Hd) of
@@ -1041,7 +1323,12 @@ dropwhile(Pred, [Hd|Tail]=Rest) ->
end;
dropwhile(Pred, []) when is_function(Pred, 1) -> [].
--spec splitwith(fun((T) -> boolean()), [T]) -> {[T], [T]}.
+-spec splitwith(Pred, List) -> {List1, List2} when
+ Pred :: fun((T) -> boolean()),
+ List :: [T],
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
splitwith(Pred, List) when is_function(Pred, 1) ->
splitwith(Pred, List, []).
@@ -1054,7 +1341,12 @@ splitwith(Pred, [Hd|Tail], Taken) ->
splitwith(Pred, [], Taken) when is_function(Pred, 1) ->
{reverse(Taken),[]}.
--spec split(non_neg_integer(), [T]) -> {[T], [T]}.
+-spec split(N, List1) -> {List2, List3} when
+ N :: non_neg_integer(),
+ List1 :: [T],
+ List2 :: [T],
+ List3 :: [T],
+ T :: term().
split(N, List) when is_integer(N), N >= 0, is_list(List) ->
case split(N, List, []) of
diff --git a/lib/stdlib/src/log_mf_h.erl b/lib/stdlib/src/log_mf_h.erl
index 5fa5360fa1..f7f128dac7 100644
--- a/lib/stdlib/src/log_mf_h.erl
+++ b/lib/stdlib/src/log_mf_h.erl
@@ -27,14 +27,13 @@
%%-----------------------------------------------------------------
--type dir() :: file:filename().
-type b() :: non_neg_integer().
-type f() :: 1..255.
-type pred() :: fun((term()) -> boolean()).
%%-----------------------------------------------------------------
--record(state, {dir :: dir(),
+-record(state, {dir :: file:filename(),
maxB :: b(),
maxF :: f(),
curB :: b(),
@@ -67,11 +66,23 @@
%% EventMgr = pid() | atom().
%%-----------------------------------------------------------------
--spec init(dir(), b(), f()) -> {dir(), b(), f(), pred()}.
+-opaque args() :: {file:filename(), b(), f(), pred()}.
+
+
+-spec init(Dir, MaxBytes, MaxFiles) -> Args when
+ Dir :: file:filename(),
+ MaxBytes :: non_neg_integer(), % b()
+ MaxFiles :: 1..255, % f()
+ Args :: args().
init(Dir, MaxB, MaxF) -> init(Dir, MaxB, MaxF, fun(_) -> true end).
--spec init(dir(), b(), f(), pred()) -> {dir(), b(), f(), pred()}.
+-spec init(Dir, MaxBytes, MaxFiles, Pred) -> Args when
+ Dir :: file:filename(),
+ MaxBytes :: non_neg_integer(), % b()
+ MaxFiles :: 1..255, % f()
+ Pred :: fun((Event :: term()) -> boolean()), % pred()
+ Args :: args().
init(Dir, MaxB, MaxF, Pred) -> {Dir, MaxB, MaxF, Pred}.
@@ -79,7 +90,7 @@ init(Dir, MaxB, MaxF, Pred) -> {Dir, MaxB, MaxF, Pred}.
%% Call-back functions from gen_event
%%-----------------------------------------------------------------
--spec init({dir(), b(), f(), pred()}) -> {'ok', #state{}} | {'error', term()}.
+-spec init({file:filename(), non_neg_integer(), f(), pred()}) -> {'ok', #state{}} | {'error', term()}.
init({Dir, MaxB, MaxF, Pred}) when is_integer(MaxF), MaxF > 0, MaxF < 256 ->
First =
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index b565eb20f4..48e22e53fa 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -66,6 +66,11 @@
%%
%% Called by compiler or ets/dbg:fun2ms when errors/warnings occur
%%
+
+-spec(format_error(Error) -> Chars when
+ Error :: {error, module(), term()},
+ Chars :: io_lib:chars()).
+
format_error({?WARN_SHADOW_VAR,Name}) ->
lists:flatten(
io_lib:format("variable ~p shadowed in ms_transform fun head",
@@ -186,6 +191,12 @@ format_error(Else) ->
%%
%% Called when translating in shell
%%
+
+-spec transform_from_shell(Dialect, Clauses, BoundEnvironment) -> term() when
+ Dialect :: ets | dbg,
+ Clauses :: [erl_parse:abstract_clause()],
+ BoundEnvironment :: erl_eval:binding_struct().
+
transform_from_shell(Dialect, Clauses, BoundEnvironment) ->
SaveFilename = setup_filename(),
case catch ms_clause_list(1,Clauses,Dialect,gb_sets:new()) of
@@ -211,6 +222,11 @@ transform_from_shell(Dialect, Clauses, BoundEnvironment) ->
%%
%% Called when translating during compiling
%%
+
+-spec parse_transform(Forms, Options) -> Forms when
+ Forms :: [erl_parse:abstract_form()],
+ Options :: term().
+
parse_transform(Forms, _Options) ->
SaveFilename = setup_filename(),
%io:format("Forms: ~p~n",[Forms]),
diff --git a/lib/stdlib/src/orddict.erl b/lib/stdlib/src/orddict.erl
index 4e30c9eefd..45d3c84b3e 100644
--- a/lib/stdlib/src/orddict.erl
+++ b/lib/stdlib/src/orddict.erl
@@ -25,9 +25,11 @@
-export([store/3,append/3,append_list/3,update/3,update/4,update_counter/3]).
-export([fold/3,map/2,filter/2,merge/3]).
+-export_type([orddict/0]).
+
%%---------------------------------------------------------------------------
--type orddict() :: [{term(), term()}].
+-type orddict() :: [{Key :: term(), Value :: term()}].
%%---------------------------------------------------------------------------
@@ -35,45 +37,63 @@
new() -> [].
--spec is_key(Key::term(), Dictionary::orddict()) -> boolean().
+-spec is_key(Key, Orddict) -> boolean() when
+ Key :: term(),
+ Orddict :: orddict().
is_key(Key, [{K,_}|_]) when Key < K -> false;
is_key(Key, [{K,_}|Dict]) when Key > K -> is_key(Key, Dict);
is_key(_Key, [{_K,_Val}|_]) -> true; %Key == K
is_key(_, []) -> false.
--spec to_list(orddict()) -> [{term(), term()}].
+-spec to_list(Orddict) -> List when
+ Orddict :: orddict(),
+ List :: [{Key :: term(), Value :: term()}].
to_list(Dict) -> Dict.
--spec from_list([{term(), term()}]) -> orddict().
+-spec from_list(List) -> Orddict when
+ List :: [{Key :: term(), Value :: term()}],
+ Orddict :: orddict().
from_list(Pairs) ->
lists:foldl(fun ({K,V}, D) -> store(K, V, D) end, [], Pairs).
--spec size(orddict()) -> non_neg_integer().
+-spec size(Orddict) -> non_neg_integer() when
+ Orddict :: orddict().
size(D) -> length(D).
--spec fetch(Key::term(), Dictionary::orddict()) -> term().
+-spec fetch(Key, Orddict) -> Value when
+ Key :: term(),
+ Value :: term(),
+ Orddict :: orddict().
fetch(Key, [{K,_}|D]) when Key > K -> fetch(Key, D);
fetch(Key, [{K,Value}|_]) when Key == K -> Value.
--spec find(Key::term(), Dictionary::orddict()) -> {'ok', term()} | 'error'.
+-spec find(Key, Orddict) -> {'ok', Value} | 'error' when
+ Key :: term(),
+ Orddict :: orddict(),
+ Value :: term().
find(Key, [{K,_}|_]) when Key < K -> error;
find(Key, [{K,_}|D]) when Key > K -> find(Key, D);
find(_Key, [{_K,Value}|_]) -> {ok,Value}; %Key == K
find(_, []) -> error.
--spec fetch_keys(Dictionary::orddict()) -> [term()].
+-spec fetch_keys(Orddict) -> Keys when
+ Orddict :: orddict(),
+ Keys :: [term()].
fetch_keys([{Key,_}|Dict]) ->
[Key|fetch_keys(Dict)];
fetch_keys([]) -> [].
--spec erase(Key::term(), Dictionary::orddict()) -> orddict().
+-spec erase(Key, Orddict1) -> Orddict2 when
+ Key :: term(),
+ Orddict1 :: orddict(),
+ Orddict2 :: orddict().
erase(Key, [{K,_}=E|Dict]) when Key < K -> [E|Dict];
erase(Key, [{K,_}=E|Dict]) when Key > K ->
@@ -81,7 +101,11 @@ erase(Key, [{K,_}=E|Dict]) when Key > K ->
erase(_Key, [{_K,_Val}|Dict]) -> Dict; %Key == K
erase(_, []) -> [].
--spec store(Key::term(), Value::term(), Dictionary::orddict()) -> orddict().
+-spec store(Key, Value, Orddict1) -> Orddict2 when
+ Key :: term(),
+ Value :: term(),
+ Orddict1 :: orddict(),
+ Orddict2 :: orddict().
store(Key, New, [{K,_}=E|Dict]) when Key < K ->
[{Key,New},E|Dict];
@@ -91,7 +115,11 @@ store(Key, New, [{_K,_Old}|Dict]) -> %Key == K
[{Key,New}|Dict];
store(Key, New, []) -> [{Key,New}].
--spec append(Key::term(), Value::term(), Dictionary::orddict()) -> orddict().
+-spec append(Key, Value, Orddict1) -> Orddict2 when
+ Key :: term(),
+ Value :: term(),
+ Orddict1 :: orddict(),
+ Orddict2 :: orddict().
append(Key, New, [{K,_}=E|Dict]) when Key < K ->
[{Key,[New]},E|Dict];
@@ -101,7 +129,11 @@ append(Key, New, [{_K,Old}|Dict]) -> %Key == K
[{Key,Old ++ [New]}|Dict];
append(Key, New, []) -> [{Key,[New]}].
--spec append_list(Key::term(), ValueList::[term()], orddict()) -> orddict().
+-spec append_list(Key, ValList, Orddict1) -> Orddict2 when
+ Key :: term(),
+ ValList :: [Value :: term()],
+ Orddict1 :: orddict(),
+ Orddict2 :: orddict().
append_list(Key, NewList, [{K,_}=E|Dict]) when Key < K ->
[{Key,NewList},E|Dict];
@@ -112,14 +144,23 @@ append_list(Key, NewList, [{_K,Old}|Dict]) -> %Key == K
append_list(Key, NewList, []) ->
[{Key,NewList}].
--spec update(Key::term(), Fun::fun((term()) -> term()), orddict()) -> orddict().
+-spec update(Key, Fun, Orddict1) -> Orddict2 when
+ Key :: term(),
+ Fun :: fun((Value1 :: term()) -> Value2 :: term()),
+ Orddict1 :: orddict(),
+ Orddict2 :: orddict().
update(Key, Fun, [{K,_}=E|Dict]) when Key > K ->
[E|update(Key, Fun, Dict)];
update(Key, Fun, [{K,Val}|Dict]) when Key == K ->
[{Key,Fun(Val)}|Dict].
--spec update(term(), fun((term()) -> term()), term(), orddict()) -> orddict().
+-spec update(Key, Fun, Initial, Orddict1) -> Orddict2 when
+ Key :: term(),
+ Initial :: term(),
+ Fun :: fun((Value1 :: term()) -> Value2 :: term()),
+ Orddict1 :: orddict(),
+ Orddict2 :: orddict().
update(Key, _, Init, [{K,_}=E|Dict]) when Key < K ->
[{Key,Init},E|Dict];
@@ -129,7 +170,11 @@ update(Key, Fun, _Init, [{_K,Val}|Dict]) -> %Key == K
[{Key,Fun(Val)}|Dict];
update(Key, _, Init, []) -> [{Key,Init}].
--spec update_counter(Key::term(), Incr::number(), orddict()) -> orddict().
+-spec update_counter(Key, Increment, Orddict1) -> Orddict2 when
+ Key :: term(),
+ Increment :: number(),
+ Orddict1 :: orddict(),
+ Orddict2 :: orddict().
update_counter(Key, Incr, [{K,_}=E|Dict]) when Key < K ->
[{Key,Incr},E|Dict];
@@ -139,19 +184,29 @@ update_counter(Key, Incr, [{_K,Val}|Dict]) -> %Key == K
[{Key,Val+Incr}|Dict];
update_counter(Key, Incr, []) -> [{Key,Incr}].
--spec fold(fun((term(),term(),term()) -> term()), term(), orddict()) -> term().
+-spec fold(Fun, Acc0, Orddict) -> Acc1 when
+ Fun :: fun((Key :: term(), Value :: term(), AccIn :: term()) -> AccOut :: term()),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ Orddict :: orddict().
fold(F, Acc, [{Key,Val}|D]) ->
fold(F, F(Key, Val, Acc), D);
fold(F, Acc, []) when is_function(F, 3) -> Acc.
--spec map(fun((term(), term()) -> term()), orddict()) -> orddict().
+-spec map(Fun, Orddict1) -> Orddict2 when
+ Fun :: fun((Key :: term(), Value1 :: term()) -> Value2 :: term()),
+ Orddict1 :: orddict(),
+ Orddict2 :: orddict().
map(F, [{Key,Val}|D]) ->
[{Key,F(Key, Val)}|map(F, D)];
map(F, []) when is_function(F, 2) -> [].
--spec filter(fun((term(), term()) -> boolean()), orddict()) -> orddict().
+-spec filter(Pred, Orddict1) -> Orddict2 when
+ Pred :: fun((Key :: term(), Value :: term()) -> boolean()),
+ Orddict1 :: orddict(),
+ Orddict2 :: orddict().
filter(F, [{Key,Val}=E|D]) ->
case F(Key, Val) of
@@ -160,8 +215,11 @@ filter(F, [{Key,Val}=E|D]) ->
end;
filter(F, []) when is_function(F, 2) -> [].
--spec merge(fun((term(), term(), term()) -> term()), orddict(), orddict()) ->
- orddict().
+-spec merge(Fun, Orddict1, Orddict2) -> Orddict3 when
+ Fun :: fun((Key :: term(), Value1 :: term(), Value2 :: term()) -> Value :: term()),
+ Orddict1 :: orddict(),
+ Orddict2 :: orddict(),
+ Orddict3 :: orddict().
merge(F, [{K1,_}=E1|D1], [{K2,_}=E2|D2]) when K1 < K2 ->
[E1|merge(F, D1, [E2|D2])];
diff --git a/lib/stdlib/src/ordsets.erl b/lib/stdlib/src/ordsets.erl
index 5a1c260703..4a8b1275b2 100644
--- a/lib/stdlib/src/ordsets.erl
+++ b/lib/stdlib/src/ordsets.erl
@@ -40,7 +40,8 @@ new() -> [].
%% is_set(Term) -> boolean().
%% Return 'true' if Set is an ordered set of elements, else 'false'.
--spec is_set(term()) -> boolean().
+-spec is_set(Ordset) -> boolean() when
+ Ordset :: term().
is_set([E|Es]) -> is_set(Es, E);
is_set([]) -> true;
@@ -54,21 +55,26 @@ is_set([], _) -> true.
%% size(OrdSet) -> int().
%% Return the number of elements in OrdSet.
--spec size(ordset(_)) -> non_neg_integer().
+-spec size(Ordset) -> non_neg_integer() when
+ Ordset :: ordset(_).
size(S) -> length(S).
%% to_list(OrdSet) -> [Elem].
%% Return the elements in OrdSet as a list.
--spec to_list(ordset(T)) -> [T].
+-spec to_list(Ordset) -> List when
+ Ordset :: ordset(T),
+ List :: [T].
to_list(S) -> S.
%% from_list([Elem]) -> Set.
%% Build an ordered set from the elements in List.
--spec from_list([T]) -> ordset(T).
+-spec from_list(List) -> Ordset when
+ List :: [T],
+ Ordset :: ordset(T).
from_list(L) ->
lists:usort(L).
@@ -76,7 +82,9 @@ from_list(L) ->
%% is_element(Element, OrdSet) -> boolean().
%% Return 'true' if Element is an element of OrdSet, else 'false'.
--spec is_element(term(), ordset(_)) -> boolean().
+-spec is_element(Element, Ordset) -> boolean() when
+ Element :: term(),
+ Ordset :: ordset(_).
is_element(E, [H|Es]) when E > H -> is_element(E, Es);
is_element(E, [H|_]) when E < H -> false;
@@ -86,7 +94,12 @@ is_element(_, []) -> false.
%% add_element(Element, OrdSet) -> OrdSet.
%% Return OrdSet with Element inserted in it.
--spec add_element(E, ordset(T)) -> [T | E,...].
+-spec add_element(Element, Ordset1) -> Ordset2 when
+ Element :: E,
+ Ordset1 :: ordset(T),
+ Ordset2 :: ordset(T | E).
+
+%-spec add_element(E, ordset(T)) -> [T | E,...].
add_element(E, [H|Es]) when E > H -> [H|add_element(E, Es)];
add_element(E, [H|_]=Set) when E < H -> [E|Set];
@@ -96,7 +109,10 @@ add_element(E, []) -> [E].
%% del_element(Element, OrdSet) -> OrdSet.
%% Return OrdSet but with Element removed.
--spec del_element(term(), ordset(T)) -> ordset(T).
+-spec del_element(Element, Ordset1) -> Ordset2 when
+ Element :: term(),
+ Ordset1 :: ordset(T),
+ Ordset2 :: ordset(T).
del_element(E, [H|Es]) when E > H -> [H|del_element(E, Es)];
del_element(E, [H|_]=Set) when E < H -> Set;
@@ -106,7 +122,10 @@ del_element(_, []) -> [].
%% union(OrdSet1, OrdSet2) -> OrdSet
%% Return the union of OrdSet1 and OrdSet2.
--spec union(ordset(T1), ordset(T2)) -> ordset(T1 | T2).
+-spec union(Ordset1, Ordset2) -> Ordset3 when
+ Ordset1 :: ordset(T1),
+ Ordset2 :: ordset(T2),
+ Ordset3 :: ordset(T1 | T2).
union([E1|Es1], [E2|_]=Set2) when E1 < E2 ->
[E1|union(Es1, Set2)];
@@ -120,7 +139,9 @@ union(Es1, []) -> Es1.
%% union([OrdSet]) -> OrdSet
%% Return the union of the list of ordered sets.
--spec union([ordset(T)]) -> ordset(T).
+-spec union(OrdsetList) -> Ordset when
+ OrdsetList :: [ordset(T)],
+ Ordset :: ordset(T).
union([S1,S2|Ss]) ->
union1(union(S1, S2), Ss);
@@ -133,7 +154,10 @@ union1(S1, []) -> S1.
%% intersection(OrdSet1, OrdSet2) -> OrdSet.
%% Return the intersection of OrdSet1 and OrdSet2.
--spec intersection(ordset(_), ordset(_)) -> ordset(_).
+-spec intersection(Ordset1, Ordset2) -> Ordset3 when
+ Ordset1 :: ordset(_),
+ Ordset2 :: ordset(_),
+ Ordset3 :: ordset(_).
intersection([E1|Es1], [E2|_]=Set2) when E1 < E2 ->
intersection(Es1, Set2);
@@ -149,7 +173,9 @@ intersection(_, []) ->
%% intersection([OrdSet]) -> OrdSet.
%% Return the intersection of the list of ordered sets.
--spec intersection([ordset(_),...]) -> ordset(_).
+-spec intersection(OrdsetList) -> Ordset when
+ OrdsetList :: [ordset(_),...],
+ Ordset :: ordset(_).
intersection([S1,S2|Ss]) ->
intersection1(intersection(S1, S2), Ss);
@@ -162,7 +188,9 @@ intersection1(S1, []) -> S1.
%% is_disjoint(OrdSet1, OrdSet2) -> boolean().
%% Check whether OrdSet1 and OrdSet2 are disjoint.
--spec is_disjoint(ordset(_), ordset(_)) -> boolean().
+-spec is_disjoint(Ordset1, Ordset2) -> boolean() when
+ Ordset1 :: ordset(_),
+ Ordset2 :: ordset(_).
is_disjoint([E1|Es1], [E2|_]=Set2) when E1 < E2 ->
is_disjoint(Es1, Set2);
@@ -179,7 +207,10 @@ is_disjoint(_, []) ->
%% Return all and only the elements of OrdSet1 which are not also in
%% OrdSet2.
--spec subtract(ordset(_), ordset(_)) -> ordset(_).
+-spec subtract(Ordset1, Ordset2) -> Ordset3 when
+ Ordset1 :: ordset(_),
+ Ordset2 :: ordset(_),
+ Ordset3 :: ordset(_).
subtract([E1|Es1], [E2|_]=Set2) when E1 < E2 ->
[E1|subtract(Es1, Set2)];
@@ -194,7 +225,9 @@ subtract(Es1, []) -> Es1.
%% Return 'true' when every element of OrdSet1 is also a member of
%% OrdSet2, else 'false'.
--spec is_subset(ordset(_), ordset(_)) -> boolean().
+-spec is_subset(Ordset1, Ordset2) -> boolean() when
+ Ordset1 :: ordset(_),
+ Ordset2 :: ordset(_).
is_subset([E1|_], [E2|_]) when E1 < E2 -> %E1 not in Set2
false;
@@ -208,7 +241,11 @@ is_subset(_, []) -> false.
%% fold(Fun, Accumulator, OrdSet) -> Accumulator.
%% Fold function Fun over all elements in OrdSet and return Accumulator.
--spec fold(fun((T, term()) -> term()), term(), ordset(T)) -> term().
+-spec fold(Function, Acc0, Ordset) -> Acc1 when
+ Function :: fun((Element :: T, AccIn :: term()) -> AccOut :: term()),
+ Ordset :: ordset(T),
+ Acc0 :: term(),
+ Acc1 :: term().
fold(F, Acc, Set) ->
lists:foldl(F, Acc, Set).
@@ -216,7 +253,10 @@ fold(F, Acc, Set) ->
%% filter(Fun, OrdSet) -> OrdSet.
%% Filter OrdSet with Fun.
--spec filter(fun((T) -> boolean()), ordset(T)) -> ordset(T).
+-spec filter(Pred, Ordset1) -> Ordset2 when
+ Pred :: fun((Element :: T) -> boolean()),
+ Ordset1 :: ordset(T),
+ Ordset2 :: ordset(T).
filter(F, Set) ->
lists:filter(F, Set).
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 5c52dfcbf0..c1285dab60 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -180,6 +180,9 @@ obsolete_1(calendar, local_time_to_universal_time, 1) ->
obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 ->
{deprecated, {rpc, multi_server_call, A}};
+
+%% *** SNMP ***
+
obsolete_1(snmp, N, A) ->
case is_snmp_agent_function(N, A) of
false ->
@@ -189,9 +192,100 @@ obsolete_1(snmp, N, A) ->
integer_to_list(A)++" instead"}
end;
+obsolete_1(snmpm, agent_info, 3) ->
+ {deprecated, {snmpm, agent_info, 2}, "R16B"};
+obsolete_1(snmpm, update_agent_info, 5) ->
+ {deprecated, {snmpm, update_agent_info, 4}, "R16B"};
+obsolete_1(snmpm, g, 3) ->
+ {deprecated, {snmpm, sync_get, 3}, "R16B"};
+obsolete_1(snmpm, g, 4) ->
+ {deprecated, {snmpm, sync_get, [3,4]}, "R16B"};
+obsolete_1(snmpm, g, 5) ->
+ {deprecated, {snmpm, sync_get, [4,5]}, "R16B"};
+obsolete_1(snmpm, g, 6) ->
+ {deprecated, {snmpm, sync_get, [5,6]}, "R16B"};
+obsolete_1(snmpm, g, 7) ->
+ {deprecated, {snmpm, sync_get, 6}, "R16B"};
+obsolete_1(snmpm, ag, 3) ->
+ {deprecated, {snmpm, async_get, 3}, "R16B"};
+obsolete_1(snmpm, ag, 4) ->
+ {deprecated, {snmpm, async_get, [3,4]}, "R16B"};
+obsolete_1(snmpm, ag, 5) ->
+ {deprecated, {snmpm, async_get, [4,5]}, "R16B"};
+obsolete_1(snmpm, ag, 6) ->
+ {deprecated, {snmpm, async_get, [5,6]}, "R16B"};
+obsolete_1(snmpm, ag, 7) ->
+ {deprecated, {snmpm, async_get, 6}, "R16B"};
+obsolete_1(snmpm, gn, 3) ->
+ {deprecated, {snmpm, sync_get_next, 3}, "R16B"};
+obsolete_1(snmpm, gn, 4) ->
+ {deprecated, {snmpm, sync_get_next, [3,4]}, "R16B"};
+obsolete_1(snmpm, gn, 5) ->
+ {deprecated, {snmpm, sync_get_next, [4,5]}, "R16B"};
+obsolete_1(snmpm, gn, 6) ->
+ {deprecated, {snmpm, sync_get_next, [5,6]}, "R16B"};
+obsolete_1(snmpm, gn, 7) ->
+ {deprecated, {snmpm, sync_get_next, 6}, "R16B"};
+obsolete_1(snmpm, agn, 3) ->
+ {deprecated, {snmpm, async_get_next, 3}, "R16B"};
+obsolete_1(snmpm, agn, 4) ->
+ {deprecated, {snmpm, async_get_next, [3,4]}, "R16B"};
+obsolete_1(snmpm, agn, 5) ->
+ {deprecated, {snmpm, async_get_next, [4,5]}, "R16B"};
+obsolete_1(snmpm, agn, 6) ->
+ {deprecated, {snmpm, async_get_next, [5,6]}, "R16B"};
+obsolete_1(snmpm, agn, 7) ->
+ {deprecated, {snmpm, async_get_next, 6}, "R16B"};
+obsolete_1(snmpm, s, 3) ->
+ {deprecated, {snmpm, sync_set, 3}, "R16B"};
+obsolete_1(snmpm, s, 4) ->
+ {deprecated, {snmpm, sync_set, [3,4]}, "R16B"};
+obsolete_1(snmpm, s, 5) ->
+ {deprecated, {snmpm, sync_set, [4,5]}, "R16B"};
+obsolete_1(snmpm, s, 6) ->
+ {deprecated, {snmpm, sync_set, [5,6]}, "R16B"};
+obsolete_1(snmpm, s, 7) ->
+ {deprecated, {snmpm, sync_set, 6}, "R16B"};
+obsolete_1(snmpm, as, 3) ->
+ {deprecated, {snmpm, async_set, 3}, "R16B"};
+obsolete_1(snmpm, as, 4) ->
+ {deprecated, {snmpm, async_set, [3,4]}, "R16B"};
+obsolete_1(snmpm, as, 5) ->
+ {deprecated, {snmpm, async_set, [4,5]}, "R16B"};
+obsolete_1(snmpm, as, 6) ->
+ {deprecated, {snmpm, async_set, [5,6]}, "R16B"};
+obsolete_1(snmpm, as, 7) ->
+ {deprecated, {snmpm, async_set, 6}, "R16B"};
+obsolete_1(snmpm, gb, 5) ->
+ {deprecated, {snmpm, sync_get_bulk, 5}, "R16B"};
+obsolete_1(snmpm, gb, 6) ->
+ {deprecated, {snmpm, sync_get_bulk, [5,6]}, "R16B"};
+obsolete_1(snmpm, gb, 7) ->
+ {deprecated, {snmpm, sync_get_bulk, [6,7]}, "R16B"};
+obsolete_1(snmpm, gb, 8) ->
+ {deprecated, {snmpm, sync_get_bulk, [7,8]}, "R16B"};
+obsolete_1(snmpm, gb, 9) ->
+ {deprecated, {snmpm, sync_get_bulk, 8}, "R16B"};
+obsolete_1(snmpm, agb, 5) ->
+ {deprecated, {snmpm, async_get_bulk, 5}, "R16B"};
+obsolete_1(snmpm, agb, 6) ->
+ {deprecated, {snmpm, async_get_bulk, [5,6]}, "R16B"};
+obsolete_1(snmpm, agb, 7) ->
+ {deprecated, {snmpm, async_get_bulk, [6,7]}, "R16B"};
+obsolete_1(snmpm, agb, 8) ->
+ {deprecated, {snmpm, async_get_bulk, [7,8]}, "R16B"};
+obsolete_1(snmpm, agb, 9) ->
+ {deprecated, {snmpm, async_get_bulk, 8}, "R16B"};
+
+
+%% *** MEGACO ***
+
obsolete_1(megaco, format_versions, 1) ->
{deprecated, "Deprecated; use megaco:print_version_info/0,1 instead"};
+
+%% *** OS-MON-MIB ***
+
obsolete_1(os_mon_mib, init, 1) ->
{deprecated, {os_mon_mib, load, 1}};
obsolete_1(os_mon_mib, stop, 1) ->
@@ -236,22 +330,22 @@ obsolete_1(erlang, fault, 2) ->
obsolete_1(file, rawopen, 2) ->
{removed, "deprecated (will be removed in R13B); use file:open/2 with the raw option"};
-obsolete_1(http, request, 1) -> {deprecated,{httpc,request,1},"R15B"};
-obsolete_1(http, request, 2) -> {deprecated,{httpc,request,2},"R15B"};
-obsolete_1(http, request, 4) -> {deprecated,{httpc,request,4},"R15B"};
-obsolete_1(http, request, 5) -> {deprecated,{httpc,request,5},"R15B"};
-obsolete_1(http, cancel_request, 1) -> {deprecated,{httpc,cancel_request,1},"R15B"};
-obsolete_1(http, cancel_request, 2) -> {deprecated,{httpc,cancel_request,2},"R15B"};
-obsolete_1(http, set_option, 2) -> {deprecated,{httpc,set_option,2},"R15B"};
-obsolete_1(http, set_option, 3) -> {deprecated,{httpc,set_option,3},"R15B"};
-obsolete_1(http, set_options, 1) -> {deprecated,{httpc,set_options,1},"R15B"};
-obsolete_1(http, set_options, 2) -> {deprecated,{httpc,set_options,2},"R15B"};
-obsolete_1(http, verify_cookies, 2) -> {deprecated,{httpc,verify_cookies,2},"R15B"};
-obsolete_1(http, verify_cookies, 3) -> {deprecated,{httpc,verify_cookies,3},"R15B"};
-obsolete_1(http, cookie_header, 1) -> {deprecated,{httpc,cookie_header,1},"R15B"};
-obsolete_1(http, cookie_header, 2) -> {deprecated,{httpc,cookie_header,2},"R15B"};
-obsolete_1(http, stream_next, 1) -> {deprecated,{httpc,stream_next,1},"R15B"};
-obsolete_1(http, default_profile, 0) -> {deprecated,{httpc,default_profile,0},"R15B"};
+obsolete_1(http, request, 1) -> {removed,{httpc,request,1},"R15B"};
+obsolete_1(http, request, 2) -> {removed,{httpc,request,2},"R15B"};
+obsolete_1(http, request, 4) -> {removed,{httpc,request,4},"R15B"};
+obsolete_1(http, request, 5) -> {removed,{httpc,request,5},"R15B"};
+obsolete_1(http, cancel_request, 1) -> {removed,{httpc,cancel_request,1},"R15B"};
+obsolete_1(http, cancel_request, 2) -> {removed,{httpc,cancel_request,2},"R15B"};
+obsolete_1(http, set_option, 2) -> {removed,{httpc,set_option,2},"R15B"};
+obsolete_1(http, set_option, 3) -> {removed,{httpc,set_option,3},"R15B"};
+obsolete_1(http, set_options, 1) -> {removed,{httpc,set_options,1},"R15B"};
+obsolete_1(http, set_options, 2) -> {removed,{httpc,set_options,2},"R15B"};
+obsolete_1(http, verify_cookies, 2) -> {removed,{httpc,store_cookies,2},"R15B"};
+obsolete_1(http, verify_cookies, 3) -> {removed,{httpc,store_cookies,3},"R15B"};
+obsolete_1(http, cookie_header, 1) -> {removed,{httpc,cookie_header,1},"R15B"};
+obsolete_1(http, cookie_header, 2) -> {removed,{httpc,cookie_header,2},"R15B"};
+obsolete_1(http, stream_next, 1) -> {removed,{httpc,stream_next,1},"R15B"};
+obsolete_1(http, default_profile, 0) -> {removed,{httpc,default_profile,0},"R15B"};
obsolete_1(httpd, start, 0) -> {removed,{inets,start,[2,3]},"R14B"};
obsolete_1(httpd, start, 1) -> {removed,{inets,start,[2,3]},"R14B"};
@@ -355,7 +449,7 @@ obsolete_1(ssl_pkix, decode_cert, A) when A =:= 1; A =:= 2 ->
%% Added in R13B04.
obsolete_1(erlang, concat_binary, 1) ->
- {deprecated,{erlang,list_to_binary,1},"R15B"};
+ {removed,{erlang,list_to_binary,1},"R15B"};
%% Added in R14A.
obsolete_1(ssl, peercert, 2) ->
@@ -367,6 +461,18 @@ obsolete_1(public_key, pem_to_der, 1) ->
obsolete_1(public_key, decode_private_key, A) when A =:= 1; A =:= 2 ->
{deprecated,{public_key,pem_entry_decode,1},"R15A"};
+%% Added in R14B03.
+obsolete_1(docb_gen, _, _) ->
+ {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"};
+obsolete_1(docb_transform, _, _) ->
+ {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"};
+obsolete_1(docb_xml_check, _, _) ->
+ {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"};
+
+%% Added in R15B
+obsolete_1(asn1rt, F, _) when F == load_driver; F == unload_driver ->
+ {deprecated,"deprecated (will be removed in R16A); has no effect as drivers are no longer used."};
+
obsolete_1(_, _, _) ->
no.
diff --git a/lib/stdlib/src/pg.erl b/lib/stdlib/src/pg.erl
index 503654e706..ee177e4e0b 100644
--- a/lib/stdlib/src/pg.erl
+++ b/lib/stdlib/src/pg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -35,7 +35,9 @@
%% Create a brand new empty process group with the master residing
%% at the local node
--spec create(term()) -> 'ok' | {'error', term()}.
+-spec create(PgName) -> 'ok' | {'error', Reason} when
+ PgName :: term(),
+ Reason :: 'already_created' | term().
create(PgName) ->
catch begin check(PgName),
@@ -46,7 +48,10 @@ create(PgName) ->
%% Create a brand new empty process group with the master
%% residing at Node
--spec create(term(), node()) -> 'ok' | {'error', term()}.
+-spec create(PgName, Node) -> 'ok' | {'error', Reason} when
+ PgName :: term(),
+ Node :: node(),
+ Reason :: 'already_created' | term().
create(PgName, Node) ->
catch begin check(PgName),
@@ -66,7 +71,10 @@ standby(_PgName, _Node) ->
%% Tell process group PgName that Pid is a new member of the group
%% synchronously return a list of all old members in the group
--spec join(atom(), pid()) -> [pid()].
+-spec join(PgName, Pid) -> Members when
+ PgName :: term(),
+ Pid :: pid(),
+ Members :: [pid()].
join(PgName, Pid) when is_atom(PgName) ->
global:send(PgName, {join,self(),Pid}),
@@ -77,7 +85,9 @@ join(PgName, Pid) when is_atom(PgName) ->
%% Multi cast Mess to all members in the group
--spec send(atom() | pid(), term()) -> 'ok'.
+-spec send(PgName, Msg) -> 'ok' when
+ PgName :: term(),
+ Msg :: term().
send(PgName, Mess) when is_atom(PgName) ->
global:send(PgName, {send, self(), Mess}),
@@ -89,7 +99,9 @@ send(Pg, Mess) when is_pid(Pg) ->
%% multi cast a message to all members in the group but ourselves
%% If we are a member
--spec esend(atom() | pid(), term()) -> 'ok'.
+-spec esend(PgName, Msg) -> 'ok' when
+ PgName :: term(),
+ Msg :: term().
esend(PgName, Mess) when is_atom(PgName) ->
global:send(PgName, {esend,self(),Mess}),
@@ -100,7 +112,9 @@ esend(Pg, Mess) when is_pid(Pg) ->
%% Return the members of the group
--spec members(atom() | pid()) -> [pid()].
+-spec members(PgName) -> Members when
+ PgName :: term(),
+ Members :: [pid()].
members(PgName) when is_atom(PgName) ->
global:send(PgName, {self() ,members}),
diff --git a/lib/stdlib/src/pool.erl b/lib/stdlib/src/pool.erl
index 7f5f23e26d..a5eb191ab2 100644
--- a/lib/stdlib/src/pool.erl
+++ b/lib/stdlib/src/pool.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -52,11 +52,16 @@
%% Start up using the .hosts.erlang file
--spec start(atom()) -> [node()].
+-spec start(Name) -> Nodes when
+ Name :: atom(),
+ Nodes :: [node()].
start(Name) ->
start(Name,[]).
--spec start(atom(), string()) -> [node()].
+-spec start(Name, Args) -> Nodes when
+ Name :: atom(),
+ Args :: string(),
+ Nodes :: [node()].
start(Name, Args) when is_atom(Name) ->
gen_server:start({global, pool_master}, pool, [], []),
Hosts = net_adm:host_file(),
@@ -71,7 +76,8 @@ start(Name, Args) when is_atom(Name) ->
get_nodes() ->
get_elements(2, get_nodes_and_load()).
--spec attach(node()) -> 'already_attached' | 'attached'.
+-spec attach(Node) -> 'already_attached' | 'attached' when
+ Node :: node().
attach(Node) ->
gen_server:call({global, pool_master}, {attach, Node}).
@@ -82,11 +88,17 @@ get_nodes_and_load() ->
get_node() ->
gen_server:call({global, pool_master}, get_node).
--spec pspawn(module(), atom(), [term()]) -> pid().
+-spec pspawn(Mod, Fun, Args) -> pid() when
+ Mod :: module(),
+ Fun :: atom(),
+ Args :: [term()].
pspawn(M, F, A) ->
gen_server:call({global, pool_master}, {spawn, group_leader(), M, F, A}).
--spec pspawn_link(module(), atom(), [term()]) -> pid().
+-spec pspawn_link(Mod, Fun, Args) -> pid() when
+ Mod :: module(),
+ Fun :: atom(),
+ Args :: [term()].
pspawn_link(M, F, A) ->
P = pspawn(M, F, A),
link(P),
@@ -95,6 +107,9 @@ pspawn_link(M, F, A) ->
start_nodes([], _, _) -> [];
start_nodes([Host|Tail], Name, Args) ->
case slave:start(Host, Name, Args) of
+ {error, {already_running, Node}} ->
+ io:format("Can't start node on host ~w due to ~w~n",[Host, {already_running, Node}]),
+ [Node | start_nodes(Tail, Name, Args)];
{error, R} ->
io:format("Can't start node on host ~w due to ~w~n",[Host, R]),
start_nodes(Tail, Name, Args);
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index 4fb64a3353..02bcbb5a60 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -40,77 +40,108 @@
-type priority_level() :: 'high' | 'low' | 'max' | 'normal'.
-type spawn_option() :: 'link'
+ | 'monitor'
| {'priority', priority_level()}
| {'min_heap_size', non_neg_integer()}
+ | {'min_bin_vheap_size', non_neg_integer()}
| {'fullsweep_after', non_neg_integer()}.
--type dict_or_pid() :: pid() | [_] | {integer(), integer(), integer()}.
+-type dict_or_pid() :: pid()
+ | (ProcInfo :: [_])
+ | {X :: integer(), Y :: integer(), Z :: integer()}.
%%-----------------------------------------------------------------------------
--spec spawn(function()) -> pid().
+-spec spawn(Fun) -> pid() when
+ Fun :: function().
spawn(F) when is_function(F) ->
Parent = get_my_name(),
Ancestors = get_ancestors(),
erlang:spawn(?MODULE, init_p, [Parent,Ancestors,F]).
--spec spawn(atom(), atom(), [term()]) -> pid().
+-spec spawn(Module, Function, Args) -> pid() when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()].
spawn(M,F,A) when is_atom(M), is_atom(F), is_list(A) ->
Parent = get_my_name(),
Ancestors = get_ancestors(),
erlang:spawn(?MODULE, init_p, [Parent,Ancestors,M,F,A]).
--spec spawn_link(function()) -> pid().
+-spec spawn_link(Fun) -> pid() when
+ Fun :: function().
spawn_link(F) when is_function(F) ->
Parent = get_my_name(),
Ancestors = get_ancestors(),
erlang:spawn_link(?MODULE, init_p, [Parent,Ancestors,F]).
--spec spawn_link(atom(), atom(), [term()]) -> pid().
+-spec spawn_link(Module, Function, Args) -> pid() when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()].
spawn_link(M,F,A) when is_atom(M), is_atom(F), is_list(A) ->
Parent = get_my_name(),
Ancestors = get_ancestors(),
erlang:spawn_link(?MODULE, init_p, [Parent,Ancestors,M,F,A]).
--spec spawn(node(), function()) -> pid().
+-spec spawn(Node, Fun) -> pid() when
+ Node :: node(),
+ Fun :: function().
spawn(Node, F) when is_function(F) ->
Parent = get_my_name(),
Ancestors = get_ancestors(),
erlang:spawn(Node, ?MODULE, init_p, [Parent,Ancestors,F]).
--spec spawn(node(), atom(), atom(), [term()]) -> pid().
+-spec spawn(Node, Module, Function, Args) -> pid() when
+ Node :: node(),
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()].
+
spawn(Node, M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
Parent = get_my_name(),
Ancestors = get_ancestors(),
erlang:spawn(Node, ?MODULE, init_p, [Parent,Ancestors,M,F,A]).
--spec spawn_link(node(), function()) -> pid().
+-spec spawn_link(Node, Fun) -> pid() when
+ Node :: node(),
+ Fun :: function().
spawn_link(Node, F) when is_function(F) ->
Parent = get_my_name(),
Ancestors = get_ancestors(),
erlang:spawn_link(Node, ?MODULE, init_p, [Parent,Ancestors,F]).
--spec spawn_link(node(), atom(), atom(), [term()]) -> pid().
+-spec spawn_link(Node, Module, Function, Args) -> pid() when
+ Node :: node(),
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()].
spawn_link(Node, M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
Parent = get_my_name(),
Ancestors = get_ancestors(),
erlang:spawn_link(Node, ?MODULE, init_p, [Parent,Ancestors,M,F,A]).
--spec spawn_opt(function(), [spawn_option()]) -> pid().
+-spec spawn_opt(Fun, SpawnOpts) -> pid() when
+ Fun :: function(),
+ SpawnOpts :: [spawn_option()].
+
spawn_opt(F, Opts) when is_function(F) ->
Parent = get_my_name(),
Ancestors = get_ancestors(),
check_for_monitor(Opts),
erlang:spawn_opt(?MODULE, init_p, [Parent,Ancestors,F],Opts).
--spec spawn_opt(node(), function(), [spawn_option()]) -> pid().
+-spec spawn_opt(Node, Function, SpawnOpts) -> pid() when
+ Node :: node(),
+ Function :: function(),
+ SpawnOpts :: [spawn_option()].
spawn_opt(Node, F, Opts) when is_function(F) ->
Parent = get_my_name(),
@@ -118,7 +149,11 @@ spawn_opt(Node, F, Opts) when is_function(F) ->
check_for_monitor(Opts),
erlang:spawn_opt(Node, ?MODULE, init_p, [Parent,Ancestors,F], Opts).
--spec spawn_opt(atom(), atom(), [term()], [spawn_option()]) -> pid().
+-spec spawn_opt(Module, Function, Args, SpawnOpts) -> pid() when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ SpawnOpts :: [spawn_option()].
spawn_opt(M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) ->
Parent = get_my_name(),
@@ -126,7 +161,12 @@ spawn_opt(M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) ->
check_for_monitor(Opts),
erlang:spawn_opt(?MODULE, init_p, [Parent,Ancestors,M,F,A], Opts).
--spec spawn_opt(node(), atom(), atom(), [term()], [spawn_option()]) -> pid().
+-spec spawn_opt(Node, Module, Function, Args, SpawnOpts) -> pid() when
+ Node :: node(),
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ SpawnOpts :: [spawn_option()].
spawn_opt(Node, M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) ->
Parent = get_my_name(),
@@ -144,7 +184,10 @@ check_for_monitor(SpawnOpts) ->
false
end.
--spec hibernate(module(), atom(), [term()]) -> no_return().
+-spec hibernate(Module, Function, Args) -> no_return() when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()].
hibernate(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
erlang:hibernate(?MODULE, wake_up, [M, F, A]).
@@ -210,35 +253,65 @@ exit_p(Class, Reason) ->
exit(Reason)
end.
--spec start(atom(), atom(), [term()]) -> term().
+-spec start(Module, Function, Args) -> Ret when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Ret :: term() | {error, Reason :: term()}.
start(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
start(M, F, A, infinity).
--spec start(atom(), atom(), [term()], timeout()) -> term().
+-spec start(Module, Function, Args, Time) -> Ret when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Time :: timeout(),
+ Ret :: term() | {error, Reason :: term()}.
start(M, F, A, Timeout) when is_atom(M), is_atom(F), is_list(A) ->
Pid = ?MODULE:spawn(M, F, A),
sync_wait(Pid, Timeout).
--spec start(atom(), atom(), [term()], timeout(), [spawn_option()]) -> term().
+-spec start(Module, Function, Args, Time, SpawnOpts) -> Ret when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Time :: timeout(),
+ SpawnOpts :: [spawn_option()],
+ Ret :: term() | {error, Reason :: term()}.
start(M, F, A, Timeout, SpawnOpts) when is_atom(M), is_atom(F), is_list(A) ->
Pid = ?MODULE:spawn_opt(M, F, A, SpawnOpts),
sync_wait(Pid, Timeout).
--spec start_link(atom(), atom(), [term()]) -> term().
+-spec start_link(Module, Function, Args) -> Ret when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Ret :: term() | {error, Reason :: term()}.
start_link(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
start_link(M, F, A, infinity).
--spec start_link(atom(), atom(), [term()], timeout()) -> term().
+-spec start_link(Module, Function, Args, Time) -> Ret when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Time :: timeout(),
+ Ret :: term() | {error, Reason :: term()}.
start_link(M, F, A, Timeout) when is_atom(M), is_atom(F), is_list(A) ->
Pid = ?MODULE:spawn_link(M, F, A),
sync_wait(Pid, Timeout).
--spec start_link(atom(),atom(),[term()],timeout(),[spawn_option()]) -> term().
+-spec start_link(Module, Function, Args, Time, SpawnOpts) -> Ret when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Time :: timeout(),
+ SpawnOpts :: [spawn_option()],
+ Ret :: term() | {error, Reason :: term()}.
start_link(M,F,A,Timeout,SpawnOpts) when is_atom(M), is_atom(F), is_list(A) ->
Pid = ?MODULE:spawn_opt(M, F, A, ensure_link(SpawnOpts)),
@@ -267,13 +340,17 @@ flush(Pid) ->
true
end.
--spec init_ack(pid(), term()) -> 'ok'.
+-spec init_ack(Parent, Ret) -> 'ok' when
+ Parent :: pid(),
+ Ret :: term().
init_ack(Parent, Return) ->
Parent ! {ack, self(), Return},
ok.
--spec init_ack(term()) -> 'ok'.
+-spec init_ack(Ret) -> 'ok' when
+ Ret :: term().
+
init_ack(Return) ->
[Parent|_] = get('$ancestors'),
init_ack(Parent, Return).
@@ -282,7 +359,11 @@ init_ack(Return) ->
%% Fetch the initial call of a proc_lib spawned process.
%% -----------------------------------------------------
--spec initial_call(dict_or_pid()) -> {atom(), atom(), [atom()]} | 'false'.
+-spec initial_call(Process) -> {Module, Function, Args} | 'false' when
+ Process :: dict_or_pid(),
+ Module :: module(),
+ Function :: atom(),
+ Args :: [atom()].
initial_call(DictOrPid) ->
case raw_initial_call(DictOrPid) of
@@ -305,7 +386,11 @@ make_dummy_args(N, Acc) ->
%% This function is typically called from c:i() and c:regs().
%% -----------------------------------------------------
--spec translate_initial_call(dict_or_pid()) -> mfa().
+-spec translate_initial_call(Process) -> {Module, Function, Arity} when
+ Process :: dict_or_pid(),
+ Module :: module(),
+ Function :: atom(),
+ Arity :: byte().
translate_initial_call(DictOrPid) ->
case raw_initial_call(DictOrPid) of
@@ -577,7 +662,8 @@ check(Res) -> Res.
%%% Format (and write) a generated crash info structure.
%%% -----------------------------------------------------------
--spec format([term()]) -> string().
+-spec format(CrashReport) -> string() when
+ CrashReport :: [term()].
format([OwnReport,LinkReport]) ->
OwnFormat = format_report(OwnReport),
diff --git a/lib/stdlib/src/proplists.erl b/lib/stdlib/src/proplists.erl
index 6a45e0f868..e3eda5d932 100644
--- a/lib/stdlib/src/proplists.erl
+++ b/lib/stdlib/src/proplists.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,7 +37,7 @@
%% overriding the default settings, object properties, annotations,
%% etc.</p>
%%
-%% @type property() = atom() | tuple()
+%% % @type property() = atom() | tuple()
-module(proplists).
@@ -49,18 +49,13 @@
%% ---------------------------------------------------------------------
--export_type([property/0]).
+-export_type([property/0, proplist/0]).
-type property() :: atom() | tuple().
-
--type aliases() :: [{any(), any()}].
--type negations() :: [{any(), any()}].
--type expansions() :: [{property(), [any()]}].
+-type proplist() :: [property()].
%% ---------------------------------------------------------------------
-%% @spec property(P::property()) -> property()
-%%
%% @doc Creates a normal form (minimal) representation of a property. If
%% <code>P</code> is <code>{Key, true}</code> where <code>Key</code> is
%% an atom, this returns <code>Key</code>, otherwise the whole term
@@ -68,7 +63,8 @@
%%
%% @see property/2
--spec property(property()) -> property().
+-spec property(Property) -> Property when
+ Property :: property().
property({Key, true}) when is_atom(Key) ->
Key;
@@ -76,8 +72,6 @@ property(Property) ->
Property.
-%% @spec property(Key::term(), Value::term()) -> property()
-%%
%% @doc Creates a normal form (minimal) representation of a simple
%% key/value property. Returns <code>Key</code> if <code>Value</code> is
%% <code>true</code> and <code>Key</code> is an atom, otherwise a tuple
@@ -85,7 +79,10 @@ property(Property) ->
%%
%% @see property/1
--spec property(Key::term(), Value::term()) -> atom() | {term(), term()}.
+-spec property(Key, Value) -> Property when
+ Key :: term(),
+ Value :: term(),
+ Property :: atom() | {term(), term()}.
property(Key, true) when is_atom(Key) ->
Key;
@@ -95,14 +92,13 @@ property(Key, Value) ->
%% ---------------------------------------------------------------------
-%% @spec unfold(List::[term()]) -> [term()]
-%%
%% @doc Unfolds all occurences of atoms in <code>List</code> to tuples
%% <code>{Atom, true}</code>.
%%
%% @see compact/1
--spec unfold(List::[term()]) -> [term()].
+-spec unfold(List) -> List when
+ List :: [term()].
unfold([P | Ps]) ->
if is_atom(P) ->
@@ -113,15 +109,14 @@ unfold([P | Ps]) ->
unfold([]) ->
[].
-%% @spec compact(List::[term()]) -> [term()]
-%%
%% @doc Minimizes the representation of all entries in the list. This is
%% equivalent to <code>[property(P) || P &lt;- List]</code>.
%%
%% @see unfold/1
%% @see property/1
--spec compact(List::[property()]) -> [property()].
+-spec compact(List) -> List when
+ List :: [property()].
compact(List) ->
[property(P) || P <- List].
@@ -129,8 +124,6 @@ compact(List) ->
%% ---------------------------------------------------------------------
-%% @spec lookup(Key::term(), List::[term()]) -> none | tuple()
-%%
%% @doc Returns the first entry associated with <code>Key</code> in
%% <code>List</code>, if one exists, otherwise returns
%% <code>none</code>. For an atom <code>A</code> in the list, the tuple
@@ -140,7 +133,9 @@ compact(List) ->
%% @see get_value/2
%% @see get_bool/2
--spec lookup(Key::term(), List::[term()]) -> 'none' | tuple().
+-spec lookup(Key, List) -> 'none' | tuple() when
+ Key :: term(),
+ List :: [term()].
lookup(Key, [P | Ps]) ->
if is_atom(P), P =:= Key ->
@@ -154,15 +149,15 @@ lookup(Key, [P | Ps]) ->
lookup(_Key, []) ->
none.
-%% @spec lookup_all(Key::term(), List::[term()]) -> [tuple()]
-%%
%% @doc Returns the list of all entries associated with <code>Key</code>
%% in <code>List</code>. If no such entry exists, the result is the
%% empty list.
%%
%% @see lookup/2
--spec lookup_all(Key::term(), List::[term()]) -> [tuple()].
+-spec lookup_all(Key, List) -> [tuple()] when
+ Key :: term(),
+ List :: [term()].
lookup_all(Key, [P | Ps]) ->
if is_atom(P), P =:= Key ->
@@ -178,13 +173,13 @@ lookup_all(_Key, []) ->
%% ---------------------------------------------------------------------
-%% @spec is_defined(Key::term(), List::[term()]) -> boolean()
-%%
%% @doc Returns <code>true</code> if <code>List</code> contains at least
%% one entry associated with <code>Key</code>, otherwise
%% <code>false</code> is returned.
--spec is_defined(Key::term(), List::[term()]) -> boolean().
+-spec is_defined(Key, List) -> boolean() when
+ Key :: term(),
+ List :: [term()].
is_defined(Key, [P | Ps]) ->
if is_atom(P), P =:= Key ->
@@ -200,17 +195,15 @@ is_defined(_Key, []) ->
%% ---------------------------------------------------------------------
-%% @spec get_value(Key::term(), List::[term()]) -> term()
%% @equiv get_value(Key, List, undefined)
--spec get_value(Key::term(), List::[term()]) -> term().
+-spec get_value(Key, List) -> term() when
+ Key :: term(),
+ List :: List::[term()].
get_value(Key, List) ->
get_value(Key, List, undefined).
-%% @spec get_value(Key::term(), List::[term()], Default::term()) ->
-%% term()
-%%
%% @doc Returns the value of a simple key/value property in
%% <code>List</code>. If <code>lookup(Key, List)</code> would yield
%% <code>{Key, Value}</code>, this function returns the corresponding
@@ -221,7 +214,10 @@ get_value(Key, List) ->
%% @see get_all_values/2
%% @see get_bool/2
--spec get_value(Key::term(), List::[term()], Default::term()) -> term().
+-spec get_value(Key, List, Default) -> term() when
+ Key :: term(),
+ List :: [term()],
+ Default :: term().
get_value(Key, [P | Ps], Default) ->
if is_atom(P), P =:= Key ->
@@ -240,8 +236,6 @@ get_value(Key, [P | Ps], Default) ->
get_value(_Key, [], Default) ->
Default.
-%% @spec get_all_values(Key, List) -> [term()]
-%%
%% @doc Similar to <code>get_value/2</code>, but returns the list of
%% values for <em>all</em> entries <code>{Key, Value}</code> in
%% <code>List</code>. If no such entry exists, the result is the empty
@@ -249,7 +243,9 @@ get_value(_Key, [], Default) ->
%%
%% @see get_value/2
--spec get_all_values(Key::term(), List::[term()]) -> [term()].
+-spec get_all_values(Key, List) -> [term()] when
+ Key :: term(),
+ List :: [term()].
get_all_values(Key, [P | Ps]) ->
if is_atom(P), P =:= Key ->
@@ -267,8 +263,6 @@ get_all_values(Key, [P | Ps]) ->
get_all_values(_Key, []) ->
[].
-%% @spec append_values(Key::term(), List::[term()]) -> [term()]
-%%
%% @doc Similar to <code>get_all_values/2</code>, but each value is
%% wrapped in a list unless it is already itself a list, and the
%% resulting list of lists is concatenated. This is often useful for
@@ -278,7 +272,9 @@ get_all_values(_Key, []) ->
%%
%% @see get_all_values/2
--spec append_values(Key::term(), List::[term()]) -> [term()].
+-spec append_values(Key, List) -> List when
+ Key :: term(),
+ List :: [term()].
append_values(Key, [P | Ps]) ->
if is_atom(P), P =:= Key ->
@@ -301,8 +297,6 @@ append_values(_Key, []) ->
%% ---------------------------------------------------------------------
-%% @spec get_bool(Key::term(), List::[term()]) -> boolean()
-%%
%% @doc Returns the value of a boolean key/value option. If
%% <code>lookup(Key, List)</code> would yield <code>{Key, true}</code>,
%% this function returns <code>true</code>; otherwise <code>false</code>
@@ -311,7 +305,9 @@ append_values(_Key, []) ->
%% @see lookup/2
%% @see get_value/2
--spec get_bool(Key::term(), List::[term()]) -> boolean().
+-spec get_bool(Key, List) -> boolean() when
+ Key :: term(),
+ List :: [term()].
get_bool(Key, [P | Ps]) ->
if is_atom(P), P =:= Key ->
@@ -333,12 +329,11 @@ get_bool(_Key, []) ->
%% ---------------------------------------------------------------------
-%% @spec get_keys(List::[term()]) -> [term()]
-%%
%% @doc Returns an unordered list of the keys used in <code>List</code>,
%% not containing duplicates.
--spec get_keys(List::[term()]) -> [term()].
+-spec get_keys(List) -> [term()] when
+ List :: [term()].
get_keys(Ps) ->
sets:to_list(get_keys(Ps, sets:new())).
@@ -357,12 +352,12 @@ get_keys([], Keys) ->
%% ---------------------------------------------------------------------
-%% @spec delete(Key::term(), List::[term()]) -> [term()]
-%%
%% @doc Deletes all entries associated with <code>Key</code> from
%% <code>List</code>.
--spec delete(Key::term(), List::[term()]) -> [term()].
+-spec delete(Key, List) -> List when
+ Key :: term(),
+ List::[term()].
delete(Key, [P | Ps]) ->
if is_atom(P), P =:= Key ->
@@ -378,11 +373,6 @@ delete(_, []) ->
%% ---------------------------------------------------------------------
-%% @spec substitute_aliases(Aliases, List::[term()]) -> [term()]
-%%
-%% Aliases = [{Key, Key}]
-%% Key = term()
-%%
%% @doc Substitutes keys of properties. For each entry in
%% <code>List</code>, if it is associated with some key <code>K1</code>
%% such that <code>{K1, K2}</code> occurs in <code>Aliases</code>, the
@@ -398,7 +388,10 @@ delete(_, []) ->
%% @see substitute_negations/2
%% @see normalize/2
--spec substitute_aliases(aliases(), List::[term()]) -> [term()].
+-spec substitute_aliases(Aliases, List) -> List when
+ Aliases :: [{Key, Key}],
+ Key :: term(),
+ List::[term()].
substitute_aliases(As, Props) ->
[substitute_aliases_1(As, P) || P <- Props].
@@ -417,11 +410,6 @@ substitute_aliases_1([], P) ->
%% ---------------------------------------------------------------------
-%% @spec substitute_negations(Negations, List::[term()]) -> [term()]
-%%
-%% Negations = [{Key, Key}]
-%% Key = term()
-%%
%% @doc Substitutes keys of boolean-valued properties and simultaneously
%% negates their values. For each entry in <code>List</code>, if it is
%% associated with some key <code>K1</code> such that <code>{K1,
@@ -443,7 +431,10 @@ substitute_aliases_1([], P) ->
%% @see substitute_aliases/2
%% @see normalize/2
--spec substitute_negations(negations(), List::[term()]) -> [term()].
+-spec substitute_negations(Negations, List) -> List when
+ Negations :: [{Key, Key}],
+ Key :: term(),
+ List :: [term()].
substitute_negations(As, Props) ->
[substitute_negations_1(As, P) || P <- Props].
@@ -472,10 +463,6 @@ substitute_negations_1([], P) ->
%% ---------------------------------------------------------------------
-%% @spec expand(Expansions, List::[term()]) -> [term()]
-%%
-%% Expansions = [{property(), [term()]}]
-%%
%% @doc Expands particular properties to corresponding sets of
%% properties (or other terms). For each pair <code>{Property,
%% Expansion}</code> in <code>Expansions</code>, if <code>E</code> is
@@ -510,7 +497,9 @@ substitute_negations_1([], P) ->
%%
%% @see normalize/2
--spec expand(Expansions::expansions(), [term()]) -> [term()].
+-spec expand(Expansions, List) -> List when
+ Expansions :: [{Property :: property(), Expansion :: [term()]}],
+ List :: [term()].
expand(Es, Ps) when is_list(Ps) ->
Es1 = [{property(P), V} || {P, V} <- Es],
@@ -589,15 +578,6 @@ flatten([]) ->
%% ---------------------------------------------------------------------
-%% @spec normalize(List::[term()], Stages::[Operation]) -> [term()]
-%%
-%% Operation = {aliases, Aliases} | {negations, Negations}
-%% | {expand, Expansions}
-%% Aliases = [{Key, Key}]
-%% Negations = [{Key, Key}]
-%% Key = term()
-%% Expansions = [{property(), [term()]}]
-%%
%% @doc Passes <code>List</code> through a sequence of
%% substitution/expansion stages. For an <code>aliases</code> operation,
%% the function <code>substitute_aliases/2</code> is applied using the
@@ -619,11 +599,15 @@ flatten([]) ->
%% @see expand/2
%% @see compact/1
--type operation() :: {'aliases', aliases()}
- | {'negations', negations()}
- | {'expand', expansions()}.
-
--spec normalize(List::[term()], Stages::[operation()]) -> [term()].
+-spec normalize(List, Stages) -> List when
+ List :: [term()],
+ Stages :: [Operation],
+ Operation :: {'aliases', Aliases}
+ | {'negations', Negations}
+ | {'expand', Expansions},
+ Aliases :: [{Key, Key}],
+ Negations :: [{Key, Key}],
+ Expansions :: [{Property :: property(), Expansion :: [term()]}].
normalize(L, [{aliases, As} | Xs]) ->
normalize(substitute_aliases(As, L), Xs);
@@ -636,10 +620,6 @@ normalize(L, []) ->
%% ---------------------------------------------------------------------
-%% @spec split(List::[term()], Keys::[term()]) -> {Lists, Rest}
-%% Lists = [[term()]]
-%% Rest = [term()]
-%%
%% @doc Partitions <code>List</code> into a list of sublists and a
%% remainder. <code>Lists</code> contains one sublist for each key in
%% <code>Keys</code>, in the corresponding order. The relative order of
@@ -654,7 +634,11 @@ normalize(L, []) ->
%% {[[a], [{b, 5}, b],[{c, 2}, {c, 3, 4}]], [{e, 1}, d]}</pre>
%% </p>
--spec split(List::[term()], Keys::[term()]) -> {[[term()]], [term()]}.
+-spec split(List, Keys) -> {Lists, Rest} when
+ List :: [term()],
+ Keys :: [term()],
+ Lists :: [[term()]],
+ Rest :: [term()].
split(List, Keys) ->
{Store, Rest} = split(List, dict:from_list([{K, []} || K <- Keys]), []),
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index bc6944e520..f5e180b4bd 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -60,7 +60,7 @@
-record(qlc_table, % qlc:table/2
{trav_fun, % traverse fun
- trav_MS, % bool(); true iff traverse fun takes a match spec
+ trav_MS, % boolean(); true iff traverse fun takes a match spec
pre_fun,
post_fun,
info_fun,
@@ -110,12 +110,12 @@
-record(qlc_cursor, {c}).
-record(qlc_opt,
- {unique = false, % bool()
- cache = false, % bool() | list (true~ets, false~no)
+ {unique = false, % boolean()
+ cache = false, % boolean() | list (true~ets, false~no)
max_lookup = -1, % int() >= 0 | -1 (represents infinity)
join = any, % any | nested_loop | merge | lookup
tmpdir = "", % global tmpdir
- lookup = any, % any | bool()
+ lookup = any, % any | boolean()
max_list = ?MAX_LIST_SIZE, % int() >= 0
tmpdir_usage = allowed % allowed | not_allowed
% | warning_msg | error_msg | info_msg
@@ -123,7 +123,9 @@
-record(setup, {parent}).
--define(THROWN_ERROR, {?MODULE, throw_error, _}).
+-define(THROWN_ERROR, {?MODULE, throw_error, _, _}).
+
+-export_type([query_handle/0]).
%%% A query handle is a tuple {qlc_handle, Handle} where Handle is one
%%% of #qlc_append, #qlc_table, #qlc_sort, and #qlc_lc.
@@ -144,6 +146,35 @@ get_handle(_) ->
%%% Exported functions
%%%
+-type(query_list_comprehension() :: term()).
+-opaque(query_cursor() :: {qlc_cursor, term()}).
+-opaque(query_handle() :: {qlc_handle, term()}).
+-type(query_handle_or_list() :: query_handle() | list()).
+-type(answers() :: [answer()]).
+-type(answer() :: term()).
+-type(abstract_expr() :: erl_parse:abstract_expr()).
+-type(match_expression() :: ets:match_spec()).
+-type(spawn_options() :: default | [proc_lib:spawn_option()]).
+-type(sort_options() :: [sort_option()] | sort_option()).
+-type(sort_option() :: {compressed, boolean()}
+ | {no_files, no_files()}
+ | {order, order()}
+ | {size, pos_integer()}
+ | {tmpdir, tmp_directory()}
+ | {unique, boolean()}).
+-type(order() :: ascending | descending | order_fun()).
+-type(order_fun() :: fun((term(), term()) -> boolean())).
+-type(tmp_directory() :: [] | file:name()).
+-type(no_files() :: pos_integer()). % > 1
+-type(key_pos() :: pos_integer() | [pos_integer()]).
+-type(max_list_size() :: non_neg_integer()).
+-type(cache() :: ets | list | no).
+-type(tmp_file_usage() :: allowed | not_allowed | info_msg
+ | warning_msg | error_msg).
+
+-spec(append(QHL) -> QH when
+ QHL :: [query_handle_or_list()],
+ QH :: query_handle()).
append(QHs) ->
Hs = [case get_handle(QH) of
badarg -> erlang:error(badarg, [QHs]);
@@ -151,6 +182,10 @@ append(QHs) ->
end || QH <- QHs],
#qlc_handle{h = #qlc_append{hl = Hs}}.
+-spec(append(QH1, QH2) -> QH3 when
+ QH1 :: query_handle_or_list(),
+ QH2 :: query_handle_or_list(),
+ QH3 :: query_handle()).
append(QH1, QH2) ->
Hs = [case get_handle(QH) of
badarg -> erlang:error(badarg, [QH1, QH2]);
@@ -158,9 +193,22 @@ append(QH1, QH2) ->
end || QH <- [QH1, QH2]],
#qlc_handle{h = #qlc_append{hl = Hs}}.
+-spec(cursor(QH) -> Cursor when
+ QH :: query_handle_or_list(),
+ Cursor :: query_cursor()).
cursor(QH) ->
cursor(QH, []).
+-spec(cursor(QH, Options) -> Cursor when
+ QH :: query_handle_or_list(),
+ Options :: [Option] | Option,
+ Option :: {cache_all, cache()} | cache_all
+ | {max_list_size, max_list_size()}
+ | {spawn_options, spawn_options()}
+ | {tmpdir_usage, tmp_file_usage()}
+ | {tmpdir, tmp_directory()}
+ | {unique_all, boolean()} | unique_all,
+ Cursor :: query_cursor()).
cursor(QH, Options) ->
case {options(Options, [unique_all, cache_all, tmpdir,
spawn_options, max_list_size,
@@ -179,6 +227,8 @@ cursor(QH, Options) ->
end
end.
+-spec(delete_cursor(QueryCursor) -> ok when
+ QueryCursor :: query_cursor()).
delete_cursor(#qlc_cursor{c = {_, Owner}}=C) when Owner =/= self() ->
erlang:error(not_cursor_owner, [C]);
delete_cursor(#qlc_cursor{c = {Pid, _}}) ->
@@ -186,15 +236,47 @@ delete_cursor(#qlc_cursor{c = {Pid, _}}) ->
delete_cursor(T) ->
erlang:error(badarg, [T]).
+-spec(e(QH) -> Answers | Error when
+ QH :: query_handle_or_list(),
+ Answers :: answers(),
+ Error :: {error, module(), Reason},
+ Reason :: file_sorter:reason()).
e(QH) ->
eval(QH, []).
+-spec(e(QH, Options) -> Answers | Error when
+ QH :: query_handle_or_list(),
+ Options :: [Option] | Option,
+ Option :: {cache_all, cache()} | cache_all
+ | {max_list_size, max_list_size()}
+ | {tmpdir_usage, tmp_file_usage()}
+ | {tmpdir, tmp_directory()}
+ | {unique_all, boolean()} | unique_all,
+ Answers :: answers(),
+ Error :: {error, module(), Reason},
+ Reason :: file_sorter:reason()).
e(QH, Options) ->
eval(QH, Options).
+-spec(eval(QH) -> Answers | Error when
+ QH :: query_handle_or_list(),
+ Answers :: answers(),
+ Error :: {error, module(), Reason},
+ Reason :: file_sorter:reason()).
eval(QH) ->
eval(QH, []).
+-spec(eval(QH, Options) -> Answers | Error when
+ QH :: query_handle_or_list(),
+ Answers :: answers(),
+ Options :: [Option] | Option,
+ Option :: {cache_all, cache()} | cache_all
+ | {max_list_size, max_list_size()}
+ | {tmpdir_usage, tmp_file_usage()}
+ | {tmpdir, tmp_directory()}
+ | {unique_all, boolean()} | unique_all,
+ Error :: {error, module(), Reason},
+ Reason :: file_sorter:reason()).
eval(QH, Options) ->
case {options(Options, [unique_all, cache_all, tmpdir, max_list_size,
tmpdir_usage]),
@@ -226,9 +308,35 @@ eval(QH, Options) ->
end
end.
+-spec(fold(Function, Acc0, QH) ->
+ Acc1 | Error when
+ QH :: query_handle_or_list(),
+ Function :: fun((answer(), AccIn) -> AccOut),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ Error :: {error, module(), Reason},
+ Reason :: file_sorter:reason()).
fold(Fun, Acc0, QH) ->
fold(Fun, Acc0, QH, []).
+-spec(fold(Function, Acc0, QH, Options) ->
+ Acc1 | Error when
+ QH :: query_handle_or_list(),
+ Function :: fun((answer(), AccIn) -> AccOut),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ Options :: [Option] | Option,
+ Option :: {cache_all, cache()} | cache_all
+ | {max_list_size, max_list_size()}
+ | {tmpdir_usage, tmp_file_usage()}
+ | {tmpdir, tmp_directory()}
+ | {unique_all, boolean()} | unique_all,
+ Error :: {error, module(), Reason},
+ Reason :: file_sorter:reason()).
fold(Fun, Acc0, QH, Options) ->
case {options(Options, [unique_all, cache_all, tmpdir, max_list_size,
tmpdir_usage]),
@@ -258,6 +366,9 @@ fold(Fun, Acc0, QH, Options) ->
end
end.
+-spec(format_error(Error) -> Chars when
+ Error :: {error, module(), term()},
+ Chars :: io_lib:chars()).
format_error(not_a_query_list_comprehension) ->
io_lib:format("argument is not a query list comprehension", []);
format_error({used_generator_variable, V}) ->
@@ -295,9 +406,29 @@ format_error({error, Module, Reason}) ->
format_error(E) ->
io_lib:format("~p~n", [E]).
+-spec(info(QH) -> Info when
+ QH :: query_handle_or_list(),
+ Info :: abstract_expr() | string()).
info(QH) ->
info(QH, []).
+-spec(info(QH, Options) -> Info when
+ QH :: query_handle_or_list(),
+ Options :: [Option] | Option,
+ Option :: EvalOption | ReturnOption,
+ EvalOption :: {cache_all, cache()} | cache_all
+ | {max_list_size, max_list_size()}
+ | {tmpdir_usage, tmp_file_usage()}
+ | {tmpdir, tmp_directory()}
+ | {unique_all, boolean()} | unique_all,
+ ReturnOption :: {depth, Depth}
+ | {flat, boolean()}
+ | {format, Format}
+ | {n_elements, NElements},
+ Depth :: infinity | non_neg_integer(),
+ Format :: abstract_code | string,
+ NElements :: infinity | pos_integer(),
+ Info :: abstract_expr() | string()).
info(QH, Options) ->
case {options(Options, [unique_all, cache_all, flat, format, n_elements,
depth, tmpdir, max_list_size, tmpdir_usage]),
@@ -333,9 +464,18 @@ info(QH, Options) ->
end
end.
+-spec(keysort(KeyPos, QH1) -> QH2 when
+ KeyPos :: key_pos(),
+ QH1 :: query_handle_or_list(),
+ QH2 :: query_handle()).
keysort(KeyPos, QH) ->
keysort(KeyPos, QH, []).
+-spec(keysort(KeyPos, QH1, SortOptions) -> QH2 when
+ KeyPos :: key_pos(),
+ SortOptions :: sort_options(),
+ QH1 :: query_handle_or_list(),
+ QH2 :: query_handle()).
keysort(KeyPos, QH, Options) ->
case {is_keypos(KeyPos),
options(Options, [tmpdir, order, unique, compressed,
@@ -354,9 +494,22 @@ keysort(KeyPos, QH, Options) ->
-define(DEFAULT_NUM_OF_ANSWERS, 10).
+-spec(next_answers(QueryCursor) ->
+ Answers | Error when
+ QueryCursor :: query_cursor(),
+ Answers :: answers(),
+ Error :: {error, module(), Reason},
+ Reason :: file_sorter:reason()).
next_answers(C) ->
next_answers(C, ?DEFAULT_NUM_OF_ANSWERS).
+-spec(next_answers(QueryCursor, NumberOfAnswers) ->
+ Answers | Error when
+ QueryCursor :: query_cursor(),
+ Answers :: answers(),
+ NumberOfAnswers :: all_remaining | pos_integer(),
+ Error :: {error, module(), Reason},
+ Reason :: file_sorter:reason()).
next_answers(#qlc_cursor{c = {_, Owner}}=C,
NumOfAnswers) when Owner =/= self() ->
erlang:error(not_cursor_owner, [C, NumOfAnswers]);
@@ -370,14 +523,35 @@ next_answers(#qlc_cursor{c = {Pid, _}}=C, NumOfAnswers) ->
next_answers(T1, T2) ->
erlang:error(badarg, [T1, T2]).
+-spec(parse_transform(Forms, Options) -> Forms2 when
+ Forms :: [erl_parse:abstract_form()],
+ Forms2 :: [erl_parse:abstract_form()],
+ Options :: [Option],
+ Option :: type_checker | compile:option()).
+
parse_transform(Forms, Options) ->
qlc_pt:parse_transform(Forms, Options).
%% The funcspecs qlc:q/1 and qlc:q/2 are known by erl_eval.erl and
%% erl_lint.erl.
+-spec(q(QLC) -> QH when
+ QLC :: query_list_comprehension(),
+ QH :: query_handle()).
q(QLC_lc) ->
q(QLC_lc, []).
+-spec(q(QLC, Options) -> QH when
+ QH :: query_handle(),
+ Options :: [Option] | Option,
+ Option :: {max_lookup, MaxLookup}
+ | {cache, cache()} | cache
+ | {join, Join}
+ | {lookup, Lookup}
+ | {unique, boolean()} | unique,
+ MaxLookup :: non_neg_integer() | infinity,
+ Join :: any | lookup | merge | nested_loop,
+ Lookup :: boolean() | any,
+ QLC :: query_list_comprehension()).
q(#qlc_lc{}=QLC_lc, Options) ->
case options(Options, [unique, cache, max_lookup, join, lookup]) of
[Unique, Cache, Max, Join, Lookup] ->
@@ -390,9 +564,16 @@ q(#qlc_lc{}=QLC_lc, Options) ->
q(T1, T2) ->
erlang:error(badarg, [T1, T2]).
+-spec(sort(QH1) -> QH2 when
+ QH1 :: query_handle_or_list(),
+ QH2 :: query_handle()).
sort(QH) ->
sort(QH, []).
+-spec(sort(QH1, SortOptions) -> QH2 when
+ SortOptions :: sort_options(),
+ QH1 :: query_handle_or_list(),
+ QH2 :: query_handle()).
sort(QH, Options) ->
case {options(Options, [tmpdir, order, unique, compressed,
size, no_files]), get_handle(QH)} of
@@ -406,14 +587,47 @@ sort(QH, Options) ->
end.
%% Note that the generated code is evaluated by (the slow) erl_eval.
+-spec(string_to_handle(QueryString) -> QH | Error when
+ QueryString :: string(),
+ QH :: query_handle(),
+ Error :: {error, module(), Reason},
+ Reason :: erl_parse:error_info() | erl_scan:error_info()).
string_to_handle(Str) ->
string_to_handle(Str, []).
+-spec(string_to_handle(QueryString, Options) -> QH | Error when
+ QueryString :: string(),
+ Options :: [Option] | Option,
+ Option :: {max_lookup, MaxLookup}
+ | {cache, cache()} | cache
+ | {join, Join}
+ | {lookup, Lookup}
+ | {unique, boolean()} | unique,
+ MaxLookup :: non_neg_integer() | infinity,
+ Join :: any | lookup | merge | nested_loop,
+ Lookup :: boolean() | any,
+ QH :: query_handle(),
+ Error :: {error, module(), Reason},
+ Reason :: erl_parse:error_info() | erl_scan:error_info()).
string_to_handle(Str, Options) ->
- string_to_handle(Str, Options, []).
-
-string_to_handle(Str, Options, Bindings) when is_list(Str),
- is_list(Bindings) ->
+ string_to_handle(Str, Options, erl_eval:new_bindings()).
+
+-spec(string_to_handle(QueryString, Options, Bindings) -> QH | Error when
+ QueryString :: string(),
+ Options :: [Option] | Option,
+ Option :: {max_lookup, MaxLookup}
+ | {cache, cache()} | cache
+ | {join, Join}
+ | {lookup, Lookup}
+ | {unique, boolean()} | unique,
+ MaxLookup :: non_neg_integer() | infinity,
+ Join :: any | lookup | merge | nested_loop,
+ Lookup :: boolean() | any,
+ Bindings :: erl_eval:binding_struct(),
+ QH :: query_handle(),
+ Error :: {error, module(), Reason},
+ Reason :: erl_parse:error_info() | erl_scan:error_info()).
+string_to_handle(Str, Options, Bindings) when is_list(Str) ->
case options(Options, [unique, cache, max_lookup, join, lookup]) of
badarg ->
erlang:error(badarg, [Str, Options, Bindings]);
@@ -447,6 +661,51 @@ string_to_handle(Str, Options, Bindings) when is_list(Str),
string_to_handle(T1, T2, T3) ->
erlang:error(badarg, [T1, T2, T3]).
+-spec(table(TraverseFun, Options) -> QH when
+ TraverseFun :: TraverseFun0 | TraverseFun1,
+ TraverseFun0 :: fun(() -> TraverseResult),
+ TraverseFun1 :: fun((match_expression()) -> TraverseResult),
+ TraverseResult :: Objects | term(),
+ Objects :: [] | [term() | ObjectList],
+ ObjectList :: TraverseFun0 | Objects,
+ Options :: [Option] | Option,
+ Option :: {format_fun, FormatFun}
+ | {info_fun, InfoFun}
+ | {lookup_fun, LookupFun}
+ | {parent_fun, ParentFun}
+ | {post_fun, PostFun}
+ | {pre_fun, PreFun}
+ | {key_equality, KeyComparison},
+ FormatFun :: undefined | fun((SelectedObjects) -> FormatedTable),
+ SelectedObjects :: all
+ | {all, NElements, DepthFun}
+ | {match_spec, match_expression()}
+ | {lookup, Position, Keys}
+ | {lookup, Position, Keys, NElements, DepthFun},
+ NElements :: infinity | pos_integer(),
+ DepthFun :: fun((term()) -> term()),
+ FormatedTable :: {Mod, Fun, Args}
+ | abstract_expr()
+ | string(),
+ InfoFun :: undefined | fun((InfoTag) -> InfoValue),
+ InfoTag :: indices | is_unique_objects | keypos | num_of_objects,
+ InfoValue :: undefined | term(),
+ LookupFun :: undefined | fun((Position, Keys) -> LookupResult),
+ LookupResult :: [term()] | term(),
+ ParentFun :: undefined | fun(() -> ParentFunValue),
+ PostFun :: undefined | fun(() -> term()),
+ PreFun :: undefined | fun((PreArgs) -> term()),
+ PreArgs :: [PreArg],
+ PreArg :: {parent_value, ParentFunValue} | {stop_fun, StopFun},
+ ParentFunValue :: undefined | term(),
+ StopFun :: undefined | fun(() -> term()),
+ KeyComparison :: '=:=' | '==',
+ Position :: pos_integer(),
+ Keys :: [term()],
+ Mod :: atom(),
+ Fun :: atom(),
+ Args :: [term()],
+ QH :: query_handle()).
table(TraverseFun, Options) when is_function(TraverseFun) ->
case {is_function(TraverseFun, 0),
IsFun1 = is_function(TraverseFun, 1)} of
@@ -472,6 +731,11 @@ table(TraverseFun, Options) when is_function(TraverseFun) ->
table(T1, T2) ->
erlang:error(badarg, [T1, T2]).
+-spec(transform_from_evaluator(LC, Bs) -> Expr when
+ LC :: abstract_expr(),
+ Expr :: abstract_expr(),
+ Bs :: erl_eval:binding_struct()).
+
transform_from_evaluator(LC, Bs0) ->
qlc_pt:transform_from_evaluator(LC, Bs0).
@@ -722,8 +986,8 @@ listify(T) ->
%% Optimizations to be carried out.
-record(optz,
- {unique = false, % bool()
- cache = false, % bool() | list
+ {unique = false, % boolean()
+ cache = false, % boolean() | list
join_option = any, % constraint set by the 'join' option
fast_join = no, % no | #qlc_join. 'no' means nested loop.
opt % #qlc_opt
@@ -756,8 +1020,8 @@ listify(T) ->
lu_skip_quals = [], % qualifiers to skip due to lookup
join = {[],[]}, % {Lookup, Merge}
n_objs = undefined, % for join (not used yet)
- is_unique_objects = false, % bool()
- is_cached = false % bool() (true means 'ets' or 'list')
+ is_unique_objects = false, % boolean()
+ is_cached = false % boolean() (true means 'ets' or 'list')
}).
%%% Cursor process functions.
@@ -1143,20 +1407,20 @@ monitor_request(Pid, Req) ->
%% QueryDesc = {qlc, TemplateDesc, [QualDesc], [QueryOpt]}
%% | {table, TableDesc}
%% | {append, [QueryDesc]}
-%% | {sort, QueryDesc, [SortOption]}
-%% | {keysort, KeyPos, QueryDesc, [SortOption]}
+%% | {sort, QueryDesc, [sort_option()]}
+%% | {keysort, key_pos(), QueryDesc, [sort_option()]}
%% | {list, list()}
-%% | {list, QueryDesc, MatchExpression}
+%% | {list, QueryDesc, match_expression()}
%% TableDesc = {Mod, Fun, Args}
-%% | AbstractExpression
-%% | character_list()
+%% | erl_parse:abstract_expr()
+%% | string()
%% Mod = module()
%% Fun = atom()
%% Args = [term()]
%% QualDesc = FilterDesc
%% | {generate, PatternDesc, QueryDesc}
-%% QueryOpt = {cache, bool()} | cache
-%% | {unique, bool()} | unique
+%% QueryOpt = {cache, boolean()} | cache
+%% | {unique, boolean()} | unique
%% FilterDesc = PatternDesc = TemplateDesc = binary()
le_info(#prepared{qh = #simple_qlc{le = LE, p = P, line = L, optz = Optz}},
@@ -3437,7 +3701,8 @@ lookup_join(F1, C1, LuF, C2, Rev) ->
maybe_error_logger(allowed, _) ->
ok;
maybe_error_logger(Name, Why) ->
- [_, _, {?MODULE,maybe_error_logger,_} | Stacktrace] = expand_stacktrace(),
+ [_, _, {?MODULE,maybe_error_logger,_,_} | Stacktrace] =
+ expand_stacktrace(),
Trimmer = fun(M, _F, _A) -> M =:= erl_eval end,
Formater = fun(Term, I) -> io_lib:print(Term, I, 80, -1) end,
X = lib:format_stacktrace(1, Stacktrace, Trimmer, Formater),
@@ -3456,7 +3721,7 @@ expand_stacktrace() ->
expand_stacktrace(D) ->
_ = erlang:system_flag(backtrace_depth, D),
{'EXIT', {foo, Stacktrace}} = (catch erlang:error(foo)),
- L = lists:takewhile(fun({M,_,_}) -> M =/= ?MODULE
+ L = lists:takewhile(fun({M,_,_,_}) -> M =/= ?MODULE
end, lists:reverse(Stacktrace)),
if
length(L) < 3 andalso length(Stacktrace) =:= D ->
diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl
index 24378a0698..21504d707b 100644
--- a/lib/stdlib/src/qlc_pt.erl
+++ b/lib/stdlib/src/qlc_pt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -63,6 +63,12 @@
%%% Exported functions
%%%
+-spec(parse_transform(Forms, Options) -> Forms2 when
+ Forms :: [erl_parse:abstract_form()],
+ Forms2 :: [erl_parse:abstract_form()],
+ Options :: [Option],
+ Option :: type_checker | compile:option()).
+
parse_transform(Forms, Options) ->
?DEBUG("qlc Parse Transform~n", []),
State = #state{imp = is_qlc_q_imported(Forms),
@@ -96,10 +102,20 @@ parse_transform(Forms, Options) ->
end
end.
+-spec(transform_from_evaluator(LC, Bs) -> Expr when
+ LC :: erl_parse:abstract_expr(),
+ Expr :: erl_parse:abstract_expr(),
+ Bs :: erl_eval:binding_struct()).
+
transform_from_evaluator(LC, Bindings) ->
?DEBUG("qlc Parse Transform (Evaluator Version)~n", []),
transform_expression(LC, Bindings, false).
+-spec(transform_expression(LC, Bs) -> Expr when
+ LC :: erl_parse:abstract_expr(),
+ Expr :: erl_parse:abstract_expr(),
+ Bs :: erl_eval:binding_struct()).
+
transform_expression(LC, Bindings) ->
transform_expression(LC, Bindings, true).
diff --git a/lib/stdlib/src/queue.erl b/lib/stdlib/src/queue.erl
index c09079e8d2..afe917b151 100644
--- a/lib/stdlib/src/queue.erl
+++ b/lib/stdlib/src/queue.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -56,14 +56,14 @@
new() -> {[],[]}. %{RearList,FrontList}
%% O(1)
--spec is_queue(term()) -> boolean().
+-spec is_queue(Term :: term()) -> boolean().
is_queue({R,F}) when is_list(R), is_list(F) ->
true;
is_queue(_) ->
false.
%% O(1)
--spec is_empty(queue()) -> boolean().
+-spec is_empty(Q :: queue()) -> boolean().
is_empty({[],[]}) ->
true;
is_empty({In,Out}) when is_list(In), is_list(Out) ->
@@ -72,14 +72,14 @@ is_empty(Q) ->
erlang:error(badarg, [Q]).
%% O(len(Q))
--spec len(queue()) -> non_neg_integer().
+-spec len(Q :: queue()) -> non_neg_integer().
len({R,F}) when is_list(R), is_list(F) ->
length(R)+length(F);
len(Q) ->
erlang:error(badarg, [Q]).
%% O(len(Q))
--spec to_list(queue()) -> list().
+-spec to_list(Q :: queue()) -> list().
to_list({In,Out}) when is_list(In), is_list(Out) ->
Out++lists:reverse(In, []);
to_list(Q) ->
@@ -88,7 +88,7 @@ to_list(Q) ->
%% Create queue from list
%%
%% O(length(L))
--spec from_list(list()) -> queue().
+-spec from_list(L :: list()) -> queue().
from_list(L) when is_list(L) ->
f2r(L);
from_list(L) ->
@@ -97,7 +97,7 @@ from_list(L) ->
%% Return true or false depending on if element is in queue
%%
%% O(length(Q)) worst case
--spec member(term(), queue()) -> boolean().
+-spec member(Item :: term(), Q :: queue()) -> boolean().
member(X, {R,F}) when is_list(R), is_list(F) ->
lists:member(X, R) orelse lists:member(X, F);
member(X, Q) ->
@@ -110,7 +110,7 @@ member(X, Q) ->
%% Put at least one element in each list, if it is cheap
%%
%% O(1)
--spec in(term(), queue()) -> queue().
+-spec in(Item :: term(), Q1 :: queue()) -> Q2 :: queue().
in(X, {[_]=In,[]}) ->
{[X], In};
in(X, {In,Out}) when is_list(In), is_list(Out) ->
@@ -122,7 +122,7 @@ in(X, Q) ->
%% Put at least one element in each list, if it is cheap
%%
%% O(1)
--spec in_r(term(), queue()) -> queue().
+-spec in_r(Item :: term(), Q1 :: queue()) -> Q2 :: queue().
in_r(X, {[],[_]=F}) ->
{F,[X]};
in_r(X, {R,F}) when is_list(R), is_list(F) ->
@@ -133,7 +133,9 @@ in_r(X, Q) ->
%% Take from head/front
%%
%% O(1) amortized, O(len(Q)) worst case
--spec out(queue()) -> {'empty' | {'value',term()}, queue()}.
+-spec out(Q1 :: queue()) ->
+ {{value, Item :: term()}, Q2 :: queue()} |
+ {empty, Q1 :: queue()}.
out({[],[]}=Q) ->
{empty,Q};
out({[V],[]}) ->
@@ -151,7 +153,9 @@ out(Q) ->
%% Take from tail/rear
%%
%% O(1) amortized, O(len(Q)) worst case
--spec out_r(queue()) -> {'empty' | {'value',term()}, queue()}.
+-spec out_r(Q1 :: queue()) ->
+ {{value, Item :: term()}, Q2 :: queue()} |
+ {empty, Q1 :: queue()}.
out_r({[],[]}=Q) ->
{empty,Q};
out_r({[],[V]}) ->
@@ -172,7 +176,7 @@ out_r(Q) ->
%% Return the first element in the queue
%%
%% O(1) since the queue is supposed to be well formed
--spec get(queue()) -> term().
+-spec get(Q :: queue()) -> Item :: term().
get({[],[]}=Q) ->
erlang:error(empty, [Q]);
get({R,F}) when is_list(R), is_list(F) ->
@@ -191,7 +195,7 @@ get([_|R], []) -> % malformed queue -> O(len(Q))
%% Return the last element in the queue
%%
%% O(1) since the queue is supposed to be well formed
--spec get_r(queue()) -> term().
+-spec get_r(Q :: queue()) -> Item :: term().
get_r({[],[]}=Q) ->
erlang:error(empty, [Q]);
get_r({[H|_],F}) when is_list(F) ->
@@ -206,7 +210,7 @@ get_r(Q) ->
%% Return the first element in the queue
%%
%% O(1) since the queue is supposed to be well formed
--spec peek(queue()) -> 'empty' | {'value',term()}.
+-spec peek(Q :: queue()) -> empty | {value,Item :: term()}.
peek({[],[]}) ->
empty;
peek({R,[H|_]}) when is_list(R) ->
@@ -221,7 +225,7 @@ peek(Q) ->
%% Return the last element in the queue
%%
%% O(1) since the queue is supposed to be well formed
--spec peek_r(queue()) -> 'empty' | {'value',term()}.
+-spec peek_r(Q :: queue()) -> empty | {value,Item :: term()}.
peek_r({[],[]}) ->
empty;
peek_r({[H|_],F}) when is_list(F) ->
@@ -236,7 +240,7 @@ peek_r(Q) ->
%% Remove the first element and return resulting queue
%%
%% O(1) amortized
--spec drop(queue()) -> queue().
+-spec drop(Q1 :: queue()) -> Q2 :: queue().
drop({[],[]}=Q) ->
erlang:error(empty, [Q]);
drop({[_],[]}) ->
@@ -254,7 +258,7 @@ drop(Q) ->
%% Remove the last element and return resulting queue
%%
%% O(1) amortized
--spec drop_r(queue()) -> queue().
+-spec drop_r(Q1 :: queue()) -> Q2 :: queue().
drop_r({[],[]}=Q) ->
erlang:error(empty, [Q]);
drop_r({[],[_]}) ->
@@ -275,7 +279,7 @@ drop_r(Q) ->
%% Return reversed queue
%%
%% O(1)
--spec reverse(queue()) -> queue().
+-spec reverse(Q1 :: queue()) -> Q2 :: queue().
reverse({R,F}) when is_list(R), is_list(F) ->
{F,R};
reverse(Q) ->
@@ -285,7 +289,7 @@ reverse(Q) ->
%%
%% Q2 empty: O(1)
%% else: O(len(Q1))
--spec join(queue(), queue()) -> queue().
+-spec join(Q1 :: queue(), Q2 :: queue()) -> Q3 :: queue().
join({R,F}=Q, {[],[]}) when is_list(R), is_list(F) ->
Q;
join({[],[]}, {R,F}=Q) when is_list(R), is_list(F) ->
@@ -299,7 +303,8 @@ join(Q1, Q2) ->
%%
%% N = 0..len(Q)
%% O(max(N, len(Q)))
--spec split(non_neg_integer(), queue()) -> {queue(),queue()}.
+-spec split(N :: non_neg_integer(), Q1 :: queue()) ->
+ {Q2 :: queue(),Q3 :: queue()}.
split(0, {R,F}=Q) when is_list(R), is_list(F) ->
{{[],[]},Q};
split(N, {R,F}=Q) when is_integer(N), N >= 1, is_list(R), is_list(F) ->
@@ -340,7 +345,8 @@ split_r1_to_f2(N, [X|R1], F1, R2, F2) ->
%%
%% Fun(_) -> List: O(length(List) * len(Q))
%% else: O(len(Q)
--spec filter(fun((term()) -> boolean() | list()), queue()) -> queue().
+-spec filter(Fun, Q1 :: queue()) -> Q2 :: queue() when
+ Fun :: fun((Item :: term()) -> boolean() | list()).
filter(Fun, {R0,F0}) when is_function(Fun, 1), is_list(R0), is_list(F0) ->
F = filter_f(Fun, F0),
R = filter_r(Fun, R0),
@@ -416,7 +422,7 @@ filter_r(Fun, [X|R0]) ->
%% Cons to head
%%
--spec cons(term(), queue()) -> queue().
+-spec cons(Item :: term(), Q1 :: queue()) -> Q2 :: queue().
cons(X, Q) ->
in_r(X, Q).
@@ -425,7 +431,7 @@ cons(X, Q) ->
%% Return the first element in the queue
%%
%% O(1) since the queue is supposed to be well formed
--spec head(queue()) -> term().
+-spec head(Q :: queue()) -> Item :: term().
head({[],[]}=Q) ->
erlang:error(empty, [Q]);
head({R,F}) when is_list(R), is_list(F) ->
@@ -435,7 +441,7 @@ head(Q) ->
%% Remove head element and return resulting queue
%%
--spec tail(queue()) -> queue().
+-spec tail(Q1 :: queue()) -> Q2 :: queue().
tail(Q) ->
drop(Q).
@@ -443,22 +449,22 @@ tail(Q) ->
%% Cons to tail
%%
--spec snoc(queue(), term()) -> queue().
+-spec snoc(Q1 :: queue(), Item :: term()) -> Q2 :: queue().
snoc(Q, X) ->
in(X, Q).
%% Return last element
--spec daeh(queue()) -> term().
+-spec daeh(Q :: queue()) -> Item :: term().
daeh(Q) -> get_r(Q).
--spec last(queue()) -> term().
+-spec last(Q :: queue()) -> Item :: term().
last(Q) -> get_r(Q).
%% Remove last element and return resulting queue
--spec liat(queue()) -> queue().
+-spec liat(Q1 :: queue()) -> Q2 :: queue().
liat(Q) -> drop_r(Q).
--spec lait(queue()) -> queue().
+-spec lait(Q1 :: queue()) -> Q2 :: queue().
lait(Q) -> drop_r(Q). %% Oops, mis-spelled 'tail' reversed. Forget this one.
--spec init(queue()) -> queue().
+-spec init(Q1 :: queue()) -> Q2 :: queue().
init(Q) -> drop_r(Q).
%%--------------------------------------------------------------------------
diff --git a/lib/stdlib/src/random.erl b/lib/stdlib/src/random.erl
index 606edbb1fb..d7b51a151c 100644
--- a/lib/stdlib/src/random.erl
+++ b/lib/stdlib/src/random.erl
@@ -57,7 +57,10 @@ seed() ->
%% seed({A1, A2, A3})
%% Seed random number generation
--spec seed({integer(), integer(), integer()}) -> 'undefined' | ran().
+-spec seed({A1, A2, A3}) -> 'undefined' | ran() when
+ A1 :: integer(),
+ A2 :: integer(),
+ A3 :: integer().
seed({A1, A2, A3}) ->
seed(A1, A2, A3).
@@ -65,7 +68,10 @@ seed({A1, A2, A3}) ->
%% seed(A1, A2, A3)
%% Seed random number generation
--spec seed(integer(), integer(), integer()) -> 'undefined' | ran().
+-spec seed(A1, A2, A3) -> 'undefined' | ran() when
+ A1 :: integer(),
+ A2 :: integer(),
+ A3 :: integer().
seed(A1, A2, A3) ->
seed_put({(abs(A1) rem (?PRIME1-1)) + 1, % Avoid seed numbers that are
@@ -99,7 +105,8 @@ uniform() ->
%% Given an integer N >= 1, uniform(N) returns a random integer
%% between 1 and N.
--spec uniform(pos_integer()) -> pos_integer().
+-spec uniform(N) -> pos_integer() when
+ N :: pos_integer().
uniform(N) when is_integer(N), N >= 1 ->
trunc(uniform() * N) + 1.
@@ -110,7 +117,9 @@ uniform(N) when is_integer(N), N >= 1 ->
%% uniform_s(State) -> {F, NewState}
%% Returns a random float between 0 and 1.
--spec uniform_s(ran()) -> {float(), ran()}.
+-spec uniform_s(State0) -> {float(), State1} when
+ State0 :: ran(),
+ State1 :: ran().
uniform_s({A1, A2, A3}) ->
B1 = (A1*171) rem ?PRIME1,
@@ -123,7 +132,10 @@ uniform_s({A1, A2, A3}) ->
%% Given an integer N >= 1, uniform(N) returns a random integer
%% between 1 and N.
--spec uniform_s(pos_integer(), ran()) -> {integer(), ran()}.
+-spec uniform_s(N, State0) -> {integer(), State1} when
+ N :: pos_integer(),
+ State0 :: ran(),
+ State1 :: ran().
uniform_s(N, State0) when is_integer(N), N >= 1 ->
{F, State1} = uniform_s(State0),
diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl
index e2cc9f57ce..99bcbd722e 100644
--- a/lib/stdlib/src/re.erl
+++ b/lib/stdlib/src/re.erl
@@ -19,15 +19,46 @@
-module(re).
-export([grun/3,urun/3,ucompile/2,replace/3,replace/4,split/2,split/3]).
+%-opaque mp() :: {re_pattern, _, _, _}.
+-type mp() :: {re_pattern, _, _, _}.
+
+-type nl_spec() :: cr | crlf | lf | anycrlf | any.
+
+-type compile_option() :: unicode | anchored | caseless | dollar_endonly
+ | dotall | extended | firstline | multiline
+ | no_auto_capture | dupnames | ungreedy
+ | {newline, nl_spec()}| bsr_anycrlf
+ | bsr_unicode.
+
%% Emulator builtins in this module:
%% re:compile/1
%% re:compile/2
%% re:run/2
%% re:run/3
+-spec split(Subject, RE) -> SplitList when
+ Subject :: iodata() | unicode:charlist(),
+ RE :: mp() | iodata(),
+ SplitList :: [iodata() | unicode:charlist()].
+
split(Subject,RE) ->
split(Subject,RE,[]).
+-spec split(Subject, RE, Options) -> SplitList when
+ Subject :: iodata() | unicode:charlist(),
+ RE :: mp() | iodata() | unicode:charlist(),
+ Options :: [ Option ],
+ Option :: anchored | global | notbol | noteol | notempty
+ | {offset, non_neg_integer()} | {newline, nl_spec()}
+ | bsr_anycrlf | bsr_unicode | {return, ReturnType}
+ | {parts, NumParts} | group | trim | CompileOpt,
+ NumParts :: non_neg_integer() | infinity,
+ ReturnType :: iodata | list | binary,
+ CompileOpt :: compile_option(),
+ SplitList :: [RetData] | [GroupedRetData],
+ GroupedRetData :: [RetData],
+ RetData :: iodata() | unicode:charlist() | binary() | list().
+
split(Subject,RE,Options) ->
try
{NewOpt,Convert,Unicode,Limit,Strip,Group} =
@@ -197,10 +228,26 @@ compile_split(Pat,Options0) when not is_tuple(Pat) ->
compile_split(_,_) ->
throw(badre).
+-spec replace(Subject, RE, Replacement) -> iodata() | unicode:charlist() when
+ Subject :: iodata() | unicode:charlist(),
+ RE :: mp() | iodata(),
+ Replacement :: iodata() | unicode:charlist().
replace(Subject,RE,Replacement) ->
replace(Subject,RE,Replacement,[]).
+-spec replace(Subject, RE, Replacement, Options) -> iodata() | unicode:charlist() when
+ Subject :: iodata() | unicode:charlist(),
+ RE :: mp() | iodata() | unicode:charlist(),
+ Replacement :: iodata() | unicode:charlist(),
+ Options :: [Option],
+ Option :: anchored | global | notbol | noteol | notempty
+ | {offset, non_neg_integer()} | {newline, NLSpec} | bsr_anycrlf
+ | bsr_unicode | {return, ReturnType} | CompileOpt,
+ ReturnType :: iodata | list | binary,
+ CompileOpt :: compile_option(),
+ NLSpec :: cr | crlf | lf | anycrlf | any.
+
replace(Subject,RE,Replacement,Options) ->
try
{NewOpt,Convert,Unicode} =
@@ -526,10 +573,10 @@ ucompile(RE,Options) ->
re:compile(unicode:characters_to_binary(RE,unicode),Options)
catch
error:AnyError ->
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,Loc}|Rest]}} =
(catch erlang:error(new_stacktrace,
[RE,Options])),
- erlang:raise(error,AnyError,[{Mod,compile,L}|Rest])
+ erlang:raise(error,AnyError,[{Mod,compile,L,Loc}|Rest])
end.
@@ -538,10 +585,10 @@ urun(Subject,RE,Options) ->
urun2(Subject,RE,Options)
catch
error:AnyError ->
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,Loc}|Rest]}} =
(catch erlang:error(new_stacktrace,
[Subject,RE,Options])),
- erlang:raise(error,AnyError,[{Mod,run,L}|Rest])
+ erlang:raise(error,AnyError,[{Mod,run,L,Loc}|Rest])
end.
urun2(Subject0,RE0,Options0) ->
@@ -578,20 +625,20 @@ grun(Subject,RE,{Options,NeedClean}) ->
grun2(Subject,RE,{Options,NeedClean})
catch
error:AnyError ->
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,Loc}|Rest]}} =
(catch erlang:error(new_stacktrace,
[Subject,RE,Options])),
- erlang:raise(error,AnyError,[{Mod,run,L}|Rest])
+ erlang:raise(error,AnyError,[{Mod,run,L,Loc}|Rest])
end;
grun(Subject,RE,{Options,NeedClean,OrigRE}) ->
try
grun2(Subject,RE,{Options,NeedClean})
catch
error:AnyError ->
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,Loc}|Rest]}} =
(catch erlang:error(new_stacktrace,
[Subject,OrigRE,Options])),
- erlang:raise(error,AnyError,[{Mod,run,L}|Rest])
+ erlang:raise(error,AnyError,[{Mod,run,L,Loc}|Rest])
end.
grun2(Subject,RE,{Options,NeedClean}) ->
diff --git a/lib/stdlib/src/regexp.erl b/lib/stdlib/src/regexp.erl
index 8f5994bbee..65f9ca247d 100644
--- a/lib/stdlib/src/regexp.erl
+++ b/lib/stdlib/src/regexp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,6 +37,9 @@
-import(string, [substr/2,substr/3]).
-import(lists, [reverse/1]).
+-type errordesc() :: term().
+-opaque regexp() :: term().
+
%% -type matchres() = {match,Start,Length} | nomatch | {error,E}.
%% -type subres() = {ok,RepString,RepCount} | {error,E}.
%% -type splitres() = {ok,[SubString]} | {error,E}.
@@ -287,6 +290,10 @@ re_apply_or(R1, nomatch) -> R1.
%% Convert a sh style regexp into a full AWK one. The main difficulty is
%% getting character sets right as the conventions are different.
+-spec sh_to_awk(ShRegExp) -> AwkRegExp when
+ ShRegExp :: string(),
+ AwkRegExp :: string().
+
sh_to_awk(Sh) -> "^(" ++ sh_to_awk_1(Sh). %Fix the beginning
sh_to_awk_1([$*|Sh]) -> %This matches any string
@@ -336,6 +343,12 @@ special_char(_C) -> false.
%% parse(RegExp) -> {ok,RE} | {error,E}.
%% Parse the regexp described in the string RegExp.
+-spec parse(RegExp) -> ParseRes when
+ RegExp :: string(),
+ ParseRes :: {ok, RE} | {error, Error},
+ RE :: regexp(),
+ Error :: errordesc().
+
parse(S) ->
case catch reg(S) of
{R,[]} -> {ok,R};
@@ -345,6 +358,10 @@ parse(S) ->
%% format_error(Error) -> String.
+-spec format_error(ErrorDescriptor) -> Chars when
+ ErrorDescriptor :: errordesc(),
+ Chars :: io_lib:chars().
+
format_error({illegal,What}) -> ["illegal character `",What,"'"];
format_error({unterminated,What}) -> ["unterminated `",What,"'"];
format_error({char_class,What}) ->
@@ -353,6 +370,14 @@ format_error({char_class,What}) ->
%% -type match(String, RegExp) -> matchres().
%% Find the longest match of RegExp in String.
+-spec match(String, RegExp) -> MatchRes when
+ String :: string(),
+ RegExp :: string() | regexp(),
+ MatchRes :: {match, Start, Length} | nomatch | {error, Error},
+ Start :: pos_integer(),
+ Length :: pos_integer(),
+ Error :: errordesc().
+
match(S, RegExp) when is_list(RegExp) ->
case parse(RegExp) of
{ok,RE} -> match(S, RE);
@@ -378,6 +403,14 @@ match(RE, S, St, Pos, L) ->
%% -type first_match(String, RegExp) -> matchres().
%% Find the first match of RegExp in String.
+-spec first_match(String, RegExp) -> MatchRes when
+ String :: string(),
+ RegExp :: string() | regexp(),
+ MatchRes :: {match, Start, Length} | nomatch | {error, Error},
+ Start :: pos_integer(),
+ Length :: pos_integer(),
+ Error :: errordesc().
+
first_match(S, RegExp) when is_list(RegExp) ->
case parse(RegExp) of
{ok,RE} -> first_match(S, RE);
@@ -400,6 +433,15 @@ first_match(_RE, [], _St) -> nomatch.
%% -type matches(String, RegExp) -> {match,[{Start,Length}]} | {error,E}.
%% Return the all the non-overlapping matches of RegExp in String.
+-spec matches(String, RegExp) -> MatchRes when
+ String :: string(),
+ RegExp :: string() | regexp(),
+ MatchRes :: {match, Matches} | {error, Error},
+ Matches :: [{Start, Length}],
+ Start :: pos_integer(),
+ Length :: pos_integer(),
+ Error :: errordesc().
+
matches(S, RegExp) when is_list(RegExp) ->
case parse(RegExp) of
{ok,RE} -> matches(S, RE);
@@ -420,6 +462,15 @@ matches(S, RE, St) ->
%% the string Replace in String. Accept pre-parsed regular
%% expressions.
+-spec sub(String, RegExp, New) -> SubRes when
+ String :: string(),
+ RegExp :: string() | regexp(),
+ New :: string(),
+ NewString :: string(),
+ SubRes :: {ok, NewString, RepCount} | {error, Error},
+ RepCount :: 0 | 1,
+ Error :: errordesc().
+
sub(String, RegExp, Rep) when is_list(RegExp) ->
case parse(RegExp) of
{ok,RE} -> sub(String, RE, Rep);
@@ -449,6 +500,15 @@ sub_repl([], _M, Rest) -> Rest.
%% Substitute every match of the regular expression RegExp with the
%% string New in String. Accept pre-parsed regular expressions.
+-spec gsub(String, RegExp, New) -> SubRes when
+ String :: string(),
+ RegExp :: string() | regexp(),
+ New :: string(),
+ NewString :: string(),
+ SubRes :: {ok, NewString, RepCount} | {error, Error},
+ RepCount :: non_neg_integer(),
+ Error :: errordesc().
+
gsub(String, RegExp, Rep) when is_list(RegExp) ->
case parse(RegExp) of
{ok,RE} -> gsub(String, RE, Rep);
@@ -462,6 +522,13 @@ gsub(String, RE, Rep) ->
%% Split a string into substrings where the RegExp describes the
%% field seperator. The RegExp " " is specially treated.
+-spec split(String, RegExp) -> SplitRes when
+ String :: string(),
+ RegExp :: string() | regexp(),
+ SplitRes :: {ok, FieldList} | {error, Error},
+ FieldList :: [string()],
+ Error :: errordesc().
+
split(String, " ") -> %This is really special
{ok,RE} = parse("[ \t]+"),
case split_apply(String, RE, true) of
diff --git a/lib/stdlib/src/sets.erl b/lib/stdlib/src/sets.erl
index bcddca2567..3fd6c81e5f 100644
--- a/lib/stdlib/src/sets.erl
+++ b/lib/stdlib/src/sets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -84,30 +84,38 @@ new() ->
%% is_set(Set) -> boolean().
%% Return 'true' if Set is a set of elements, else 'false'.
--spec is_set(term()) -> boolean().
+-spec is_set(Set) -> boolean() when
+ Set :: term().
is_set(#set{}) -> true;
is_set(_) -> false.
%% size(Set) -> int().
%% Return the number of elements in Set.
--spec size(set()) -> non_neg_integer().
+-spec size(Set) -> non_neg_integer() when
+ Set :: set().
size(S) -> S#set.size.
%% to_list(Set) -> [Elem].
%% Return the elements in Set as a list.
--spec to_list(set()) -> [term()].
+-spec to_list(Set) -> List when
+ Set :: set(),
+ List :: [term()].
to_list(S) ->
fold(fun (Elem, List) -> [Elem|List] end, [], S).
%% from_list([Elem]) -> Set.
%% Build a set from the elements in List.
--spec from_list([term()]) -> set().
+-spec from_list(List) -> Set when
+ List :: [term()],
+ Set :: set().
from_list(L) ->
lists:foldl(fun (E, S) -> add_element(E, S) end, new(), L).
%% is_element(Element, Set) -> boolean().
%% Return 'true' if Element is an element of Set, else 'false'.
--spec is_element(term(), set()) -> boolean().
+-spec is_element(Element, Set) -> boolean() when
+ Element :: term(),
+ Set :: set().
is_element(E, S) ->
Slot = get_slot(S, E),
Bkt = get_bucket(S, Slot),
@@ -115,7 +123,10 @@ is_element(E, S) ->
%% add_element(Element, Set) -> Set.
%% Return Set with Element inserted in it.
--spec add_element(term(), set()) -> set().
+-spec add_element(Element, Set1) -> Set2 when
+ Element :: term(),
+ Set1 :: set(),
+ Set2 :: set().
add_element(E, S0) ->
Slot = get_slot(S0, E),
{S1,Ic} = on_bucket(fun (B0) -> add_bkt_el(E, B0, B0) end, S0, Slot),
@@ -129,7 +140,10 @@ add_bkt_el(E, [], Bkt) -> {[E|Bkt],1}.
%% del_element(Element, Set) -> Set.
%% Return Set but with Element removed.
--spec del_element(term(), set()) -> set().
+-spec del_element(Element, Set1) -> Set2 when
+ Element :: term(),
+ Set1 :: set(),
+ Set2 :: set().
del_element(E, S0) ->
Slot = get_slot(S0, E),
{S1,Dc} = on_bucket(fun (B0) -> del_bkt_el(E, B0) end, S0, Slot),
@@ -144,7 +158,10 @@ del_bkt_el(_, []) -> {[],0}.
%% union(Set1, Set2) -> Set
%% Return the union of Set1 and Set2.
--spec union(set(), set()) -> set().
+-spec union(Set1, Set2) -> Set3 when
+ Set1 :: set(),
+ Set2 :: set(),
+ Set3 :: set().
union(S1, S2) when S1#set.size < S2#set.size ->
fold(fun (E, S) -> add_element(E, S) end, S2, S1);
union(S1, S2) ->
@@ -152,7 +169,9 @@ union(S1, S2) ->
%% union([Set]) -> Set
%% Return the union of the list of sets.
--spec union([set()]) -> set().
+-spec union(SetList) -> Set when
+ SetList :: [set()],
+ Set :: set().
union([S1,S2|Ss]) ->
union1(union(S1, S2), Ss);
union([S]) -> S;
@@ -165,7 +184,10 @@ union1(S1, []) -> S1.
%% intersection(Set1, Set2) -> Set.
%% Return the intersection of Set1 and Set2.
--spec intersection(set(), set()) -> set().
+-spec intersection(Set1, Set2) -> Set3 when
+ Set1 :: set(),
+ Set2 :: set(),
+ Set3 :: set().
intersection(S1, S2) when S1#set.size < S2#set.size ->
filter(fun (E) -> is_element(E, S2) end, S1);
intersection(S1, S2) ->
@@ -173,7 +195,9 @@ intersection(S1, S2) ->
%% intersection([Set]) -> Set.
%% Return the intersection of the list of sets.
--spec intersection([set(),...]) -> set().
+-spec intersection(SetList) -> Set when
+ SetList :: [set(),...],
+ Set :: set().
intersection([S1,S2|Ss]) ->
intersection1(intersection(S1, S2), Ss);
intersection([S]) -> S.
@@ -185,7 +209,9 @@ intersection1(S1, []) -> S1.
%% is_disjoint(Set1, Set2) -> boolean().
%% Check whether Set1 and Set2 are disjoint.
--spec is_disjoint(set(), set()) -> boolean().
+-spec is_disjoint(Set1, Set2) -> boolean() when
+ Set1 :: set(),
+ Set2 :: set().
is_disjoint(S1, S2) when S1#set.size < S2#set.size ->
fold(fun (_, false) -> false;
(E, true) -> not is_element(E, S2)
@@ -198,25 +224,39 @@ is_disjoint(S1, S2) ->
%% subtract(Set1, Set2) -> Set.
%% Return all and only the elements of Set1 which are not also in
%% Set2.
--spec subtract(set(), set()) -> set().
+-spec subtract(Set1, Set2) -> Set3 when
+ Set1 :: set(),
+ Set2 :: set(),
+ Set3 :: set().
subtract(S1, S2) ->
filter(fun (E) -> not is_element(E, S2) end, S1).
%% is_subset(Set1, Set2) -> boolean().
%% Return 'true' when every element of Set1 is also a member of
%% Set2, else 'false'.
--spec is_subset(set(), set()) -> boolean().
+-spec is_subset(Set1, Set2) -> boolean() when
+ Set1 :: set(),
+ Set2 :: set().
is_subset(S1, S2) ->
fold(fun (E, Sub) -> Sub andalso is_element(E, S2) end, true, S1).
%% fold(Fun, Accumulator, Set) -> Accumulator.
%% Fold function Fun over all elements in Set and return Accumulator.
--spec fold(fun((_,_) -> _), T, set()) -> T.
+-spec fold(Function, Acc0, Set) -> Acc1 when
+ Function :: fun((E :: term(),AccIn) -> AccOut),
+ Set :: set(),
+ Acc0 :: T,
+ Acc1 :: T,
+ AccIn :: T,
+ AccOut :: T.
fold(F, Acc, D) -> fold_set(F, Acc, D).
%% filter(Fun, Set) -> Set.
%% Filter Set with Fun.
--spec filter(fun((_) -> boolean()), set()) -> set().
+-spec filter(Pred, Set1) -> Set2 when
+ Pred :: fun((E :: term()) -> boolean()),
+ Set1 :: set(),
+ Set2 :: set().
filter(F, D) -> filter_set(F, D).
%% get_slot(Hashdb, Key) -> Slot.
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index ebb221c151..964697cae6 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -115,7 +115,9 @@ whereis_evaluator(Shell) ->
%% Call this function to start a user restricted shell
%% from a normal shell session.
--spec start_restricted(module()) -> {'error', code:load_error_rsn()}.
+-spec start_restricted(Module) -> {'error', Reason} when
+ Module :: module(),
+ Reason :: code:load_error_rsn().
start_restricted(RShMod) when is_atom(RShMod) ->
case code:ensure_loaded(RShMod) of
@@ -465,7 +467,7 @@ getc(N) ->
{get({command,N}), get({result,N}), N}.
get_cmd(Num, C) ->
- case catch erl_eval:expr(Num, []) of
+ case catch erl_eval:expr(Num, erl_eval:new_bindings()) of
{value,N,_} when N < 0 -> getc(C+N);
{value,N,_} -> getc(N);
_Other -> {undefined,undefined,undefined}
@@ -1086,7 +1088,7 @@ shell_default(F,As,Bs) ->
end.
shell_undef(F,A) ->
- erlang:error({shell_undef,F,A}).
+ erlang:error({shell_undef,F,A,[]}).
local_func_handler(Shell, RT, Ef) ->
H = fun(Lf) ->
@@ -1184,6 +1186,8 @@ expr(E, Bs, Lf, Ef) ->
expr_list(Es, Bs, Lf, Ef) ->
erl_eval:expr_list(Es, strip_bindings(Bs), Lf, Ef).
+-spec strip_bindings(erl_eval:binding_struct()) -> erl_eval:binding_struct().
+
strip_bindings(Bs) ->
Bs -- [B || {{module,_},_}=B <- Bs].
@@ -1468,23 +1472,26 @@ set_env(App, Name, Val, Default) ->
application_controller:set_env(App, Name, Val),
Prev.
--spec history(non_neg_integer()) -> non_neg_integer().
+-spec history(N) -> non_neg_integer() when
+ N :: non_neg_integer().
history(L) when is_integer(L), L >= 0 ->
set_env(stdlib, shell_history_length, L, ?DEF_HISTORY).
--spec results(non_neg_integer()) -> non_neg_integer().
+-spec results(N) -> non_neg_integer() when
+ N :: non_neg_integer().
results(L) when is_integer(L), L >= 0 ->
set_env(stdlib, shell_saved_results, L, ?DEF_RESULTS).
--spec catch_exception(boolean()) -> boolean().
+-spec catch_exception(Bool) -> Bool when
+ Bool :: boolean().
catch_exception(Bool) ->
set_env(stdlib, shell_catch_exception, Bool, ?DEF_CATCH_EXCEPTION).
--type prompt_func() :: 'default' | {module(),atom()}.
--spec prompt_func(prompt_func()) -> prompt_func().
+-spec prompt_func(PromptFunc) -> PromptFunc when
+ PromptFunc :: 'default' | {module(),atom()}.
prompt_func(String) ->
set_env(stdlib, shell_prompt_func, String, ?DEF_PROMPT_FUNC).
diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl
index 196b659938..de0179da59 100644
--- a/lib/stdlib/src/slave.erl
+++ b/lib/stdlib/src/slave.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -54,6 +54,10 @@ pseudo([Master | ServerList]) ->
pseudo(_) ->
error_msg("No master node given to slave:pseudo/1~n",[]).
+-spec pseudo(Master, ServerList) -> ok when
+ Master :: node(),
+ ServerList :: [atom()].
+
pseudo(_, []) -> ok;
pseudo(Master, [S|Tail]) ->
start_pseudo(S, whereis(S), Master),
@@ -68,6 +72,9 @@ start_pseudo(_,_,_) -> ok. %% It's already there
%% This relay can be used to relay all messages directed to a process.
+-spec relay(Pid) -> no_return() when
+ Pid :: pid().
+
relay({badrpc,Reason}) ->
error_msg(" ** exiting relay server ~w :~w **~n", [self(),Reason]),
exit(Reason);
@@ -120,25 +127,61 @@ relay1(Pid) ->
%% {error, no_rsh} |
%% {error, {already_running, Name@Host}}
+-spec start(Host) -> {ok, Node} | {error, Reason} when
+ Host :: atom(),
+ Node :: node(),
+ Reason :: timeout | no_rsh | {already_running, Node}.
+
start(Host) ->
L = atom_to_list(node()),
Name = upto($@, L),
- start(Host, Name).
+ start(Host, Name, [], no_link).
+
+-spec start(Host, Name) -> {ok, Node} | {error, Reason} when
+ Host :: atom(),
+ Name :: atom(),
+ Node :: node(),
+ Reason :: timeout | no_rsh | {already_running, Node}.
start(Host, Name) ->
start(Host, Name, []).
+-spec start(Host, Name, Args) -> {ok, Node} | {error, Reason} when
+ Host :: atom(),
+ Name :: atom(),
+ Args :: string(),
+ Node :: node(),
+ Reason :: timeout | no_rsh | {already_running, Node}.
+
start(Host, Name, Args) ->
start(Host, Name, Args, no_link).
+-spec start_link(Host) -> {ok, Node} | {error, Reason} when
+ Host :: atom(),
+ Node :: node(),
+ Reason :: timeout | no_rsh | {already_running, Node}.
+
start_link(Host) ->
L = atom_to_list(node()),
Name = upto($@, L),
- start_link(Host, Name).
+ start(Host, Name, [], self()).
+
+-spec start_link(Host, Name) -> {ok, Node} | {error, Reason} when
+ Host :: atom(),
+ Name :: atom(),
+ Node :: node(),
+ Reason :: timeout | no_rsh | {already_running, Node}.
start_link(Host, Name) ->
start_link(Host, Name, []).
+-spec start_link(Host, Name, Args) -> {ok, Node} | {error, Reason} when
+ Host :: atom(),
+ Name :: atom(),
+ Args :: string(),
+ Node :: node(),
+ Reason :: timeout | no_rsh | {already_running, Node}.
+
start_link(Host, Name, Args) ->
start(Host, Name, Args, self()).
@@ -163,6 +206,9 @@ start(Host0, Name, Args, LinkTo, Prog) ->
%% Stops a running node.
+-spec stop(Node) -> ok when
+ Node :: node().
+
stop(Node) ->
% io:format("stop(~p)~n", [Node]),
rpc:call(Node, erlang, halt, []),
diff --git a/lib/stdlib/src/sofs.erl b/lib/stdlib/src/sofs.erl
index a83f803330..34eb224647 100644
--- a/lib/stdlib/src/sofs.erl
+++ b/lib/stdlib/src/sofs.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(sofs).
@@ -40,11 +40,11 @@
substitution/2, projection/2, partition/1, partition/2,
partition/3, multiple_relative_product/2, join/4]).
--export([family_to_relation/1, family_specification/2,
+-export([family_to_relation/1, family_specification/2,
union_of_family/1, intersection_of_family/1,
family_union/1, family_intersection/1,
family_domain/1, family_range/1, family_field/1,
- family_union/2, family_intersection/2, family_difference/2,
+ family_union/2, family_intersection/2, family_difference/2,
partition_family/2, family_projection/2]).
-export([family_to_digraph/1, family_to_digraph/2,
@@ -64,9 +64,9 @@
-compile({inline, [{external_fun,1},{element_type,1}]}).
--compile({inline,
+-compile({inline,
[{unify_types,2}, {match_types,2},
- {test_rel,3}, {symdiff,3},
+ {test_rel,3}, {symdiff,3},
{subst,3}]}).
-compile({inline, [{fam_binop,3}]}).
@@ -80,13 +80,14 @@
-define(TAG, 'Set').
-define(ORDTAG, 'OrdSet').
--record(?TAG, {data = [], type = type}).
--record(?ORDTAG, {orddata = {}, ordtype = type}).
+-record(?TAG, {data = [] :: list(), type = type :: term()}).
+-record(?ORDTAG, {orddata = {} :: tuple() | atom(),
+ ordtype = type :: term()}).
-define(LIST(S), (S)#?TAG.data).
-define(TYPE(S), (S)#?TAG.type).
-%%-define(SET(L, T),
-%% case is_type(T) of
+%%-define(SET(L, T),
+%% case is_type(T) of
%% true -> #?TAG{data = L, type = T};
%% false -> erlang:error(badtype, [T])
%% end
@@ -113,14 +114,40 @@
-define(IS_SET_OF(X), is_list(X)).
-define(FAMILY(X, Y), ?BINREL(X, ?SET_OF(Y))).
+-export_type([anyset/0, binary_relation/0, external_set/0, a_function/0,
+ family/0, relation/0, set_of_sets/0, set_fun/0, spec_fun/0,
+ type/0]).
+-export_type([ordset/0, a_set/0]).
+
+-type(anyset() :: ordset() | a_set()).
+-type(binary_relation() :: relation()).
+-type(external_set() :: term()).
+-type(a_function() :: relation()).
+-type(family() :: a_function()).
+-opaque(ordset() :: #?ORDTAG{}).
+-type(relation() :: a_set()).
+-opaque(a_set() :: #?TAG{}).
+-type(set_of_sets() :: a_set()).
+-type(set_fun() :: pos_integer()
+ | {external, fun((external_set()) -> external_set())}
+ | fun((anyset()) -> anyset())).
+-type(spec_fun() :: {external, fun((external_set()) -> boolean())}
+ | fun((anyset()) -> boolean())).
+-type(type() :: term()).
+
+-type(tuple_of(_T) :: tuple()).
+
%%
%% Exported functions
%%
-%%%
+%%%
%%% Create sets
-%%%
+%%%
+-spec(from_term(Term) -> AnySet when
+ AnySet :: anyset(),
+ Term :: term()).
from_term(T) ->
Type = case T of
_ when is_list(T) -> [?ANYTYPE];
@@ -133,6 +160,10 @@ from_term(T) ->
Set
end.
+-spec(from_term(Term, Type) -> AnySet when
+ AnySet :: anyset(),
+ Term :: term(),
+ Type :: type()).
from_term(L, T) ->
case is_type(T) of
true ->
@@ -146,14 +177,23 @@ from_term(L, T) ->
erlang:error(badarg, [L, T])
end.
+-spec(from_external(ExternalSet, Type) -> AnySet when
+ ExternalSet :: external_set(),
+ AnySet :: anyset(),
+ Type :: type()).
from_external(L, ?SET_OF(Type)) ->
?SET(L, Type);
from_external(T, Type) ->
?ORDSET(T, Type).
+-spec(empty_set() -> Set when
+ Set :: a_set()).
empty_set() ->
?SET([], ?ANYTYPE).
+-spec(is_type(Term) -> Bool when
+ Bool :: boolean(),
+ Term :: term()).
is_type(Atom) when ?IS_ATOM_TYPE(Atom), Atom =/= ?ANYTYPE ->
true;
is_type(?SET_OF(T)) ->
@@ -163,19 +203,26 @@ is_type(T) when tuple_size(T) > 0 ->
is_type(_T) ->
false.
+-spec(set(Terms) -> Set when
+ Set :: a_set(),
+ Terms :: [term()]).
set(L) ->
case catch usort(L) of
{'EXIT', _} ->
erlang:error(badarg, [L]);
- SL ->
+ SL ->
?SET(SL, ?ATOM_TYPE)
end.
+-spec(set(Terms, Type) -> Set when
+ Set :: a_set(),
+ Terms :: [term()],
+ Type :: type()).
set(L, ?SET_OF(Type) = T) when ?IS_ATOM_TYPE(Type), Type =/= ?ANYTYPE ->
case catch usort(L) of
{'EXIT', _} ->
erlang:error(badarg, [L, T]);
- SL ->
+ SL ->
?SET(SL, Type)
end;
set(L, ?SET_OF(_) = T) ->
@@ -188,6 +235,12 @@ set(L, ?SET_OF(_) = T) ->
set(L, T) ->
erlang:error(badarg, [L, T]).
+-spec(from_sets(ListOfSets) -> Set when
+ Set :: a_set(),
+ ListOfSets :: [anyset()];
+ (TupleOfSets) -> Ordset when
+ Ordset :: ordset(),
+ TupleOfSets :: tuple_of(anyset())).
from_sets(Ss) when is_list(Ss) ->
case set_of_sets(Ss, [], ?ANYTYPE) of
{error, Error} ->
@@ -205,6 +258,9 @@ from_sets(Tuple) when is_tuple(Tuple) ->
from_sets(T) ->
erlang:error(badarg, [T]).
+-spec(relation(Tuples) -> Relation when
+ Relation :: relation(),
+ Tuples :: [tuple()]).
relation([]) ->
?SET([], ?BINREL(?ATOM_TYPE, ?ATOM_TYPE));
relation(Ts = [T | _]) when is_tuple(T) ->
@@ -217,6 +273,11 @@ relation(Ts = [T | _]) when is_tuple(T) ->
relation(E) ->
erlang:error(badarg, [E]).
+-spec(relation(Tuples, Type) -> Relation when
+ N :: integer(),
+ Type :: N | type(),
+ Relation :: relation(),
+ Tuples :: [tuple()]).
relation(Ts, TS) ->
case catch rel(Ts, TS) of
{'EXIT', _} ->
@@ -225,6 +286,9 @@ relation(Ts, TS) ->
Set
end.
+-spec(a_function(Tuples) -> Function when
+ Function :: a_function(),
+ Tuples :: [tuple()]).
a_function(Ts) ->
case catch func(Ts, ?BINREL(?ATOM_TYPE, ?ATOM_TYPE)) of
{'EXIT', _} ->
@@ -235,6 +299,10 @@ a_function(Ts) ->
Set
end.
+-spec(a_function(Tuples, Type) -> Function when
+ Function :: a_function(),
+ Tuples :: [tuple()],
+ Type :: type()).
a_function(Ts, T) ->
case catch a_func(Ts, T) of
{'EXIT', _} ->
@@ -245,6 +313,9 @@ a_function(Ts, T) ->
Set
end.
+-spec(family(Tuples) -> Family when
+ Family :: family(),
+ Tuples :: [tuple()]).
family(Ts) ->
case catch fam2(Ts, ?FAMILY(?ATOM_TYPE, ?ATOM_TYPE)) of
{'EXIT', _} ->
@@ -255,6 +326,10 @@ family(Ts) ->
Set
end.
+-spec(family(Tuples, Type) -> Family when
+ Family :: family(),
+ Tuples :: [tuple()],
+ Type :: type()).
family(Ts, T) ->
case catch fam(Ts, T) of
{'EXIT', _} ->
@@ -265,20 +340,30 @@ family(Ts, T) ->
Set
end.
-%%%
+%%%
%%% Functions on sets.
-%%%
+%%%
+-spec(to_external(AnySet) -> ExternalSet when
+ ExternalSet :: external_set(),
+ AnySet :: anyset()).
to_external(S) when ?IS_SET(S) ->
?LIST(S);
to_external(S) when ?IS_ORDSET(S) ->
?ORDDATA(S).
+-spec(type(AnySet) -> Type when
+ AnySet :: anyset(),
+ Type :: type()).
type(S) when ?IS_SET(S) ->
?SET_OF(?TYPE(S));
type(S) when ?IS_ORDSET(S) ->
?ORDTYPE(S).
+-spec(to_sets(ASet) -> Sets when
+ ASet :: a_set() | ordset(),
+ Sets :: tuple_of(AnySet) | [AnySet],
+ AnySet :: anyset()).
to_sets(S) when ?IS_SET(S) ->
case ?TYPE(S) of
?SET_OF(Type) -> list_of_sets(?LIST(S), Type, []);
@@ -289,6 +374,9 @@ to_sets(S) when ?IS_ORDSET(S), is_tuple(?ORDTYPE(S)) ->
to_sets(S) when ?IS_ORDSET(S) ->
erlang:error(badarg, [S]).
+-spec(no_elements(ASet) -> NoElements when
+ ASet :: a_set() | ordset(),
+ NoElements :: non_neg_integer()).
no_elements(S) when ?IS_SET(S) ->
length(?LIST(S));
no_elements(S) when ?IS_ORDSET(S), is_tuple(?ORDTYPE(S)) ->
@@ -296,6 +384,10 @@ no_elements(S) when ?IS_ORDSET(S), is_tuple(?ORDTYPE(S)) ->
no_elements(S) when ?IS_ORDSET(S) ->
erlang:error(badarg, [S]).
+-spec(specification(Fun, Set1) -> Set2 when
+ Fun :: spec_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
specification(Fun, S) when ?IS_SET(S) ->
Type = ?TYPE(S),
R = case external_fun(Fun) of
@@ -311,36 +403,62 @@ specification(Fun, S) when ?IS_SET(S) ->
erlang:error(Bad, [Fun, S])
end.
+-spec(union(Set1, Set2) -> Set3 when
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
union(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
case unify_types(?TYPE(S1), ?TYPE(S2)) of
[] -> erlang:error(type_mismatch, [S1, S2]);
Type -> ?SET(umerge(?LIST(S1), ?LIST(S2)), Type)
end.
+-spec(intersection(Set1, Set2) -> Set3 when
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
intersection(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
case unify_types(?TYPE(S1), ?TYPE(S2)) of
[] -> erlang:error(type_mismatch, [S1, S2]);
Type -> ?SET(intersection(?LIST(S1), ?LIST(S2), []), Type)
end.
+-spec(difference(Set1, Set2) -> Set3 when
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
difference(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
case unify_types(?TYPE(S1), ?TYPE(S2)) of
[] -> erlang:error(type_mismatch, [S1, S2]);
Type -> ?SET(difference(?LIST(S1), ?LIST(S2), []), Type)
end.
+-spec(symdiff(Set1, Set2) -> Set3 when
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
symdiff(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
case unify_types(?TYPE(S1), ?TYPE(S2)) of
[] -> erlang:error(type_mismatch, [S1, S2]);
Type -> ?SET(symdiff(?LIST(S1), ?LIST(S2), []), Type)
end.
+-spec(symmetric_partition(Set1, Set2) -> {Set3, Set4, Set5} when
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set(),
+ Set4 :: a_set(),
+ Set5 :: a_set()).
symmetric_partition(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
case unify_types(?TYPE(S1), ?TYPE(S2)) of
[] -> erlang:error(type_mismatch, [S1, S2]);
Type -> sympart(?LIST(S1), ?LIST(S2), [], [], [], Type)
end.
+-spec(product(Set1, Set2) -> BinRel when
+ BinRel :: binary_relation(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
product(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
if
?TYPE(S1) =:= ?ANYTYPE -> S1;
@@ -351,6 +469,9 @@ product(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
?SET(relprod(map(F, ?LIST(S1)), map(F, ?LIST(S2))), T)
end.
+-spec(product(TupleOfSets) -> Relation when
+ Relation :: relation(),
+ TupleOfSets :: tuple_of(a_set())).
product({S1, S2}) ->
product(S1, S2);
product(T) when is_tuple(T) ->
@@ -365,11 +486,15 @@ product(T) when is_tuple(T) ->
case member([], L) of
true ->
empty_set();
- false ->
+ false ->
?SET(reverse(prod(L, [], [])), Type)
end
end.
+-spec(constant_function(Set, AnySet) -> Function when
+ AnySet :: anyset(),
+ Function :: a_function(),
+ Set :: a_set()).
constant_function(S, E) when ?IS_SET(S) ->
case {?TYPE(S), is_sofs_set(E)} of
{?ANYTYPE, true} -> S;
@@ -381,6 +506,10 @@ constant_function(S, E) when ?IS_SET(S) ->
constant_function(S, E) when ?IS_ORDSET(S) ->
erlang:error(badarg, [S, E]).
+-spec(is_equal(AnySet1, AnySet2) -> Bool when
+ AnySet1 :: anyset(),
+ AnySet2 :: anyset(),
+ Bool :: boolean()).
is_equal(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
case match_types(?TYPE(S1), ?TYPE(S2)) of
true -> ?LIST(S1) == ?LIST(S2);
@@ -396,12 +525,19 @@ is_equal(S1, S2) when ?IS_SET(S1), ?IS_ORDSET(S2) ->
is_equal(S1, S2) when ?IS_ORDSET(S1), ?IS_SET(S2) ->
erlang:error(type_mismatch, [S1, S2]).
+-spec(is_subset(Set1, Set2) -> Bool when
+ Bool :: boolean(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
is_subset(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
case match_types(?TYPE(S1), ?TYPE(S2)) of
true -> subset(?LIST(S1), ?LIST(S2));
false -> erlang:error(type_mismatch, [S1, S2])
end.
+-spec(is_sofs_set(Term) -> Bool when
+ Bool :: boolean(),
+ Term :: term()).
is_sofs_set(S) when ?IS_SET(S) ->
true;
is_sofs_set(S) when ?IS_ORDSET(S) ->
@@ -409,16 +545,26 @@ is_sofs_set(S) when ?IS_ORDSET(S) ->
is_sofs_set(_S) ->
false.
+-spec(is_set(AnySet) -> Bool when
+ AnySet :: anyset(),
+ Bool :: boolean()).
is_set(S) when ?IS_SET(S) ->
true;
is_set(S) when ?IS_ORDSET(S) ->
false.
-is_empty_set(S) when ?IS_SET(S) ->
+-spec(is_empty_set(AnySet) -> Bool when
+ AnySet :: anyset(),
+ Bool :: boolean()).
+is_empty_set(S) when ?IS_SET(S) ->
?LIST(S) =:= [];
is_empty_set(S) when ?IS_ORDSET(S) ->
false.
+-spec(is_disjoint(Set1, Set2) -> Bool when
+ Bool :: boolean(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
is_disjoint(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
case match_types(?TYPE(S1), ?TYPE(S2)) of
true ->
@@ -433,6 +579,9 @@ is_disjoint(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
%%% Functions on set-of-sets.
%%%
+-spec(union(SetOfSets) -> Set when
+ Set :: a_set(),
+ SetOfSets :: set_of_sets()).
union(Sets) when ?IS_SET(Sets) ->
case ?TYPE(Sets) of
?SET_OF(Type) -> ?SET(lunion(?LIST(Sets)), Type);
@@ -440,6 +589,9 @@ union(Sets) when ?IS_SET(Sets) ->
_ -> erlang:error(badarg, [Sets])
end.
+-spec(intersection(SetOfSets) -> Set when
+ Set :: a_set(),
+ SetOfSets :: set_of_sets()).
intersection(Sets) when ?IS_SET(Sets) ->
case ?LIST(Sets) of
[] -> erlang:error(badarg, [Sets]);
@@ -451,32 +603,41 @@ intersection(Sets) when ?IS_SET(Sets) ->
end
end.
+-spec(canonical_relation(SetOfSets) -> BinRel when
+ BinRel :: binary_relation(),
+ SetOfSets :: set_of_sets()).
canonical_relation(Sets) when ?IS_SET(Sets) ->
ST = ?TYPE(Sets),
case ST of
?SET_OF(?ANYTYPE) -> empty_set();
- ?SET_OF(Type) ->
+ ?SET_OF(Type) ->
?SET(can_rel(?LIST(Sets), []), ?BINREL(Type, ST));
?ANYTYPE -> Sets;
_ -> erlang:error(badarg, [Sets])
end.
-%%%
+%%%
%%% Functions on binary relations only.
-%%%
+%%%
rel2fam(R) ->
relation_to_family(R).
+-spec(relation_to_family(BinRel) -> Family when
+ Family :: family(),
+ BinRel :: binary_relation()).
%% Inlined.
relation_to_family(R) when ?IS_SET(R) ->
case ?TYPE(R) of
- ?BINREL(DT, RT) ->
+ ?BINREL(DT, RT) ->
?SET(rel2family(?LIST(R)), ?FAMILY(DT, RT));
?ANYTYPE -> R;
_Else -> erlang:error(badarg, [R])
end.
+-spec(domain(BinRel) -> Set when
+ BinRel :: binary_relation(),
+ Set :: a_set()).
domain(R) when ?IS_SET(R) ->
case ?TYPE(R) of
?BINREL(DT, _) -> ?SET(dom(?LIST(R)), DT);
@@ -484,6 +645,9 @@ domain(R) when ?IS_SET(R) ->
_Else -> erlang:error(badarg, [R])
end.
+-spec(range(BinRel) -> Set when
+ BinRel :: binary_relation(),
+ Set :: a_set()).
range(R) when ?IS_SET(R) ->
case ?TYPE(R) of
?BINREL(_, RT) -> ?SET(ran(?LIST(R), []), RT);
@@ -491,35 +655,63 @@ range(R) when ?IS_SET(R) ->
_ -> erlang:error(badarg, [R])
end.
+-spec(field(BinRel) -> Set when
+ BinRel :: binary_relation(),
+ Set :: a_set()).
%% In "Introduction to LOGIC", Suppes defines the field of a binary
%% relation to be the union of the domain and the range (or
%% counterdomain).
field(R) ->
union(domain(R), range(R)).
+-spec(relative_product(ListOfBinRels) -> BinRel2 when
+ ListOfBinRels :: [BinRel, ...],
+ BinRel :: binary_relation(),
+ BinRel2 :: binary_relation()).
+%% The following clause is kept for backward compatibility.
+%% The list is due to Dialyzer's specs.
relative_product(RT) when is_tuple(RT) ->
- case relprod_n(RT, foo, false, false) of
- {error, Reason} ->
- erlang:error(Reason, [RT]);
+ relative_product(tuple_to_list(RT));
+relative_product(RL) when is_list(RL) ->
+ case relprod_n(RL, foo, false, false) of
+ {error, Reason} ->
+ erlang:error(Reason, [RL]);
Reply ->
Reply
end.
+-spec(relative_product(ListOfBinRels, BinRel1) -> BinRel2 when
+ ListOfBinRels :: [BinRel, ...],
+ BinRel :: binary_relation(),
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation();
+ (BinRel1, BinRel2) -> BinRel3 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation(),
+ BinRel3 :: binary_relation()).
relative_product(R1, R2) when ?IS_SET(R1), ?IS_SET(R2) ->
relative_product1(converse(R1), R2);
+%% The following clause is kept for backward compatibility.
+%% The list is due to Dialyzer's specs.
relative_product(RT, R) when is_tuple(RT), ?IS_SET(R) ->
+ relative_product(tuple_to_list(RT), R);
+relative_product(RL, R) when is_list(RL), ?IS_SET(R) ->
EmptyR = case ?TYPE(R) of
?BINREL(_, _) -> ?LIST(R) =:= [];
?ANYTYPE -> true;
- _ -> erlang:error(badarg, [RT, R])
+ _ -> erlang:error(badarg, [RL, R])
end,
- case relprod_n(RT, R, EmptyR, true) of
- {error, Reason} ->
- erlang:error(Reason, [RT, R]);
+ case relprod_n(RL, R, EmptyR, true) of
+ {error, Reason} ->
+ erlang:error(Reason, [RL, R]);
Reply ->
Reply
end.
+-spec(relative_product1(BinRel1, BinRel2) -> BinRel3 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation(),
+ BinRel3 :: binary_relation()).
relative_product1(R1, R2) when ?IS_SET(R1), ?IS_SET(R2) ->
{DTR1, RTR1} = case ?TYPE(R1) of
?BINREL(_, _) = R1T -> R1T;
@@ -538,16 +730,23 @@ relative_product1(R1, R2) when ?IS_SET(R1), ?IS_SET(R2) ->
false -> erlang:error(type_mismatch, [R1, R2])
end.
+-spec(converse(BinRel1) -> BinRel2 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation()).
converse(R) when ?IS_SET(R) ->
case ?TYPE(R) of
?BINREL(DT, RT) -> ?SET(converse(?LIST(R), []), ?BINREL(RT, DT));
?ANYTYPE -> R;
_ -> erlang:error(badarg, [R])
end.
-
+
+-spec(image(BinRel, Set1) -> Set2 when
+ BinRel :: binary_relation(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
image(R, S) when ?IS_SET(R), ?IS_SET(S) ->
case ?TYPE(R) of
- ?BINREL(DT, RT) ->
+ ?BINREL(DT, RT) ->
case match_types(DT, ?TYPE(S)) of
true ->
?SET(usort(restrict(?LIST(S), ?LIST(R))), RT);
@@ -558,9 +757,13 @@ image(R, S) when ?IS_SET(R), ?IS_SET(S) ->
_ -> erlang:error(badarg, [R, S])
end.
+-spec(inverse_image(BinRel, Set1) -> Set2 when
+ BinRel :: binary_relation(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
inverse_image(R, S) when ?IS_SET(R), ?IS_SET(S) ->
case ?TYPE(R) of
- ?BINREL(DT, RT) ->
+ ?BINREL(DT, RT) ->
case match_types(RT, ?TYPE(S)) of
true ->
NL = restrict(?LIST(S), converse(?LIST(R), [])),
@@ -572,17 +775,23 @@ inverse_image(R, S) when ?IS_SET(R), ?IS_SET(S) ->
_ -> erlang:error(badarg, [R, S])
end.
+-spec(strict_relation(BinRel1) -> BinRel2 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation()).
strict_relation(R) when ?IS_SET(R) ->
case ?TYPE(R) of
- Type = ?BINREL(_, _) ->
+ Type = ?BINREL(_, _) ->
?SET(strict(?LIST(R), []), Type);
?ANYTYPE -> R;
_ -> erlang:error(badarg, [R])
end.
-
+
+-spec(weak_relation(BinRel1) -> BinRel2 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation()).
weak_relation(R) when ?IS_SET(R) ->
case ?TYPE(R) of
- ?BINREL(DT, RT) ->
+ ?BINREL(DT, RT) ->
case unify_types(DT, RT) of
[] ->
erlang:error(badarg, [R]);
@@ -592,7 +801,12 @@ weak_relation(R) when ?IS_SET(R) ->
?ANYTYPE -> R;
_ -> erlang:error(badarg, [R])
end.
-
+
+-spec(extension(BinRel1, Set, AnySet) -> BinRel2 when
+ AnySet :: anyset(),
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation(),
+ Set :: a_set()).
extension(R, S, E) when ?IS_SET(R), ?IS_SET(S) ->
case {?TYPE(R), ?TYPE(S), is_sofs_set(E)} of
{T=?BINREL(DT, RT), ST, true} ->
@@ -621,9 +835,12 @@ extension(R, S, E) when ?IS_SET(R), ?IS_SET(S) ->
erlang:error(badarg, [R, S, E])
end.
+-spec(is_a_function(BinRel) -> Bool when
+ Bool :: boolean(),
+ BinRel :: binary_relation()).
is_a_function(R) when ?IS_SET(R) ->
case ?TYPE(R) of
- ?BINREL(_, _) ->
+ ?BINREL(_, _) ->
case ?LIST(R) of
[] -> true;
[{V,_} | Es] -> is_a_func(Es, V)
@@ -632,16 +849,28 @@ is_a_function(R) when ?IS_SET(R) ->
_ -> erlang:error(badarg, [R])
end.
+-spec(restriction(BinRel1, Set) -> BinRel2 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation(),
+ Set :: a_set()).
restriction(Relation, Set) ->
restriction(1, Relation, Set).
+-spec(drestriction(BinRel1, Set) -> BinRel2 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation(),
+ Set :: a_set()).
drestriction(Relation, Set) ->
drestriction(1, Relation, Set).
-%%%
+%%%
%%% Functions on functions only.
-%%%
+%%%
+-spec(composite(Function1, Function2) -> Function3 when
+ Function1 :: a_function(),
+ Function2 :: a_function(),
+ Function3 :: a_function()).
composite(Fn1, Fn2) when ?IS_SET(Fn1), ?IS_SET(Fn2) ->
?BINREL(DTF1, RTF1) = case ?TYPE(Fn1)of
?BINREL(_, _) = F1T -> F1T;
@@ -656,7 +885,7 @@ composite(Fn1, Fn2) when ?IS_SET(Fn1), ?IS_SET(Fn2) ->
case match_types(RTF1, DTF2) of
true when DTF1 =:= ?ANYTYPE -> Fn1;
true when DTF2 =:= ?ANYTYPE -> Fn2;
- true ->
+ true ->
case comp(?LIST(Fn1), ?LIST(Fn2)) of
SL when is_list(SL) ->
?SET(sort(SL), ?BINREL(DTF1, RTF2));
@@ -666,9 +895,12 @@ composite(Fn1, Fn2) when ?IS_SET(Fn1), ?IS_SET(Fn2) ->
false -> erlang:error(type_mismatch, [Fn1, Fn2])
end.
+-spec(inverse(Function1) -> Function2 when
+ Function1 :: a_function(),
+ Function2 :: a_function()).
inverse(Fn) when ?IS_SET(Fn) ->
case ?TYPE(Fn) of
- ?BINREL(DT, RT) ->
+ ?BINREL(DT, RT) ->
case inverse1(?LIST(Fn)) of
SL when is_list(SL) ->
?SET(SL, ?BINREL(RT, DT));
@@ -678,11 +910,16 @@ inverse(Fn) when ?IS_SET(Fn) ->
?ANYTYPE -> Fn;
_ -> erlang:error(badarg, [Fn])
end.
-
-%%%
+
+%%%
%%% Functions on relations (binary or other).
-%%%
+%%%
+-spec(restriction(SetFun, Set1, Set2) -> Set3 when
+ SetFun :: set_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
%% Equivalent to range(restriction(inverse(substitution(Fun, S1)), S2)).
restriction(I, R, S) when is_integer(I), ?IS_SET(R), ?IS_SET(S) ->
RT = ?TYPE(R),
@@ -747,6 +984,11 @@ restriction(SetFun, S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
end
end.
+-spec(drestriction(SetFun, Set1, Set2) -> Set3 when
+ SetFun :: set_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
drestriction(I, R, S) when is_integer(I), ?IS_SET(R), ?IS_SET(S) ->
RT = ?TYPE(R),
ST = ?TYPE(S),
@@ -812,6 +1054,10 @@ drestriction(SetFun, S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
end
end.
+-spec(projection(SetFun, Set1) -> Set2 when
+ SetFun :: set_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
projection(I, Set) when is_integer(I), ?IS_SET(Set) ->
Type = ?TYPE(Set),
case check_for_sort(Type, I) of
@@ -827,6 +1073,10 @@ projection(I, Set) when is_integer(I), ?IS_SET(Set) ->
projection(Fun, Set) ->
range(substitution(Fun, Set)).
+-spec(substitution(SetFun, Set1) -> Set2 when
+ SetFun :: set_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
substitution(I, Set) when is_integer(I), ?IS_SET(Set) ->
Type = ?TYPE(Set),
case check_for_sort(Type, I) of
@@ -867,11 +1117,18 @@ substitution(SetFun, Set) when ?IS_SET(Set) ->
end
end.
+-spec(partition(SetOfSets) -> Partition when
+ SetOfSets :: set_of_sets(),
+ Partition :: a_set()).
partition(Sets) ->
F1 = relation_to_family(canonical_relation(Sets)),
F2 = relation_to_family(converse(F1)),
range(F2).
+-spec(partition(SetFun, Set) -> Partition when
+ SetFun :: set_fun(),
+ Partition :: a_set(),
+ Set :: a_set()).
partition(I, Set) when is_integer(I), ?IS_SET(Set) ->
Type = ?TYPE(Set),
case check_for_sort(Type, I) of
@@ -887,6 +1144,12 @@ partition(I, Set) when is_integer(I), ?IS_SET(Set) ->
partition(Fun, Set) ->
range(partition_family(Fun, Set)).
+-spec(partition(SetFun, Set1, Set2) -> {Set3, Set4} when
+ SetFun :: set_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set(),
+ Set4 :: a_set()).
partition(I, R, S) when is_integer(I), ?IS_SET(R), ?IS_SET(S) ->
RT = ?TYPE(R),
ST = ?TYPE(S),
@@ -954,21 +1217,32 @@ partition(SetFun, S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
end
end.
+-spec(multiple_relative_product(TupleOfBinRels, BinRel1) -> BinRel2 when
+ TupleOfBinRels :: tuple_of(BinRel),
+ BinRel :: binary_relation(),
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation()).
multiple_relative_product(T, R) when is_tuple(T), ?IS_SET(R) ->
case test_rel(R, tuple_size(T), eq) of
true when ?TYPE(R) =:= ?ANYTYPE ->
empty_set();
- true ->
+ true ->
MProd = mul_relprod(tuple_to_list(T), 1, R),
- relative_product(list_to_tuple(MProd));
- false ->
+ relative_product(MProd);
+ false ->
erlang:error(badarg, [T, R])
end.
-join(R1, I1, R2, I2)
+-spec(join(Relation1, I, Relation2, J) -> Relation3 when
+ Relation1 :: relation(),
+ Relation2 :: relation(),
+ Relation3 :: relation(),
+ I :: pos_integer(),
+ J :: pos_integer()).
+join(R1, I1, R2, I2)
when ?IS_SET(R1), ?IS_SET(R2), is_integer(I1), is_integer(I2) ->
case test_rel(R1, I1, lte) and test_rel(R2, I2, lte) of
- false ->
+ false ->
erlang:error(badarg, [R1, I1, R2, I2]);
true when ?TYPE(R1) =:= ?ANYTYPE -> R1;
true when ?TYPE(R2) =:= ?ANYTYPE -> R2;
@@ -980,8 +1254,8 @@ join(R1, I1, R2, I2)
true ->
fun({X,Y}) -> join_element(X, Y) end;
false ->
- fun({X,Y}) ->
- list_to_tuple(join_element(X, Y, I2))
+ fun({X,Y}) ->
+ list_to_tuple(join_element(X, Y, I2))
end
end,
?SET(replace(T, F, []), F({?TYPE(R1), ?TYPE(R2)}))
@@ -1001,9 +1275,15 @@ test_rel(R, I, C) ->
%%% Family functions
%%%
+-spec(fam2rel(Family) -> BinRel when
+ Family :: family(),
+ BinRel :: binary_relation()).
fam2rel(F) ->
family_to_relation(F).
+-spec(family_to_relation(Family) -> BinRel when
+ Family :: family(),
+ BinRel :: binary_relation()).
%% Inlined.
family_to_relation(F) when ?IS_SET(F) ->
case ?TYPE(F) of
@@ -1013,6 +1293,10 @@ family_to_relation(F) when ?IS_SET(F) ->
_ -> erlang:error(badarg, [F])
end.
+-spec(family_specification(Fun, Family1) -> Family2 when
+ Fun :: spec_fun(),
+ Family1 :: family(),
+ Family2 :: family()).
family_specification(Fun, F) when ?IS_SET(F) ->
case ?TYPE(F) of
?FAMILY(_DT, Type) = FType ->
@@ -1032,6 +1316,9 @@ family_specification(Fun, F) when ?IS_SET(F) ->
_ -> erlang:error(badarg, [Fun, F])
end.
+-spec(union_of_family(Family) -> Set when
+ Family :: family(),
+ Set :: a_set()).
union_of_family(F) when ?IS_SET(F) ->
case ?TYPE(F) of
?FAMILY(_DT, Type) ->
@@ -1040,6 +1327,9 @@ union_of_family(F) when ?IS_SET(F) ->
_ -> erlang:error(badarg, [F])
end.
+-spec(intersection_of_family(Family) -> Set when
+ Family :: family(),
+ Set :: a_set()).
intersection_of_family(F) when ?IS_SET(F) ->
case ?TYPE(F) of
?FAMILY(_DT, Type) ->
@@ -1052,6 +1342,9 @@ intersection_of_family(F) when ?IS_SET(F) ->
_ -> erlang:error(badarg, [F])
end.
+-spec(family_union(Family1) -> Family2 when
+ Family1 :: family(),
+ Family2 :: family()).
family_union(F) when ?IS_SET(F) ->
case ?TYPE(F) of
?FAMILY(DT, ?SET_OF(Type)) ->
@@ -1060,6 +1353,9 @@ family_union(F) when ?IS_SET(F) ->
_ -> erlang:error(badarg, [F])
end.
+-spec(family_intersection(Family1) -> Family2 when
+ Family1 :: family(),
+ Family2 :: family()).
family_intersection(F) when ?IS_SET(F) ->
case ?TYPE(F) of
?FAMILY(DT, ?SET_OF(Type)) ->
@@ -1073,6 +1369,9 @@ family_intersection(F) when ?IS_SET(F) ->
_ -> erlang:error(badarg, [F])
end.
+-spec(family_domain(Family1) -> Family2 when
+ Family1 :: family(),
+ Family2 :: family()).
family_domain(F) when ?IS_SET(F) ->
case ?TYPE(F) of
?FAMILY(FDT, ?BINREL(DT, _)) ->
@@ -1082,6 +1381,9 @@ family_domain(F) when ?IS_SET(F) ->
_ -> erlang:error(badarg, [F])
end.
+-spec(family_range(Family1) -> Family2 when
+ Family1 :: family(),
+ Family2 :: family()).
family_range(F) when ?IS_SET(F) ->
case ?TYPE(F) of
?FAMILY(DT, ?BINREL(_, RT)) ->
@@ -1091,15 +1393,30 @@ family_range(F) when ?IS_SET(F) ->
_ -> erlang:error(badarg, [F])
end.
+-spec(family_field(Family1) -> Family2 when
+ Family1 :: family(),
+ Family2 :: family()).
family_field(F) ->
family_union(family_domain(F), family_range(F)).
+-spec(family_union(Family1, Family2) -> Family3 when
+ Family1 :: family(),
+ Family2 :: family(),
+ Family3 :: family()).
family_union(F1, F2) ->
fam_binop(F1, F2, fun fam_union/3).
+-spec(family_intersection(Family1, Family2) -> Family3 when
+ Family1 :: family(),
+ Family2 :: family(),
+ Family3 :: family()).
family_intersection(F1, F2) ->
fam_binop(F1, F2, fun fam_intersect/3).
+-spec(family_difference(Family1, Family2) -> Family3 when
+ Family1 :: family(),
+ Family2 :: family(),
+ Family3 :: family()).
family_difference(F1, F2) ->
fam_binop(F1, F2, fun fam_difference/3).
@@ -1108,13 +1425,17 @@ fam_binop(F1, F2, FF) when ?IS_SET(F1), ?IS_SET(F2) ->
case unify_types(?TYPE(F1), ?TYPE(F2)) of
[] ->
erlang:error(type_mismatch, [F1, F2]);
- ?ANYTYPE ->
+ ?ANYTYPE ->
F1;
- Type = ?FAMILY(_, _) ->
+ Type = ?FAMILY(_, _) ->
?SET(FF(?LIST(F1), ?LIST(F2), []), Type);
_ -> erlang:error(badarg, [F1, F2])
end.
+-spec(partition_family(SetFun, Set) -> Family when
+ Family :: family(),
+ SetFun :: set_fun(),
+ Set :: a_set()).
partition_family(I, Set) when is_integer(I), ?IS_SET(Set) ->
Type = ?TYPE(Set),
case check_for_sort(Type, I) of
@@ -1159,8 +1480,12 @@ partition_family(SetFun, Set) when ?IS_SET(Set) ->
end
end.
+-spec(family_projection(SetFun, Family1) -> Family2 when
+ SetFun :: set_fun(),
+ Family1 :: family(),
+ Family2 :: family()).
family_projection(SetFun, F) when ?IS_SET(F) ->
- case ?TYPE(F) of
+ case ?TYPE(F) of
?FAMILY(_, _) when [] =:= ?LIST(F) ->
empty_set();
?FAMILY(DT, Type) ->
@@ -1172,7 +1497,7 @@ family_projection(SetFun, F) when ?IS_SET(F) ->
Bad ->
erlang:error(Bad, [SetFun, F])
end;
- _ ->
+ _ ->
erlang:error(badarg, [SetFun, F])
end;
?ANYTYPE -> F;
@@ -1183,6 +1508,9 @@ family_projection(SetFun, F) when ?IS_SET(F) ->
%%% Digraph functions
%%%
+-spec(family_to_digraph(Family) -> Graph when
+ Graph :: digraph(),
+ Family :: family()).
family_to_digraph(F) when ?IS_SET(F) ->
case ?TYPE(F) of
?FAMILY(_, _) -> fam2digraph(F, digraph:new());
@@ -1190,6 +1518,10 @@ family_to_digraph(F) when ?IS_SET(F) ->
_Else -> erlang:error(badarg, [F])
end.
+-spec(family_to_digraph(Family, GraphType) -> Graph when
+ Graph :: digraph(),
+ Family :: family(),
+ GraphType :: [digraph:d_type()]).
family_to_digraph(F, Type) when ?IS_SET(F) ->
case ?TYPE(F) of
?FAMILY(_, _) -> ok;
@@ -1208,12 +1540,19 @@ family_to_digraph(F, Type) when ?IS_SET(F) ->
error:badarg -> erlang:error(badarg, [F, Type])
end.
+-spec(digraph_to_family(Graph) -> Family when
+ Graph :: digraph(),
+ Family :: family()).
digraph_to_family(G) ->
case catch digraph_family(G) of
{'EXIT', _} -> erlang:error(badarg, [G]);
L -> ?SET(L, ?FAMILY(?ATOM_TYPE, ?ATOM_TYPE))
end.
+-spec(digraph_to_family(Graph, Type) -> Family when
+ Graph :: digraph(),
+ Family :: family(),
+ Type :: type()).
digraph_to_family(G, T) ->
case {is_type(T), T} of
{true, ?SET_OF(?FAMILY(_,_) = Type)} ->
@@ -1284,7 +1623,7 @@ rel(Ts, [Type]) ->
end;
rel(Ts, Sz) ->
rel(Ts, Sz, erlang:make_tuple(Sz, ?ATOM_TYPE)).
-
+
atoms_only(Type, I) when ?IS_ATOM_TYPE(?REL_TYPE(I, Type)) ->
atoms_only(Type, I+1);
atoms_only(Type, I) when I > tuple_size(Type), ?IS_RELATION(Type) ->
@@ -1312,7 +1651,7 @@ rel_type([], SL, Type) when ?IS_RELATION(Type) ->
%% Inlined.
a_func(Ts, T) ->
case {T, is_type(T)} of
- {[?BINREL(DT, RT) = Type], true} when ?IS_ATOM_TYPE(DT),
+ {[?BINREL(DT, RT) = Type], true} when ?IS_ATOM_TYPE(DT),
?IS_ATOM_TYPE(RT) ->
func(Ts, Type);
{[Type], true} ->
@@ -1333,16 +1672,16 @@ func([], _X0, L, Type) ->
%% Inlined.
fam(Ts, T) ->
case {T, is_type(T)} of
- {[?FAMILY(DT, RT) = Type], true} when ?IS_ATOM_TYPE(DT),
+ {[?FAMILY(DT, RT) = Type], true} when ?IS_ATOM_TYPE(DT),
?IS_ATOM_TYPE(RT) ->
fam2(Ts, Type);
{[Type], true} ->
func_type(Ts, [], Type, fun(?FAMILY(_,_)) -> true end)
end.
-fam2([], Type) ->
+fam2([], Type) ->
?SET([], Type);
-fam2(Ts, Type) ->
+fam2(Ts, Type) ->
fam2(sort(Ts), Ts, [], Type).
fam2([{I,L} | T], I0, SL, Type) when I /= I0 ->
@@ -1383,7 +1722,7 @@ setify(E, Type0) ->
{Type, OrdSet} = make_element(E, Type0, Type0),
?ORDSET(OrdSet, Type).
-is_no_lists(T) when is_tuple(T) ->
+is_no_lists(T) when is_tuple(T) ->
Sz = tuple_size(T),
is_no_lists(T, Sz, Sz, []).
@@ -1404,7 +1743,7 @@ create([], T, _T0, L) ->
make_element(C, ?ANYTYPE, _T0) ->
make_element(C);
-make_element(C, Atom, ?ANYTYPE) when ?IS_ATOM_TYPE(Atom),
+make_element(C, Atom, ?ANYTYPE) when ?IS_ATOM_TYPE(Atom),
not is_list(C), not is_tuple(C) ->
{Atom, C};
make_element(C, Atom, Atom) when ?IS_ATOM_TYPE(Atom) ->
@@ -1585,12 +1924,12 @@ sympart([H1 | T1], [H2 | T2], L1, L12, L2, T) when H1 == H2 ->
sympart([H1 | T1], [H2 | T2], L1, L12, L2, T) ->
sympart2(T1, T2, L1, L12, [H2 | L2], T, H1);
sympart(S1, [], L1, L12, L2, T) ->
- {?SET(reverse(L1, S1), T),
- ?SET(reverse(L12), T),
+ {?SET(reverse(L1, S1), T),
+ ?SET(reverse(L12), T),
?SET(reverse(L2), T)};
sympart(_, S2, L1, L12, L2, T) ->
- {?SET(reverse(L1), T),
- ?SET(reverse(L12), T),
+ {?SET(reverse(L1), T),
+ ?SET(reverse(L12), T),
?SET(reverse(L2, S2), T)}.
sympart1([H1 | T1], T2, L1, L12, L2, T, H2) when H1 < H2 ->
@@ -1600,8 +1939,8 @@ sympart1([H1 | T1], T2, L1, L12, L2, T, H2) when H1 == H2 ->
sympart1([H1 | T1], T2, L1, L12, L2, T, H2) ->
sympart2(T1, T2, L1, L12, [H2 | L2], T, H1);
sympart1(_, T2, L1, L12, L2, T, H2) ->
- {?SET(reverse(L1), T),
- ?SET(reverse(L12), T),
+ {?SET(reverse(L1), T),
+ ?SET(reverse(L12), T),
?SET(reverse(L2, [H2 | T2]), T)}.
sympart2(T1, [H2 | T2], L1, L12, L2, T, H1) when H1 > H2 ->
@@ -1611,8 +1950,8 @@ sympart2(T1, [H2 | T2], L1, L12, L2, T, H1) when H1 == H2 ->
sympart2(T1, [H2 | T2], L1, L12, L2, T, H1) ->
sympart1(T1, T2, [H1 | L1], L12, L2, T, H2);
sympart2(T1, _, L1, L12, L2, T, H1) ->
- {?SET(reverse(L1, [H1 | T1]), T),
- ?SET(reverse(L12), T),
+ {?SET(reverse(L1, [H1 | T1]), T),
+ ?SET(reverse(L12), T),
?SET(reverse(L2), T)}.
prod([[E | Es] | Xs], T, L) ->
@@ -1660,7 +1999,7 @@ lunion([[] | Ls]) ->
lunion(Ls);
lunion([S | Ss]) ->
umerge(lunion(Ss, last(S), [S], []));
-lunion([]) ->
+lunion([]) ->
[].
lunion([[E] = S | Ss], Last, SL, Ls) when E > Last -> % optimization
@@ -1669,7 +2008,7 @@ lunion([S | Ss], Last, SL, Ls) when hd(S) > Last ->
lunion(Ss, last(S), [S | SL], Ls);
lunion([S | Ss], _Last, SL, Ls) ->
lunion(Ss, last(S), [S], [append(reverse(SL)) | Ls]);
-lunion([], _Last, SL, Ls) ->
+lunion([], _Last, SL, Ls) ->
[append(reverse(SL)) | Ls].
%% The empty list is always the first list, if present.
@@ -1752,18 +2091,17 @@ relprod(B0, Bx0, By0, A0, L, Ax, [{Bx,By} | B], Ay) when Ay == Bx ->
relprod(B0, Bx0, By0, A0, L, _Ax, _B, _Ay) ->
relprod2(B0, Bx0, By0, A0, L).
-relprod_n({}, _R, _EmptyG, _IsR) ->
+relprod_n([], _R, _EmptyG, _IsR) ->
{error, badarg};
-relprod_n(RT, R, EmptyR, IsR) ->
- RL = tuple_to_list(RT),
+relprod_n(RL, R, EmptyR, IsR) ->
case domain_type(RL, ?ANYTYPE) of
- Error = {error, _Reason} ->
+ Error = {error, _Reason} ->
Error;
DType ->
Empty = any(fun is_empty_set/1, RL) or EmptyR,
RType = range_type(RL, []),
Type = ?BINREL(DType, RType),
- Prod =
+ Prod =
case Empty of
true when DType =:= ?ANYTYPE; RType =:= ?ANYTYPE ->
empty_set();
@@ -1771,7 +2109,7 @@ relprod_n(RT, R, EmptyR, IsR) ->
?SET([], Type);
false ->
TL = ?LIST((relprod_n(RL))),
- Sz = tuple_size(RT),
+ Sz = length(RL),
Fun = fun({X,A}) -> {X, flat(Sz, A, [])} end,
?SET(map(Fun, TL), Type)
end,
@@ -1799,12 +2137,12 @@ flat(N, {T,A}, L) ->
domain_type([T | Ts], T0) when ?IS_SET(T) ->
case ?TYPE(T) of
- ?BINREL(DT, _RT) ->
+ ?BINREL(DT, _RT) ->
case unify_types(DT, T0) of
[] -> {error, type_mismatch};
T1 -> domain_type(Ts, T1)
end;
- ?ANYTYPE ->
+ ?ANYTYPE ->
domain_type(Ts, T0);
_ -> {error, badarg}
end;
@@ -1813,12 +2151,12 @@ domain_type([], T0) ->
range_type([T | Ts], L) ->
case ?TYPE(T) of
- ?BINREL(_DT, RT) ->
+ ?BINREL(_DT, RT) ->
range_type(Ts, [RT | L]);
- ?ANYTYPE ->
+ ?ANYTYPE ->
?ANYTYPE
end;
-range_type([], L) ->
+range_type([], L) ->
list_to_tuple(reverse(L)).
converse([{A,B} | X], L) ->
@@ -1861,7 +2199,7 @@ weak1([E={X,_Y} | Es], Ys, L, X0) when X == X0 -> % when X < Y
weak1(Es, Ys, L, X) ->
weak(Es, Ys, [{X,X} | L]).
-weak2([E={X,_Y} | Es], Ys, L, X0) when X == X0 -> % when X < _Y
+weak2([E={X,_Y} | Es], Ys, L, X0) when X == X0 -> % when X < _Y
weak2(Es, Ys, [E | L], X);
weak2(Es, Ys, L, _X) ->
weak(Es, Ys, L).
@@ -1910,7 +2248,7 @@ restrict_n(I, [T | Ts], Key, Keys, L) ->
end;
restrict_n(_I, _Ts, _Key, _Keys, L) ->
L.
-
+
restrict_n(I, K, Ts, [Key | Keys], L, E) when K > Key ->
restrict_n(I, K, Ts, Keys, L, E);
restrict_n(I, K, Ts, [Key | Keys], L, E) when K == Key ->
@@ -1933,7 +2271,7 @@ restrict([{K,E} | Ts], _Key, Keys, L) ->
restrict(Ts, K, Keys, L, E);
restrict(_Ts, _Key, _Keys, L) ->
L.
-
+
restrict(Ts, K, [Key | Keys], L, E) when K > Key ->
restrict(Ts, K, Keys, L, E);
restrict(Ts, K, [Key | Keys], L, E) when K == Key ->
@@ -1956,7 +2294,7 @@ diff_restrict_n(I, _Ts, _Key, _Keys, L) when I =:= 1 ->
reverse(L);
diff_restrict_n(_I, _Ts, _Key, _Keys, L) ->
sort(L).
-
+
diff_restrict_n(I, K, Ts, [Key | Keys], L, T) when K > Key ->
diff_restrict_n(I, K, Ts, Keys, L, T);
diff_restrict_n(I, K, Ts, [Key | Keys], L, _T) when K == Key ->
@@ -1981,7 +2319,7 @@ diff_restrict([{K,E} | Ts], _Key, Keys, L) ->
diff_restrict(Ts, K, Keys, L, E);
diff_restrict(_Ts, _Key, _Keys, L) ->
L.
-
+
diff_restrict(Ts, K, [Key | Keys], L, E) when K > Key ->
diff_restrict(Ts, K, Keys, L, E);
diff_restrict(Ts, K, [Key | Keys], L, _E) when K == Key ->
@@ -2041,7 +2379,7 @@ external_fun({external, Function}) when is_atom(Function) ->
false;
external_fun({external, Fun}) ->
Fun;
-external_fun(_) ->
+external_fun(_) ->
false.
%% Inlined.
@@ -2121,7 +2459,7 @@ partition3_n(I, _Ts, _Key, _Keys, L1, L2) when I =:= 1 ->
[reverse(L1) | reverse(L2)];
partition3_n(_I, _Ts, _Key, _Keys, L1, L2) ->
[sort(L1) | sort(L2)].
-
+
partition3_n(I, K, Ts, [Key | Keys], L1, L2, T) when K > Key ->
partition3_n(I, K, Ts, Keys, L1, L2, T);
partition3_n(I, K, Ts, [Key | Keys], L1, L2, T) when K == Key ->
@@ -2146,7 +2484,7 @@ partition3([{K,E} | Ts], _Key, Keys, L1, L2) ->
partition3(Ts, K, Keys, L1, L2, E);
partition3(_Ts, _Key, _Keys, L1, L2) ->
[L1 | L2].
-
+
partition3(Ts, K, [Key | Keys], L1, L2, E) when K > Key ->
partition3(Ts, K, Keys, L1, L2, E);
partition3(Ts, K, [Key | Keys], L1, L2, E) when K == Key ->
@@ -2192,7 +2530,7 @@ join_element(E1, E2, I2) ->
join_element2([B | Bs], C, I2) when C =/= I2 ->
[B | join_element2(Bs, C+1, I2)];
-join_element2([_ | Bs], _C, _I2) ->
+join_element2([_ | Bs], _C, _I2) ->
Bs.
family2rel([{X,S} | F], L) ->
@@ -2297,7 +2635,7 @@ check_function([{X,_} | XL], R) ->
check_function(X, XL, R);
check_function([], R) ->
R.
-
+
check_function(X0, [{X,_} | XL], R) when X0 /= X ->
check_function(X, XL, R);
check_function(X0, [{X,_} | _XL], _R) when X0 == X ->
@@ -2371,14 +2709,14 @@ term2set(T, Type) ->
?ORDSET(T, Type).
fam2digraph(F, G) ->
- Fun = fun({From, ToL}) ->
+ Fun = fun({From, ToL}) ->
digraph:add_vertex(G, From),
Fun2 = fun(To) ->
digraph:add_vertex(G, To),
case digraph:add_edge(G, From, To) of
- {error, {bad_edge, _}} ->
+ {error, {bad_edge, _}} ->
throw({error, cyclic});
- _ ->
+ _ ->
true
end
end,
@@ -2397,7 +2735,7 @@ digraph_fam([V | Vs], V0, G, L) when V /= V0 ->
digraph_fam([], _V0, _G, L) ->
reverse(L).
-%% -> bool()
+%% -> boolean()
check_fun(T, F, FunT) ->
true = is_type(FunT),
{NT, _MaxI} = number_tuples(T, 1),
@@ -2424,7 +2762,7 @@ check_for_sort(T, _I) when T =:= ?ANYTYPE ->
check_for_sort(T, I) when ?IS_RELATION(T), I =< ?REL_ARITY(T), I >= 1 ->
I > 1;
check_for_sort(_T, _I) ->
- error.
+ error.
inverse_substitution(L, Fun, Sort) ->
%% One easily sees that the inverse of the tuples created by
@@ -2477,11 +2815,11 @@ match_types(Type1, Type2) -> match_types1(Type1, Type2).
match_types1(Atom, Atom) when ?IS_ATOM_TYPE(Atom) ->
true;
-match_types1(?ANYTYPE, _) ->
+match_types1(?ANYTYPE, _) ->
true;
-match_types1(_, ?ANYTYPE) ->
+match_types1(_, ?ANYTYPE) ->
true;
-match_types1(?SET_OF(Type1), ?SET_OF(Type2)) ->
+match_types1(?SET_OF(Type1), ?SET_OF(Type2)) ->
match_types1(Type1, Type2);
match_types1(T1, T2) when tuple_size(T1) =:= tuple_size(T2) ->
match_typesl(tuple_size(T1), T1, T2);
diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl
index 264348180f..30eac4f07d 100644
--- a/lib/stdlib/src/string.erl
+++ b/lib/stdlib/src/string.erl
@@ -29,23 +29,23 @@
%%---------------------------------------------------------------------------
--type direction() :: 'left' | 'right' | 'both'.
-
-%%---------------------------------------------------------------------------
-
%% Robert's bit
%% len(String)
%% Return the length of a string.
--spec len(string()) -> non_neg_integer().
+-spec len(String) -> Length when
+ String :: string(),
+ Length :: non_neg_integer().
len(S) -> length(S).
%% equal(String1, String2)
%% Test if 2 strings are equal.
--spec equal(string(), string()) -> boolean().
+-spec equal(String1, String2) -> boolean() when
+ String1 :: string(),
+ String2 :: string().
equal(S, S) -> true;
equal(_, _) -> false.
@@ -53,7 +53,10 @@ equal(_, _) -> false.
%% concat(String1, String2)
%% Concatenate 2 strings.
--spec concat(string(), string()) -> string().
+-spec concat(String1, String2) -> String3 when
+ String1 :: string(),
+ String2 :: string(),
+ String3 :: string().
concat(S1, S2) -> S1 ++ S2.
@@ -61,7 +64,10 @@ concat(S1, S2) -> S1 ++ S2.
%% rchr(String, Char)
%% Return the first/last index of the character in a string.
--spec chr(string(), char()) -> non_neg_integer().
+-spec chr(String, Character) -> Index when
+ String :: string(),
+ Character :: char(),
+ Index :: non_neg_integer().
chr(S, C) when is_integer(C) -> chr(S, C, 1).
@@ -69,7 +75,10 @@ chr([C|_Cs], C, I) -> I;
chr([_|Cs], C, I) -> chr(Cs, C, I+1);
chr([], _C, _I) -> 0.
--spec rchr(string(), char()) -> non_neg_integer().
+-spec rchr(String, Character) -> Index when
+ String :: string(),
+ Character :: char(),
+ Index :: non_neg_integer().
rchr(S, C) when is_integer(C) -> rchr(S, C, 1, 0).
@@ -85,7 +94,10 @@ rchr([], _C, _I, L) -> L.
%% Return the first/last index of the sub-string in a string.
%% index/2 is kept for backwards compatibility.
--spec str(string(), string()) -> non_neg_integer().
+-spec str(String, SubString) -> Index when
+ String :: string(),
+ SubString :: string(),
+ Index :: non_neg_integer().
str(S, Sub) when is_list(Sub) -> str(S, Sub, 1).
@@ -97,7 +109,10 @@ str([C|S], [C|Sub], I) ->
str([_|S], Sub, I) -> str(S, Sub, I+1);
str([], _Sub, _I) -> 0.
--spec rstr(string(), string()) -> non_neg_integer().
+-spec rstr(String, SubString) -> Index when
+ String :: string(),
+ SubString :: string(),
+ Index :: non_neg_integer().
rstr(S, Sub) when is_list(Sub) -> rstr(S, Sub, 1, 0).
@@ -116,7 +131,10 @@ prefix(Pre, String) when is_list(Pre), is_list(String) -> false.
%% span(String, Chars) -> Length.
%% cspan(String, Chars) -> Length.
--spec span(string(), string()) -> non_neg_integer().
+-spec span(String, Chars) -> Length when
+ String :: string(),
+ Chars :: string(),
+ Length :: non_neg_integer().
span(S, Cs) when is_list(Cs) -> span(S, Cs, 0).
@@ -127,7 +145,10 @@ span([C|S], Cs, I) ->
end;
span([], _Cs, I) -> I.
--spec cspan(string(), string()) -> non_neg_integer().
+-spec cspan(String, Chars) -> Length when
+ String :: string(),
+ Chars :: string(),
+ Length :: non_neg_integer().
cspan(S, Cs) when is_list(Cs) -> cspan(S, Cs, 0).
@@ -142,14 +163,21 @@ cspan([], _Cs, I) -> I.
%% substr(String, Start, Length)
%% Extract a sub-string from String.
--spec substr(string(), pos_integer()) -> string().
+-spec substr(String, Start) -> SubString when
+ String :: string(),
+ SubString :: string(),
+ Start :: pos_integer().
substr(String, 1) when is_list(String) ->
String;
substr(String, S) when is_integer(S), S > 1 ->
substr2(String, S).
--spec substr(string(), pos_integer(), non_neg_integer()) -> string().
+-spec substr(String, Start, Length) -> SubString when
+ String :: string(),
+ SubString :: string(),
+ Start :: pos_integer(),
+ Length :: non_neg_integer().
substr(String, S, L) when is_integer(S), S >= 1, is_integer(L), L >= 0 ->
substr1(substr2(String, S), L).
@@ -163,7 +191,10 @@ substr2([_|String], S) -> substr2(String, S-1).
%% tokens(String, Seperators).
%% Return a list of tokens seperated by characters in Seperators.
--spec tokens(string(), string()) -> [[char(),...]].
+-spec tokens(String, SeparatorList) -> Tokens when
+ String :: string(),
+ SeparatorList :: string(),
+ Tokens :: [Token :: nonempty_string()].
tokens(S, Seps) ->
tokens1(S, Seps, []).
@@ -184,11 +215,18 @@ tokens2([C|S], Seps, Toks, Cs) ->
tokens2([], _Seps, Toks, Cs) ->
reverse([reverse(Cs)|Toks]).
--spec chars(char(), non_neg_integer()) -> string().
+-spec chars(Character, Number) -> String when
+ Character :: char(),
+ Number :: non_neg_integer(),
+ String :: string().
chars(C, N) -> chars(C, N, []).
--spec chars(char(), non_neg_integer(), string()) -> string().
+-spec chars(Character, Number, Tail) -> String when
+ Character :: char(),
+ Number :: non_neg_integer(),
+ Tail :: string(),
+ String :: string().
chars(C, N, Tail) when N > 0 ->
chars(C, N-1, [C|Tail]);
@@ -199,7 +237,10 @@ chars(C, 0, Tail) when is_integer(C) ->
%%% COPIES %%%
--spec copies(string(), non_neg_integer()) -> string().
+-spec copies(String, Number) -> Copies when
+ String :: string(),
+ Copies :: string(),
+ Number :: non_neg_integer().
copies(CharList, Num) when is_list(CharList), is_integer(Num), Num >= 0 ->
copies(CharList, Num, []).
@@ -211,11 +252,16 @@ copies(CharList, Num, R) ->
%%% WORDS %%%
--spec words(string()) -> pos_integer().
+-spec words(String) -> Count when
+ String :: string(),
+ Count :: pos_integer().
words(String) -> words(String, $\s).
--spec words(string(), char()) -> pos_integer().
+-spec words(String, Character) -> Count when
+ String :: string(),
+ Character :: char(),
+ Count :: pos_integer().
words(String, Char) when is_integer(Char) ->
w_count(strip(String, both, Char), Char, 0).
@@ -226,11 +272,18 @@ w_count([_H|T], Char, Num) -> w_count(T, Char, Num).
%%% SUB_WORDS %%%
--spec sub_word(string(), integer()) -> string().
+-spec sub_word(String, Number) -> Word when
+ String :: string(),
+ Word :: string(),
+ Number :: integer().
sub_word(String, Index) -> sub_word(String, Index, $\s).
--spec sub_word(string(), integer(), char()) -> string().
+-spec sub_word(String, Number, Character) -> Word when
+ String :: string(),
+ Word :: string(),
+ Number :: integer(),
+ Character :: char().
sub_word(String, Index, Char) when is_integer(Index), is_integer(Char) ->
case words(String, Char) of
@@ -254,14 +307,21 @@ s_word([_|T],Stop,Char,Index,Res) when Index < Stop ->
strip(String) -> strip(String, both).
--spec strip(string(), direction()) -> string().
+-spec strip(String, Direction) -> Stripped when
+ String :: string(),
+ Stripped :: string(),
+ Direction :: left | right | both.
strip(String, left) -> strip_left(String, $\s);
strip(String, right) -> strip_right(String, $\s);
strip(String, both) ->
strip_right(strip_left(String, $\s), $\s).
--spec strip(string(), direction(), char()) -> string().
+-spec strip(String, Direction, Character) -> Stripped when
+ String :: string(),
+ Stripped :: string(),
+ Direction :: left | right | both,
+ Character :: char().
strip(String, right, Char) -> strip_right(String, Char);
strip(String, left, Char) -> strip_left(String, Char);
@@ -285,11 +345,18 @@ strip_right([], Sc) when is_integer(Sc) ->
%%% LEFT %%%
--spec left(string(), non_neg_integer()) -> string().
+-spec left(String, Number) -> Left when
+ String :: string(),
+ Left :: string(),
+ Number :: non_neg_integer().
left(String, Len) when is_integer(Len) -> left(String, Len, $\s).
--spec left(string(), non_neg_integer(), char()) -> string().
+-spec left(String, Number, Character) -> Left when
+ String :: string(),
+ Left :: string(),
+ Number :: non_neg_integer(),
+ Character :: char().
left(String, Len, Char) when is_integer(Char) ->
Slen = length(String),
@@ -303,11 +370,18 @@ l_pad(String, Num, Char) -> String ++ chars(Char, Num).
%%% RIGHT %%%
--spec right(string(), non_neg_integer()) -> string().
+-spec right(String, Number) -> Right when
+ String :: string(),
+ Right :: string(),
+ Number :: non_neg_integer().
right(String, Len) when is_integer(Len) -> right(String, Len, $\s).
--spec right(string(), non_neg_integer(), char()) -> string().
+-spec right(String, Number, Character) -> Right when
+ String :: string(),
+ Right :: string(),
+ Number :: non_neg_integer(),
+ Character :: char().
right(String, Len, Char) when is_integer(Char) ->
Slen = length(String),
@@ -321,11 +395,18 @@ r_pad(String, Num, Char) -> chars(Char, Num, String).
%%% CENTRE %%%
--spec centre(string(), non_neg_integer()) -> string().
+-spec centre(String, Number) -> Centered when
+ String :: string(),
+ Centered :: string(),
+ Number :: non_neg_integer().
centre(String, Len) when is_integer(Len) -> centre(String, Len, $\s).
--spec centre(string(), non_neg_integer(), char()) -> string().
+-spec centre(String, Number, Character) -> Centered when
+ String :: string(),
+ Centered :: string(),
+ Number :: non_neg_integer(),
+ Character :: char().
centre(String, 0, Char) when is_list(String), is_integer(Char) ->
[]; % Strange cases to centre string
@@ -341,11 +422,18 @@ centre(String, Len, Char) when is_integer(Char) ->
%%% SUB_STRING %%%
--spec sub_string(string(), pos_integer()) -> string().
+-spec sub_string(String, Start) -> SubString when
+ String :: string(),
+ SubString :: string(),
+ Start :: pos_integer().
sub_string(String, Start) -> substr(String, Start).
--spec sub_string(string(), pos_integer(), pos_integer()) -> string().
+-spec sub_string(String, Start, Stop) -> SubString when
+ String :: string(),
+ SubString :: string(),
+ Start :: pos_integer(),
+ Stop :: pos_integer().
sub_string(String, Start, Stop) -> substr(String, Start, Stop - Start + 1).
@@ -370,23 +458,34 @@ to_upper_char(C) when is_integer(C), 16#F8 =< C, C =< 16#FE ->
to_upper_char(C) ->
C.
--spec to_lower(string()) -> string()
- ; (char()) -> char().
+-spec to_lower(String) -> Result when
+ String :: string(),
+ Result :: string()
+ ; (Char) -> CharResult when
+ Char :: char(),
+ CharResult :: char().
to_lower(S) when is_list(S) ->
[to_lower_char(C) || C <- S];
to_lower(C) when is_integer(C) ->
to_lower_char(C).
--spec to_upper(string()) -> string()
- ; (char()) -> char().
+-spec to_upper(String) -> Result when
+ String :: string(),
+ Result :: string()
+ ; (Char) -> CharResult when
+ Char :: char(),
+ CharResult :: char().
to_upper(S) when is_list(S) ->
[to_upper_char(C) || C <- S];
to_upper(C) when is_integer(C) ->
to_upper_char(C).
--spec join([string()], string()) -> string().
+-spec join(StringList, Separator) -> String when
+ StringList :: [string()],
+ Separator :: string(),
+ String :: string().
join([], Sep) when is_list(Sep) ->
[];
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 3c5800effa..9da0d52f8c 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -27,27 +27,34 @@
which_children/1, count_children/1,
check_childspecs/1]).
--export([behaviour_info/1]).
-
%% Internal exports
-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]).
-export([handle_cast/2]).
%%--------------------------------------------------------------------------
--export_type([child_spec/0, del_err/0, startchild_ret/0, strategy/0]).
+-export_type([child_spec/0, startchild_ret/0, strategy/0]).
%%--------------------------------------------------------------------------
--type child_id() :: pid() | 'undefined'.
--type mfargs() :: {module(), atom(), [term()] | undefined}.
+-type child() :: pid() | 'undefined'.
+-type child_id() :: term().
+-type mfargs() :: {M :: module(), F :: atom(), A :: [term()] | undefined}.
-type modules() :: [module()] | 'dynamic'.
-type restart() :: 'permanent' | 'transient' | 'temporary'.
-type shutdown() :: 'brutal_kill' | timeout().
-type worker() :: 'worker' | 'supervisor'.
--type sup_name() :: {'local', atom()} | {'global', atom()}.
--type sup_ref() :: atom() | {atom(), atom()} | {'global', atom()} | pid().
--type child_spec() :: {term(),mfargs(),restart(),shutdown(),worker(),modules()}.
+-type sup_name() :: {'local', Name :: atom()} | {'global', Name :: atom()}.
+-type sup_ref() :: (Name :: atom())
+ | {Name :: atom(), Node :: node()}
+ | {'global', Name :: atom()}
+ | pid().
+-type child_spec() :: {Id :: child_id(),
+ StartFunc :: mfargs(),
+ Restart :: restart(),
+ Shutdown :: shutdown(),
+ Type :: worker(),
+ Modules :: modules()}.
-type strategy() :: 'one_for_all' | 'one_for_one'
| 'rest_for_one' | 'simple_one_for_one'.
@@ -55,21 +62,23 @@
%%--------------------------------------------------------------------------
-record(child, {% pid is undefined when child is not running
- pid = undefined :: child_id(),
+ pid = undefined :: child(),
name,
mfargs :: mfargs(),
restart_type :: restart(),
shutdown :: shutdown(),
child_type :: worker(),
modules = [] :: modules()}).
--type child() :: #child{}.
+-type child_rec() :: #child{}.
-define(DICT, dict).
+-define(SETS, sets).
+-define(SET, set).
-record(state, {name,
strategy :: strategy(),
- children = [] :: [child()],
- dynamics :: ?DICT() | list(),
+ children = [] :: [child_rec()],
+ dynamics :: ?DICT() | ?SET(),
intensity :: non_neg_integer(),
period :: pos_integer(),
restarts = [],
@@ -79,14 +88,12 @@
-define(is_simple(State), State#state.strategy =:= simple_one_for_one).
-%%--------------------------------------------------------------------------
-
--spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}].
-
-behaviour_info(callbacks) ->
- [{init,1}];
-behaviour_info(_Other) ->
- undefined.
+-callback init(Args :: term()) ->
+ {ok, {{RestartStrategy :: strategy(),
+ MaxR :: non_neg_integer(),
+ MaxT :: non_neg_integer()},
+ [ChildSpec :: child_spec()]}}
+ | ignore.
%%% ---------------------------------------------------
%%% This is a general process supervisor built upon gen_server.erl.
@@ -97,11 +104,16 @@ behaviour_info(_Other) ->
-type startlink_err() :: {'already_started', pid()} | 'shutdown' | term().
-type startlink_ret() :: {'ok', pid()} | 'ignore' | {'error', startlink_err()}.
--spec start_link(module(), term()) -> startlink_ret().
+-spec start_link(Module, Args) -> startlink_ret() when
+ Module :: module(),
+ Args :: term().
start_link(Mod, Args) ->
gen_server:start_link(supervisor, {self, Mod, Args}, []).
--spec start_link(sup_name(), module(), term()) -> startlink_ret().
+-spec start_link(SupName, Module, Args) -> startlink_ret() when
+ SupName :: sup_name(),
+ Module :: module(),
+ Args :: term().
start_link(SupName, Mod, Args) ->
gen_server:start_link(SupName, supervisor, {SupName, Mod, Args}, []).
@@ -109,24 +121,33 @@ start_link(SupName, Mod, Args) ->
%%% Interface functions.
%%% ---------------------------------------------------
--type info() :: term().
-type startchild_err() :: 'already_present'
- | {'already_started', child_id()} | term().
--type startchild_ret() :: {'ok', child_id()} | {'ok', child_id(), info()}
+ | {'already_started', Child :: child()} | term().
+-type startchild_ret() :: {'ok', Child :: child()}
+ | {'ok', Child :: child(), Info :: term()}
| {'error', startchild_err()}.
--spec start_child(sup_ref(), child_spec() | [term()]) -> startchild_ret().
+-spec start_child(SupRef, ChildSpec) -> startchild_ret() when
+ SupRef :: sup_ref(),
+ ChildSpec :: child_spec() | (List :: [term()]).
start_child(Supervisor, ChildSpec) ->
call(Supervisor, {start_child, ChildSpec}).
--type restart_err() :: 'running' | 'not_found' | 'simple_one_for_one' | term().
--spec restart_child(sup_ref(), term()) ->
- {'ok', child_id()} | {'ok', child_id(), info()} | {'error', restart_err()}.
+-spec restart_child(SupRef, Id) -> Result when
+ SupRef :: sup_ref(),
+ Id :: child_id(),
+ Result :: {'ok', Child :: child()}
+ | {'ok', Child :: child(), Info :: term()}
+ | {'error', Error},
+ Error :: 'running' | 'not_found' | 'simple_one_for_one' | term().
restart_child(Supervisor, Name) ->
call(Supervisor, {restart_child, Name}).
--type del_err() :: 'running' | 'not_found' | 'simple_one_for_one'.
--spec delete_child(sup_ref(), term()) -> 'ok' | {'error', del_err()}.
+-spec delete_child(SupRef, Id) -> Result when
+ SupRef :: sup_ref(),
+ Id :: child_id(),
+ Result :: 'ok' | {'error', Error},
+ Error :: 'running' | 'not_found' | 'simple_one_for_one'.
delete_child(Supervisor, Name) ->
call(Supervisor, {delete_child, Name}).
@@ -137,22 +158,39 @@ delete_child(Supervisor, Name) ->
%% way (maybe killed).
%%-----------------------------------------------------------------
--type term_err() :: 'not_found' | 'simple_one_for_one'.
--spec terminate_child(sup_ref(), term()) -> 'ok' | {'error', term_err()}.
+-spec terminate_child(SupRef, Id) -> Result when
+ SupRef :: sup_ref(),
+ Id :: pid() | child_id(),
+ Result :: 'ok' | {'error', Error},
+ Error :: 'not_found' | 'simple_one_for_one'.
terminate_child(Supervisor, Name) ->
call(Supervisor, {terminate_child, Name}).
--spec which_children(sup_ref()) -> [{term(), child_id(), worker(), modules()}].
+-spec which_children(SupRef) -> [{Id,Child,Type,Modules}] when
+ SupRef :: sup_ref(),
+ Id :: child_id() | undefined,
+ Child :: child(),
+ Type :: worker(),
+ Modules :: modules().
which_children(Supervisor) ->
call(Supervisor, which_children).
+-spec count_children(SupRef) -> PropListOfCounts when
+ SupRef :: sup_ref(),
+ PropListOfCounts :: [Count],
+ Count :: {specs, ChildSpecCount :: non_neg_integer()}
+ | {active, ActiveProcessCount :: non_neg_integer()}
+ | {supervisors, ChildSupervisorCount :: non_neg_integer()}
+ |{workers, ChildWorkerCount :: non_neg_integer()}.
count_children(Supervisor) ->
call(Supervisor, count_children).
call(Supervisor, Req) ->
gen_server:call(Supervisor, Req, infinity).
--spec check_childspecs([child_spec()]) -> 'ok' | {'error', term()}.
+-spec check_childspecs(ChildSpecs) -> Result when
+ ChildSpecs :: [child_spec()],
+ Result :: 'ok' | {'error', Error :: term()}.
check_childspecs(ChildSpecs) when is_list(ChildSpecs) ->
case check_startspec(ChildSpecs) of
{ok, _} -> ok;
@@ -220,12 +258,12 @@ init_dynamic(_State, StartSpec) ->
%%-----------------------------------------------------------------
%% Func: start_children/2
-%% Args: Children = [child()] in start order
+%% Args: Children = [child_rec()] in start order
%% SupName = {local, atom()} | {global, atom()} | {pid(), Mod}
%% Purpose: Start all children. The new list contains #child's
%% with pids.
%% Returns: {ok, NChildren} | {error, NChildren}
-%% NChildren = [child()] in termination order (reversed
+%% NChildren = [child_rec()] in termination order (reversed
%% start order)
%%-----------------------------------------------------------------
start_children(Children, SupName) -> start_children(Children, [], SupName).
@@ -297,8 +335,26 @@ handle_call({start_child, EArgs}, _From, State) when ?is_simple(State) ->
{reply, What, State}
end;
-%%% The requests terminate_child, delete_child and restart_child are
-%%% invalid for simple_one_for_one supervisors.
+%% terminate_child for simple_one_for_one can only be done with pid
+handle_call({terminate_child, Name}, _From, State) when not is_pid(Name),
+ ?is_simple(State) ->
+ {reply, {error, simple_one_for_one}, State};
+
+handle_call({terminate_child, Name}, _From, State) ->
+ case get_child(Name, State, ?is_simple(State)) of
+ {value, Child} ->
+ case do_terminate(Child, State#state.name) of
+ #child{restart_type=RT} when RT=:=temporary; ?is_simple(State) ->
+ {reply, ok, state_del_child(Child, State)};
+ NChild ->
+ {reply, ok, replace_child(NChild, State)}
+ end;
+ false ->
+ {reply, {error, not_found}, State}
+ end;
+
+%%% The requests delete_child and restart_child are invalid for
+%%% simple_one_for_one supervisors.
handle_call({_Req, _Data}, _From, State) when ?is_simple(State) ->
{reply, {error, simple_one_for_one}, State};
@@ -341,21 +397,12 @@ handle_call({delete_child, Name}, _From, State) ->
{reply, {error, not_found}, State}
end;
-handle_call({terminate_child, Name}, _From, State) ->
- case get_child(Name, State) of
- {value, Child} ->
- NChild = do_terminate(Child, State#state.name),
- {reply, ok, replace_child(NChild, State)};
- _ ->
- {reply, {error, not_found}, State}
- end;
-
handle_call(which_children, _From, #state{children = [#child{restart_type = temporary,
child_type = CT,
modules = Mods}]} =
State) when ?is_simple(State) ->
- Reply = lists:map(fun(Pid) -> {undefined, Pid, CT, Mods} end, dynamics_db(temporary,
- State#state.dynamics)),
+ Reply = lists:map(fun(Pid) -> {undefined, Pid, CT, Mods} end,
+ ?SETS:to_list(dynamics_db(temporary, State#state.dynamics))),
{reply, Reply, State};
handle_call(which_children, _From, #state{children = [#child{restart_type = RType,
@@ -380,7 +427,7 @@ handle_call(count_children, _From, #state{children = [#child{restart_type = temp
child_type = CT}]} = State)
when ?is_simple(State) ->
{Active, Count} =
- lists:foldl(fun(Pid, {Alive, Tot}) ->
+ ?SETS:fold(fun(Pid, {Alive, Tot}) ->
if is_pid(Pid) -> {Alive+1, Tot +1};
true -> {Alive, Tot + 1} end
end, {0, 0}, dynamics_db(temporary, State#state.dynamics)),
@@ -610,6 +657,9 @@ do_restart(_, normal, Child, State) ->
do_restart(_, shutdown, Child, State) ->
NState = state_del_child(Child, State),
{ok, NState};
+do_restart(_, {shutdown, _Term}, Child, State) ->
+ NState = state_del_child(Child, State),
+ {ok, NState};
do_restart(transient, Reason, Child, State) ->
report_error(child_terminated, Reason, Child, State#state.name),
restart(Child, State);
@@ -676,14 +726,21 @@ restart(one_for_all, Child, State) ->
%%-----------------------------------------------------------------
%% Func: terminate_children/2
-%% Args: Children = [child()] in termination order
+%% Args: Children = [child_rec()] in termination order
%% SupName = {local, atom()} | {global, atom()} | {pid(),Mod}
-%% Returns: NChildren = [child()] in
+%% Returns: NChildren = [child_rec()] in
%% startup order (reversed termination order)
%%-----------------------------------------------------------------
terminate_children(Children, SupName) ->
terminate_children(Children, SupName, []).
+%% Temporary children should not be restarted and thus should
+%% be skipped when building the list of terminated children, although
+%% we do want them to be shut down as many functions from this module
+%% use this function to just clear everything.
+terminate_children([Child = #child{restart_type=temporary} | Children], SupName, Res) ->
+ do_terminate(Child, SupName),
+ terminate_children(Children, SupName, Res);
terminate_children([Child | Children], SupName, Res) ->
NChild = do_terminate(Child, SupName),
terminate_children(Children, SupName, [NChild | Res]);
@@ -791,24 +848,27 @@ save_child(Child, #state{children = Children} = State) ->
State#state{children = [Child |Children]}.
save_dynamic_child(temporary, Pid, _, #state{dynamics = Dynamics} = State) ->
- State#state{dynamics = [Pid | dynamics_db(temporary, Dynamics)]};
+ State#state{dynamics = ?SETS:add_element(Pid, dynamics_db(temporary, Dynamics))};
save_dynamic_child(RestartType, Pid, Args, #state{dynamics = Dynamics} = State) ->
State#state{dynamics = ?DICT:store(Pid, Args, dynamics_db(RestartType, Dynamics))}.
dynamics_db(temporary, undefined) ->
- [];
+ ?SETS:new();
dynamics_db(_, undefined) ->
?DICT:new();
dynamics_db(_,Dynamics) ->
Dynamics.
-dynamic_child_args(_, Dynamics) when is_list(Dynamics)->
- {ok, undefined};
dynamic_child_args(Pid, Dynamics) ->
- ?DICT:find(Pid, Dynamics).
+ case ?SETS:is_set(Dynamics) of
+ true ->
+ {ok, undefined};
+ false ->
+ ?DICT:find(Pid, Dynamics)
+ end.
state_del_child(#child{pid = Pid, restart_type = temporary}, State) when ?is_simple(State) ->
- NDynamics = lists:delete(Pid, dynamics_db(temporary, State#state.dynamics)),
+ NDynamics = ?SETS:del_element(Pid, dynamics_db(temporary, State#state.dynamics)),
State#state{dynamics = NDynamics};
state_del_child(#child{pid = Pid, restart_type = RType}, State) when ?is_simple(State) ->
NDynamics = ?DICT:erase(Pid, dynamics_db(RType, State#state.dynamics)),
@@ -817,8 +877,12 @@ state_del_child(Child, State) ->
NChildren = del_child(Child#child.name, State#state.children),
State#state{children = NChildren}.
+del_child(Name, [Ch|Chs]) when Ch#child.name =:= Name, Ch#child.restart_type =:= temporary ->
+ Chs;
del_child(Name, [Ch|Chs]) when Ch#child.name =:= Name ->
[Ch#child{pid = undefined} | Chs];
+del_child(Pid, [Ch|Chs]) when Ch#child.pid =:= Pid, Ch#child.restart_type =:= temporary ->
+ Chs;
del_child(Pid, [Ch|Chs]) when Ch#child.pid =:= Pid ->
[Ch#child{pid = undefined} | Chs];
del_child(Name, [Ch|Chs]) ->
@@ -841,7 +905,31 @@ split_child(_, [], After) ->
{lists:reverse(After), []}.
get_child(Name, State) ->
+ get_child(Name, State, false).
+get_child(Pid, State, AllowPid) when AllowPid, is_pid(Pid) ->
+ get_dynamic_child(Pid, State);
+get_child(Name, State, _) ->
lists:keysearch(Name, #child.name, State#state.children).
+
+get_dynamic_child(Pid, #state{children=[Child], dynamics=Dynamics}) ->
+ case is_dynamic_pid(Pid, dynamics_db(Child#child.restart_type, Dynamics)) of
+ true ->
+ {value, Child#child{pid=Pid}};
+ false ->
+ case erlang:is_process_alive(Pid) of
+ true -> false;
+ false -> {value, Child}
+ end
+ end.
+
+is_dynamic_pid(Pid, Dynamics) ->
+ case ?SETS:is_set(Dynamics) of
+ true ->
+ ?SETS:is_element(Pid, Dynamics);
+ false ->
+ ?DICT:is_key(Pid, Dynamics)
+ end.
+
replace_child(Child, State) ->
Chs = do_replace_child(Child, State#state.children),
State#state{children = Chs}.
@@ -916,7 +1004,7 @@ supname(N, _) -> N.
%%% Shutdown = integer() | infinity | brutal_kill
%%% ChildType = supervisor | worker
%%% Modules = [atom()] | dynamic
-%%% Returns: {ok, [child()]} | Error
+%%% Returns: {ok, [child_rec()]} | Error
%%% ------------------------------------------------------
check_startspec(Children) -> check_startspec(Children, []).
diff --git a/lib/stdlib/src/supervisor_bridge.erl b/lib/stdlib/src/supervisor_bridge.erl
index 3d2bd2c9a5..e8405ab9a4 100644
--- a/lib/stdlib/src/supervisor_bridge.erl
+++ b/lib/stdlib/src/supervisor_bridge.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,15 +22,14 @@
%% External exports
-export([start_link/2, start_link/3]).
--export([behaviour_info/1]).
%% Internal exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
-export([code_change/3]).
-behaviour_info(callbacks) ->
- [{init,1},{terminate,2}];
-behaviour_info(_Other) ->
- undefined.
+-callback init(Args :: term()) ->
+ {ok, Pid :: pid(), State :: term()} | ignore | {error, Error :: term()}.
+-callback terminate(Reason :: (shutdown | term()), State :: term()) ->
+ Ignored :: term().
%%%-----------------------------------------------------------------
%%% This is a rewrite of supervisor_bridge from BS.3.
@@ -49,9 +48,25 @@ behaviour_info(_Other) ->
%%%-----------------------------------------------------------------
-record(state, {mod, pid, child_state, name}).
+-spec start_link(Module, Args) -> Result when
+ Module :: module(),
+ Args :: term(),
+ Result :: {ok, Pid} | ignore | {error, Error},
+ Error :: {already_started, Pid} | term(),
+ Pid :: pid().
+
start_link(Mod, StartArgs) ->
gen_server:start_link(supervisor_bridge, [Mod, StartArgs, self], []).
+-spec start_link(SupBridgeName, Module, Args) -> Result when
+ SupBridgeName :: {local, Name} | {global, Name},
+ Name :: atom(),
+ Module :: module(),
+ Args :: term(),
+ Result :: {ok, Pid} | ignore | {error, Error},
+ Error :: {already_started, Pid} | term(),
+ Pid :: pid().
+
start_link(Name, Mod, StartArgs) ->
gen_server:start_link(Name, supervisor_bridge, [Mod, StartArgs, Name], []).
diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl
index 12209c16d7..f34201604c 100644
--- a/lib/stdlib/src/sys.erl
+++ b/lib/stdlib/src/sys.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -33,22 +33,74 @@
%%-----------------------------------------------------------------
-type name() :: pid() | atom() | {'global', atom()}.
--type system_event() :: {'in', _Msg} | {'in', _Msg, _From} | {'out', _Msg, _To}.
+-type system_event() :: {'in', Msg :: _}
+ | {'in', Msg :: _, From :: _}
+ | {'out', Msg :: _, To :: _}
+ | term().
+-opaque dbg_opt() :: list().
+-type dbg_fun() :: fun((FuncState :: _,
+ Event :: system_event(),
+ ProcState :: _) -> 'done' | (NewFuncState :: _)).
%%-----------------------------------------------------------------
%% System messages
%%-----------------------------------------------------------------
+-spec suspend(Name) -> Void when
+ Name :: name(),
+ Void :: term().
suspend(Name) -> send_system_msg(Name, suspend).
+-spec suspend(Name, Timeout) -> Void when
+ Name :: name(),
+ Timeout :: timeout(),
+ Void :: term().
suspend(Name, Timeout) -> send_system_msg(Name, suspend, Timeout).
+-spec resume(Name) -> Void when
+ Name :: name(),
+ Void :: term().
resume(Name) -> send_system_msg(Name, resume).
+-spec resume(Name, Timeout) -> Void when
+ Name :: name(),
+ Timeout :: timeout(),
+ Void :: term().
resume(Name, Timeout) -> send_system_msg(Name, resume, Timeout).
+-spec get_status(Name) -> Status when
+ Name :: name(),
+ Status :: {status, Pid :: pid(), {module, Module :: module()}, [SItem]},
+ SItem :: (PDict :: [{Key :: term(), Value :: term()}])
+ | (SysState :: 'running' | 'suspended')
+ | (Parent :: pid())
+ | (Dbg :: dbg_opt())
+ | (Misc :: term()).
get_status(Name) -> send_system_msg(Name, get_status).
+-spec get_status(Name, Timeout) -> Status when
+ Name :: name(),
+ Timeout :: timeout(),
+ Status :: {status, Pid :: pid(), {module, Module :: module()}, [SItem]},
+ SItem :: (PDict :: [{Key :: term(), Value :: term()}])
+ | (SysState :: 'running' | 'suspended')
+ | (Parent :: pid())
+ | (Dbg :: dbg_opt())
+ | (Misc :: term()).
get_status(Name, Timeout) -> send_system_msg(Name, get_status, Timeout).
+-spec change_code(Name, Module, OldVsn, Extra) -> 'ok' | {error, Reason} when
+ Name :: name(),
+ Module :: module(),
+ OldVsn :: 'undefined' | term(),
+ Extra :: term(),
+ Reason :: term().
change_code(Name, Mod, Vsn, Extra) ->
send_system_msg(Name, {change_code, Mod, Vsn, Extra}).
+-spec change_code(Name, Module, OldVsn, Extra, Timeout) ->
+ 'ok' | {error, Reason} when
+ Name :: name(),
+ Module :: module(),
+ OldVsn :: 'undefined' | term(),
+ Extra :: term(),
+ Timeout :: timeout(),
+ Reason :: term().
change_code(Name, Mod, Vsn, Extra, Timeout) ->
send_system_msg(Name, {change_code, Mod, Vsn, Extra}, Timeout).
@@ -56,52 +108,116 @@ change_code(Name, Mod, Vsn, Extra, Timeout) ->
%% Debug commands
%%-----------------------------------------------------------------
--type log_flag() :: 'true' | {'true',pos_integer()} | 'false' | 'get' | 'print'.
-
--spec log(name(), log_flag()) -> 'ok' | {'ok', [system_event()]}.
+-spec log(Name, Flag) -> 'ok' | {'ok', [system_event()]} when
+ Name :: name(),
+ Flag :: 'true' |
+ {'true', N :: pos_integer()}
+ | 'false' | 'get' | 'print'.
log(Name, Flag) ->
send_system_msg(Name, {debug, {log, Flag}}).
--spec log(name(), log_flag(), timeout()) -> 'ok' | {'ok', [system_event()]}.
+-spec log(Name, Flag, Timeout) -> 'ok' | {'ok', [system_event()]} when
+ Name :: name(),
+ Flag :: 'true' |
+ {'true', N :: pos_integer()}
+ | 'false' | 'get' | 'print',
+ Timeout :: timeout().
log(Name, Flag, Timeout) ->
send_system_msg(Name, {debug, {log, Flag}}, Timeout).
--spec trace(name(), boolean()) -> 'ok'.
+-spec trace(Name, Flag) -> 'ok' when
+ Name :: name(),
+ Flag :: boolean().
trace(Name, Flag) ->
send_system_msg(Name, {debug, {trace, Flag}}).
--spec trace(name(), boolean(), timeout()) -> 'ok'.
+-spec trace(Name, Flag, Timeout) -> 'ok' when
+ Name :: name(),
+ Flag :: boolean(),
+ Timeout :: timeout().
trace(Name, Flag, Timeout) ->
send_system_msg(Name, {debug, {trace, Flag}}, Timeout).
--type l2f_fname() :: string() | 'false'.
-
--spec log_to_file(name(), l2f_fname()) -> 'ok' | {'error','open_file'}.
+-spec log_to_file(Name, Flag) -> 'ok' | {'error','open_file'} when
+ Name :: name(),
+ Flag :: (FileName :: string()) | 'false'.
log_to_file(Name, FileName) ->
send_system_msg(Name, {debug, {log_to_file, FileName}}).
--spec log_to_file(name(), l2f_fname(), timeout()) -> 'ok' | {'error','open_file'}.
+-spec log_to_file(Name, Flag, Timeout) -> 'ok' | {'error','open_file'} when
+ Name :: name(),
+ Flag :: (FileName :: string()) | 'false',
+ Timeout :: timeout().
log_to_file(Name, FileName, Timeout) ->
send_system_msg(Name, {debug, {log_to_file, FileName}}, Timeout).
+-spec statistics(Name, Flag) -> 'ok' | {'ok', Statistics} when
+ Name :: name(),
+ Flag :: 'true' | 'false' | 'get',
+ Statistics :: [StatisticsTuple] | no_statistics,
+ StatisticsTuple :: {'start_time', DateTime1}
+ | {'current_time', DateTime2}
+ | {'reductions', non_neg_integer()}
+ | {'messages_in', non_neg_integer()}
+ | {'messages_out', non_neg_integer()},
+ DateTime1 :: file:date_time(),
+ DateTime2 :: file:date_time().
statistics(Name, Flag) ->
send_system_msg(Name, {debug, {statistics, Flag}}).
+
+-spec statistics(Name, Flag, Timeout) -> 'ok' | {'ok', Statistics} when
+ Name :: name(),
+ Flag :: 'true' | 'false' | 'get',
+ Statistics :: [StatisticsTuple] | no_statistics,
+ StatisticsTuple :: {'start_time', DateTime1}
+ | {'current_time', DateTime2}
+ | {'reductions', non_neg_integer()}
+ | {'messages_in', non_neg_integer()}
+ | {'messages_out', non_neg_integer()},
+ DateTime1 :: file:date_time(),
+ DateTime2 :: file:date_time(),
+ Timeout :: timeout().
statistics(Name, Flag, Timeout) ->
send_system_msg(Name, {debug, {statistics, Flag}}, Timeout).
--spec no_debug(name()) -> 'ok'.
+-spec no_debug(Name) -> 'ok' when
+ Name :: name().
no_debug(Name) -> send_system_msg(Name, {debug, no_debug}).
--spec no_debug(name(), timeout()) -> 'ok'.
+-spec no_debug(Name, Timeout) -> 'ok' when
+ Name :: name(),
+ Timeout :: timeout().
no_debug(Name, Timeout) -> send_system_msg(Name, {debug, no_debug}, Timeout).
+-spec install(Name, FuncSpec) -> Void when
+ Name :: name(),
+ FuncSpec :: {Func, FuncState},
+ Func :: dbg_fun(),
+ FuncState :: term(),
+ Void :: term().
install(Name, {Func, FuncState}) ->
send_system_msg(Name, {debug, {install, {Func, FuncState}}}).
+-spec install(Name, FuncSpec, Timeout) -> Void when
+ Name :: name(),
+ FuncSpec :: {Func, FuncState},
+ Func :: dbg_fun(),
+ FuncState :: term(),
+ Timeout :: timeout(),
+ Void :: term().
install(Name, {Func, FuncState}, Timeout) ->
send_system_msg(Name, {debug, {install, {Func, FuncState}}}, Timeout).
+-spec remove(Name, Func) -> Void when
+ Name :: name(),
+ Func :: dbg_fun(),
+ Void :: term().
remove(Name, Func) ->
send_system_msg(Name, {debug, {remove, Func}}).
+-spec remove(Name, Func, Timeout) -> Void when
+ Name :: name(),
+ Func :: dbg_fun(),
+ Timeout :: timeout(),
+ Void :: term().
remove(Name, Func, Timeout) ->
send_system_msg(Name, {debug, {remove, Func}}, Timeout).
@@ -150,6 +266,14 @@ mfa(Name, Req, Timeout) ->
%% The Module must export system_continue/3, system_terminate/4
%% and format_status/2 for status information.
%%-----------------------------------------------------------------
+-spec handle_system_msg(Msg, From, Parent, Module, Debug, Misc) -> Void when
+ Msg :: term(),
+ From :: {pid(), Tag :: _},
+ Parent :: pid(),
+ Module :: module(),
+ Debug :: [dbg_opt()],
+ Misc :: term(),
+ Void :: term().
handle_system_msg(Msg, From, Parent, Module, Debug, Misc) ->
handle_system_msg(running, Msg, From, Parent, Module, Debug, Misc, false).
@@ -176,6 +300,11 @@ handle_system_msg(SysState, Msg, From, Parent, Mod, Debug, Misc, Hib) ->
%% Func is a formatting function, called as Func(Device, Event).
%% Returns: [debug_opts()]
%%-----------------------------------------------------------------
+-spec handle_debug(Debug, FormFunc, Extra, Event) -> [dbg_opt()] when
+ Debug :: [dbg_opt()],
+ FormFunc :: dbg_fun(),
+ Extra :: term(),
+ Event :: system_event().
handle_debug([{trace, true} | T], FormFunc, State, Event) ->
print_event({Event, State, FormFunc}),
[{trace, true} | handle_debug(T, FormFunc, State, Event)];
@@ -341,24 +470,36 @@ trim(N, LogData) ->
%% Debug structure manipulating functions
%%-----------------------------------------------------------------
install_debug(Item, Data, Debug) ->
- case get_debug(Item, Debug, undefined) of
+ case get_debug2(Item, Debug, undefined) of
undefined -> [{Item, Data} | Debug];
_ -> Debug
end.
remove_debug(Item, Debug) -> lists:keydelete(Item, 1, Debug).
+
+-spec get_debug(Item, Debug, Default) -> term() when
+ Item :: 'log' | 'statistics',
+ Debug :: [dbg_opt()],
+ Default :: term().
get_debug(Item, Debug, Default) ->
+ get_debug2(Item, Debug, Default).
+
+%% Workaround: accepts more Item types than get_debug/3.
+get_debug2(Item, Debug, Default) ->
case lists:keysearch(Item, 1, Debug) of
{value, {Item, Data}} -> Data;
_ -> Default
end.
+-spec print_log(Debug) -> Void when
+ Debug :: [dbg_opt()],
+ Void :: term().
print_log(Debug) ->
{_N, Logs} = get_debug(log, Debug, {0, []}),
lists:foreach(fun print_event/1,
lists:reverse(Logs)).
close_log_file(Debug) ->
- case get_debug(log_to_file, Debug, []) of
+ case get_debug2(log_to_file, Debug, []) of
[] ->
Debug;
Fd ->
@@ -375,6 +516,15 @@ close_log_file(Debug) ->
%% system messages.
%% Returns: [debug_opts()]
%%-----------------------------------------------------------------
+
+-spec debug_options(Options) -> [dbg_opt()] when
+ Options :: [Opt],
+ Opt :: 'trace' | 'log' | 'statistics' | {'log_to_file', FileName}
+ | {'install', FuncSpec},
+ FileName :: file:name(),
+ FuncSpec :: {Func, FuncState},
+ Func :: dbg_fun(),
+ FuncState :: term().
debug_options(Options) ->
debug_options(Options, []).
debug_options([trace | T], Debug) ->
diff --git a/lib/stdlib/src/timer.erl b/lib/stdlib/src/timer.erl
index b456c5d6c1..689e42051f 100644
--- a/lib/stdlib/src/timer.erl
+++ b/lib/stdlib/src/timer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,7 +22,7 @@
send_after/3, send_after/2,
exit_after/3, exit_after/2, kill_after/2, kill_after/1,
apply_interval/4, send_interval/3, send_interval/2,
- cancel/1, sleep/1, tc/2, tc/3, now_diff/2,
+ cancel/1, sleep/1, tc/1, tc/2, tc/3, now_diff/2,
seconds/1, minutes/1, hours/1, hms/3]).
-export([start_link/0, start/0,
@@ -46,103 +46,189 @@
%%
-opaque tref() :: {integer(), reference()}.
-type time() :: non_neg_integer().
--type timestamp() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}.
%%
%% Interface functions
%%
--spec apply_after(time(), atom(), atom(), [term()]) -> {'ok', tref()} | {'error', term()}.
+-spec apply_after(Time, Module, Function, Arguments) ->
+ {'ok', TRef} | {'error', Reason} when
+ Time :: time(),
+ Module :: module(),
+ Function :: atom(),
+ Arguments :: [term()],
+ TRef :: tref(),
+ Reason :: term().
+
apply_after(Time, M, F, A) ->
req(apply_after, {Time, {M, F, A}}).
--spec send_after(time(), pid() | atom(), term()) -> {'ok', tref()} | {'error', term()}.
+-spec send_after(Time, Pid, Message) -> {'ok', TRef} | {'error', Reason} when
+ Time :: time(),
+ Pid :: pid() | (RegName :: atom()),
+ Message :: term(),
+ TRef :: tref(),
+ Reason :: term().
send_after(Time, Pid, Message) ->
req(apply_after, {Time, {?MODULE, send, [Pid, Message]}}).
--spec send_after(time(), term()) -> {'ok', tref()} | {'error', term()}.
+-spec send_after(Time, Message) -> {'ok', TRef} | {'error', Reason} when
+ Time :: time(),
+ Message :: term(),
+ TRef :: tref(),
+ Reason :: term().
send_after(Time, Message) ->
send_after(Time, self(), Message).
--spec exit_after(time(), pid() | atom(), term()) -> {'ok', tref()} | {'error', term()}.
+-spec exit_after(Time, Pid, Reason1) -> {'ok', TRef} | {'error', Reason2} when
+ Time :: time(),
+ Pid :: pid() | (RegName :: atom()),
+ TRef :: tref(),
+ Reason1 :: term(),
+ Reason2 :: term().
exit_after(Time, Pid, Reason) ->
req(apply_after, {Time, {erlang, exit, [Pid, Reason]}}).
--spec exit_after(time(), term()) -> {'ok', tref()} | {'error', term()}.
+-spec exit_after(Time, Reason1) -> {'ok', TRef} | {'error', Reason2} when
+ Time :: time(),
+ TRef :: tref(),
+ Reason1 :: term(),
+ Reason2 :: term().
exit_after(Time, Reason) ->
exit_after(Time, self(), Reason).
--spec kill_after(time(), pid() | atom()) -> {'ok', tref()} | {'error', term()}.
+-spec kill_after(Time, Pid) -> {'ok', TRef} | {'error', Reason2} when
+ Time :: time(),
+ Pid :: pid() | (RegName :: atom()),
+ TRef :: tref(),
+ Reason2 :: term().
kill_after(Time, Pid) ->
exit_after(Time, Pid, kill).
--spec kill_after(time()) -> {'ok', tref()} | {'error', term()}.
+-spec kill_after(Time) -> {'ok', TRef} | {'error', Reason2} when
+ Time :: time(),
+ TRef :: tref(),
+ Reason2 :: term().
kill_after(Time) ->
exit_after(Time, self(), kill).
--spec apply_interval(time(), atom(), atom(), [term()]) -> {'ok', tref()} | {'error', term()}.
+-spec apply_interval(Time, Module, Function, Arguments) ->
+ {'ok', TRef} | {'error', Reason} when
+ Time :: time(),
+ Module :: module(),
+ Function :: atom(),
+ Arguments :: [term()],
+ TRef :: tref(),
+ Reason :: term().
apply_interval(Time, M, F, A) ->
req(apply_interval, {Time, self(), {M, F, A}}).
--spec send_interval(time(), pid() | atom(), term()) -> {'ok', tref()} | {'error', term()}.
+-spec send_interval(Time, Pid, Message) ->
+ {'ok', TRef} | {'error', Reason} when
+ Time :: time(),
+ Pid :: pid() | (RegName :: atom()),
+ Message :: term(),
+ TRef :: tref(),
+ Reason :: term().
send_interval(Time, Pid, Message) ->
req(apply_interval, {Time, Pid, {?MODULE, send, [Pid, Message]}}).
--spec send_interval(time(), term()) -> {'ok', tref()} | {'error', term()}.
+-spec send_interval(Time, Message) -> {'ok', TRef} | {'error', Reason} when
+ Time :: time(),
+ Message :: term(),
+ TRef :: tref(),
+ Reason :: term().
send_interval(Time, Message) ->
send_interval(Time, self(), Message).
--spec cancel(tref()) -> {'ok', 'cancel'} | {'error', term()}.
+-spec cancel(TRef) -> {'ok', 'cancel'} | {'error', Reason} when
+ TRef :: tref(),
+ Reason :: term().
cancel(BRef) ->
req(cancel, BRef).
--spec sleep(timeout()) -> 'ok'.
+-spec sleep(Time) -> 'ok' when
+ Time :: timeout().
sleep(T) ->
receive
after T -> ok
end.
+%%
+%% Measure the execution time (in microseconds) for Fun().
+%%
+-spec tc(Fun) -> {Time, Value} when
+ Fun :: function(),
+ Time :: integer(),
+ Value :: term().
+tc(F) ->
+ Before = os:timestamp(),
+ Val = F(),
+ After = os:timestamp(),
+ {now_diff(After, Before), Val}.
%%
%% Measure the execution time (in microseconds) for Fun(Args).
%%
--spec tc(function(), [_]) -> {time(), term()}.
+-spec tc(Fun, Arguments) -> {Time, Value} when
+ Fun :: function(),
+ Arguments :: [term()],
+ Time :: integer(),
+ Value :: term().
tc(F, A) ->
- Before = erlang:now(),
- Val = (catch apply(F, A)),
- After = erlang:now(),
+ Before = os:timestamp(),
+ Val = apply(F, A),
+ After = os:timestamp(),
{now_diff(After, Before), Val}.
%%
%% Measure the execution time (in microseconds) for an MFA.
%%
--spec tc(atom(), atom(), [term()]) -> {time(), term()}.
+-spec tc(Module, Function, Arguments) -> {Time, Value} when
+ Module :: module(),
+ Function :: atom(),
+ Arguments :: [term()],
+ Time :: integer(),
+ Value :: term().
tc(M, F, A) ->
- Before = erlang:now(),
- Val = (catch apply(M, F, A)),
- After = erlang:now(),
+ Before = os:timestamp(),
+ Val = apply(M, F, A),
+ After = os:timestamp(),
{now_diff(After, Before), Val}.
%%
%% Calculate the time difference (in microseconds) of two
%% erlang:now() timestamps, T2-T1.
%%
--spec now_diff(timestamp(), timestamp()) -> integer().
+-spec now_diff(T2, T1) -> Tdiff when
+ T1 :: erlang:timestamp(),
+ T2 :: erlang:timestamp(),
+ Tdiff :: integer().
now_diff({A2, B2, C2}, {A1, B1, C1}) ->
((A2-A1)*1000000 + B2-B1)*1000000 + C2-C1.
%%
%% Convert seconds, minutes etc. to milliseconds.
%%
--spec seconds(non_neg_integer()) -> non_neg_integer().
+-spec seconds(Seconds) -> MilliSeconds when
+ Seconds :: non_neg_integer(),
+ MilliSeconds :: non_neg_integer().
seconds(Seconds) ->
1000*Seconds.
--spec minutes(non_neg_integer()) -> non_neg_integer().
+-spec minutes(Minutes) -> MilliSeconds when
+ Minutes :: non_neg_integer(),
+ MilliSeconds :: non_neg_integer().
minutes(Minutes) ->
1000*60*Minutes.
--spec hours(non_neg_integer()) -> non_neg_integer().
+-spec hours(Hours) -> MilliSeconds when
+ Hours :: non_neg_integer(),
+ MilliSeconds :: non_neg_integer().
hours(Hours) ->
1000*60*60*Hours.
--spec hms(non_neg_integer(), non_neg_integer(), non_neg_integer()) -> non_neg_integer().
+-spec hms(Hours, Minutes, Seconds) -> MilliSeconds when
+ Hours :: non_neg_integer(),
+ Minutes :: non_neg_integer(),
+ Seconds :: non_neg_integer(),
+ MilliSeconds :: non_neg_integer().
hms(H, M, S) ->
hours(H) + minutes(M) + seconds(S).
diff --git a/lib/stdlib/src/unicode.erl b/lib/stdlib/src/unicode.erl
index 12bc60623d..e9b90befe6 100644
--- a/lib/stdlib/src/unicode.erl
+++ b/lib/stdlib/src/unicode.erl
@@ -30,12 +30,34 @@
characters_to_binary/3,
bom_to_encoding/1, encoding_to_bom/1]).
--export_type([encoding/0]).
+-export_type([chardata/0, charlist/0, encoding/0, external_chardata/0,
+ external_charlist/0, latin1_chardata/0,
+ latin1_charlist/0, unicode_binary/0, unicode_char/0]).
-type encoding() :: 'latin1' | 'unicode' | 'utf8'
| 'utf16' | {'utf16', endian()}
| 'utf32' | {'utf32', endian()}.
-type endian() :: 'big' | 'little'.
+-type unicode_binary() :: binary().
+-type unicode_char() :: non_neg_integer().
+-type charlist() :: [unicode_char() | unicode_binary() | charlist()].
+-type chardata() :: charlist() | unicode_binary().
+-type external_unicode_binary() :: binary().
+-type external_chardata() :: external_charlist() | external_unicode_binary().
+-type external_charlist() :: [unicode_char() | external_unicode_binary()
+ | external_charlist()].
+-type latin1_binary() :: binary().
+-type latin1_char() :: byte().
+-type latin1_chardata() :: latin1_charlist() | latin1_binary().
+-type latin1_charlist() :: [latin1_char() | latin1_binary()
+ | latin1_charlist()].
+
+-spec characters_to_list(Data) -> Result when
+ Data :: latin1_chardata() | chardata() | external_chardata(),
+ Result :: list()
+ | {error, list(), RestData}
+ | {incomplete, list(), binary()},
+ RestData :: latin1_chardata() | chardata() | external_chardata().
characters_to_list(ML) ->
unicode:characters_to_list(ML,unicode).
@@ -51,7 +73,7 @@ characters_to_list_int(ML, Encoding) ->
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML,Encoding])),
erlang:raise(error,TheError,[{Mod,characters_to_list,L}|Rest])
@@ -69,6 +91,13 @@ do_characters_to_list(ML, Encoding) ->
end.
+-spec characters_to_binary(Data) -> Result when
+ Data :: latin1_chardata() | chardata() | external_chardata(),
+ Result :: binary()
+ | {error, binary(), RestData}
+ | {incomplete, binary(), binary()},
+ RestData :: latin1_chardata() | chardata() | external_chardata().
+
characters_to_binary(ML) ->
try
unicode:characters_to_binary(ML,unicode)
@@ -80,7 +109,7 @@ characters_to_binary(ML) ->
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML])),
erlang:raise(error,TheError,[{Mod,characters_to_binary,L}|Rest])
@@ -98,12 +127,21 @@ characters_to_binary_int(ML,InEncoding) ->
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML,InEncoding])),
erlang:raise(error,TheError,[{Mod,characters_to_binary,L}|Rest])
end.
+-spec characters_to_binary(Data, InEncoding, OutEncoding) -> Result when
+ Data :: latin1_chardata() | chardata() | external_chardata(),
+ InEncoding :: encoding(),
+ OutEncoding :: encoding(),
+ Result :: binary()
+ | {error, binary(), RestData}
+ | {incomplete, binary(), binary()},
+ RestData :: latin1_chardata() | chardata() | external_chardata().
+
characters_to_binary(ML, latin1, latin1) when is_binary(ML) ->
ML;
characters_to_binary(ML, latin1, Uni) when is_binary(ML) and ((Uni =:= utf8) or (Uni =:= unicode)) ->
@@ -121,7 +159,7 @@ characters_to_binary(ML, latin1, Uni) when is_binary(ML) and ((Uni =:= utf8) or
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML,latin1,Uni])),
erlang:raise(error,TheError,
@@ -143,7 +181,7 @@ characters_to_binary(ML,Uni,latin1) when is_binary(ML) and ((Uni =:= utf8) or
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML,Uni,latin1])),
erlang:raise(error,TheError,
@@ -162,7 +200,7 @@ characters_to_binary(ML, InEncoding, OutEncoding) ->
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML,InEncoding,OutEncoding])),
erlang:raise(error,TheError,[{Mod,characters_to_binary,L}|Rest])
@@ -215,6 +253,13 @@ characters_to_binary_int(ML, InEncoding, OutEncoding) ->
Res
end.
+-spec bom_to_encoding(Bin) -> {Encoding, Length} when
+ Bin :: binary(),
+ Encoding :: 'latin1' | 'utf8'
+ | {'utf16', endian()}
+ | {'utf32', endian()},
+ Length :: non_neg_integer().
+
bom_to_encoding(<<239,187,191,_/binary>>) ->
{utf8,3};
bom_to_encoding(<<0,0,254,255,_/binary>>) ->
@@ -228,6 +273,10 @@ bom_to_encoding(<<255,254,_/binary>>) ->
bom_to_encoding(Bin) when is_binary(Bin) ->
{latin1,0}.
+-spec encoding_to_bom(InEncoding) -> Bin when
+ Bin :: binary(),
+ InEncoding :: encoding().
+
encoding_to_bom(unicode) ->
<<239,187,191>>;
encoding_to_bom(utf8) ->
diff --git a/lib/stdlib/src/win32reg.erl b/lib/stdlib/src/win32reg.erl
index ee0d17bc94..598e77ffdc 100644
--- a/lib/stdlib/src/win32reg.erl
+++ b/lib/stdlib/src/win32reg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -52,14 +52,17 @@
-define(reg_dword, 4).
%% Basic types internal to this file.
--type open_mode() :: 'read' | 'write'.
--type reg_handle() :: {'win32reg',port()}.
+-opaque reg_handle() :: {'win32reg',port()}.
-type name() :: string() | 'default'.
-type value() :: string() | integer() | binary().
%%% Exported functions.
--spec open([open_mode()]) -> {'ok', reg_handle()} | {'error', 'enotsup'}.
+-spec open(OpenModeList) -> ReturnValue when
+ OpenModeList :: [OpenMode],
+ OpenMode :: 'read' | 'write',
+ ReturnValue :: {'ok', RegHandle} | {'error', ErrorId :: 'enotsup'},
+ RegHandle :: reg_handle().
open(Modes) ->
case os:type() of
@@ -75,14 +78,17 @@ open(Modes) ->
{error, enotsup}
end.
--spec close(reg_handle()) -> 'ok'.
+-spec close(RegHandle) -> 'ok' when
+ RegHandle :: reg_handle().
close({win32reg, Reg}) when is_port(Reg) ->
unlink(Reg),
exit(Reg, die),
ok.
--spec current_key(reg_handle()) -> {'ok', string()}.
+-spec current_key(RegHandle) -> ReturnValue when
+ RegHandle :: reg_handle(),
+ ReturnValue :: {'ok', string()}.
current_key({win32reg, Reg}) when is_port(Reg) ->
Cmd = [?cmd_get_current],
@@ -94,12 +100,18 @@ current_key({win32reg, Reg}) when is_port(Reg) ->
_ -> Root ++ [$\\|Name]
end}.
--spec change_key(reg_handle(), string()) -> 'ok' | {'error', atom()}.
+-spec change_key(RegHandle, Key) -> ReturnValue when
+ RegHandle :: reg_handle(),
+ Key :: string(),
+ ReturnValue :: 'ok' | {'error', ErrorId :: atom()}.
change_key({win32reg, Reg}, Key) when is_port(Reg) ->
change_key(Reg, ?cmd_open_key, Key).
--spec change_key_create(reg_handle(), string()) -> 'ok' | {'error', atom()}.
+-spec change_key_create(RegHandle, Key) -> ReturnValue when
+ RegHandle :: reg_handle(),
+ Key :: string(),
+ ReturnValue :: 'ok' | {'error', ErrorId :: atom()}.
change_key_create({win32reg, Reg}, Key) when is_port(Reg) ->
change_key(Reg, ?cmd_create_key, Key).
@@ -113,21 +125,30 @@ change_key(Reg, Cmd, Key) ->
{error, Reason}
end.
--spec sub_keys(reg_handle()) -> {'ok', [string()]} | {'error', atom()}.
+-spec sub_keys(RegHandle) -> ReturnValue when
+ RegHandle :: reg_handle(),
+ ReturnValue :: {'ok', [SubKey]} | {'error', ErrorId :: atom()},
+ SubKey :: string().
sub_keys({win32reg, Reg}) when is_port(Reg) ->
Cmd = [?cmd_get_all_subkeys],
Reg ! {self(), {command, Cmd}},
collect_keys(Reg, []).
--spec delete_key(reg_handle()) -> 'ok' | {'error', atom()}.
+-spec delete_key(RegHandle) -> ReturnValue when
+ RegHandle :: reg_handle(),
+ ReturnValue :: 'ok' | {'error', ErrorId :: atom()}.
delete_key({win32reg, Reg}) when is_port(Reg) ->
Cmd = [?cmd_delete_key],
Reg ! {self(), {command, Cmd}},
get_result(Reg).
--spec set_value(reg_handle(), name(), value()) -> 'ok' | {'error', atom()}.
+-spec set_value(RegHandle, Name, Value) -> ReturnValue when
+ RegHandle :: reg_handle(),
+ Name :: name(),
+ Value :: value(),
+ ReturnValue :: 'ok' | {'error', ErrorId :: atom()}.
set_value({win32reg, Reg}, Name0, Value) when is_port(Reg) ->
Name =
@@ -140,7 +161,10 @@ set_value({win32reg, Reg}, Name0, Value) when is_port(Reg) ->
Reg ! {self(), {command, Cmd}},
get_result(Reg).
--spec value(reg_handle(), name()) -> {'ok', value()} | {'error', atom()}.
+-spec value(RegHandle, Name) -> ReturnValue when
+ RegHandle :: reg_handle(),
+ Name :: name(),
+ ReturnValue :: {'ok', Value :: value()} | {'error', ErrorId :: atom()}.
value({win32reg, Reg}, Name) when is_port(Reg) ->
Cmd = [?cmd_get_value, Name, 0],
@@ -152,14 +176,20 @@ value({win32reg, Reg}, Name) when is_port(Reg) ->
{error, Reason}
end.
--spec values(reg_handle()) -> {'ok', [{name(), value()}]} | {'error', atom()}.
+-spec values(RegHandle) -> ReturnValue when
+ RegHandle :: reg_handle(),
+ ReturnValue :: {'ok', [ValuePair]} | {'error', ErrorId :: atom()},
+ ValuePair :: {Name :: name(), Value :: value()}.
values({win32reg, Reg}) when is_port(Reg) ->
Cmd = [?cmd_get_all_values],
Reg ! {self(), {command, Cmd}},
collect_values(Reg, []).
--spec delete_value(reg_handle(), name()) -> 'ok' | {'error', atom()}.
+-spec delete_value(RegHandle, Name) -> ReturnValue when
+ RegHandle :: reg_handle(),
+ Name :: name(),
+ ReturnValue :: 'ok' | {'error', ErrorId :: atom()}.
delete_value({win32reg, Reg}, Name0) when is_port(Reg) ->
Name =
@@ -171,7 +201,9 @@ delete_value({win32reg, Reg}, Name0) when is_port(Reg) ->
Reg ! {self(), {command, Cmd}},
get_result(Reg).
--spec expand(string()) -> string().
+-spec expand(String) -> ExpandedString when
+ String :: string(),
+ ExpandedString :: string().
expand(Value) ->
expand(Value, [], []).
@@ -195,7 +227,9 @@ expand([C|Rest], Env, Result) ->
expand([], [], Result) ->
lists:reverse(Result).
--spec format_error(atom()) -> string().
+-spec format_error(ErrorId) -> ErrorString when
+ ErrorId :: atom(),
+ ErrorString :: string().
format_error(ErrorId) ->
erl_posix_msg:message(ErrorId).
@@ -203,7 +237,7 @@ format_error(ErrorId) ->
%%% Implementation.
-spec collect_values(port(), [{name(), value()}]) ->
- {'ok', [{name(), value()}]} | {'error', atom()}.
+ {'ok', [{name(), value()}]} | {'error', ErrorId :: atom()}.
collect_values(P, Result) ->
case get_result(P) of
@@ -215,7 +249,7 @@ collect_values(P, Result) ->
{error, Reason}
end.
--spec collect_keys(port(), string()) -> {'ok', [string()]} | {'error', atom()}.
+-spec collect_keys(port(), string()) -> {'ok', [string()]} | {'error', ErrorId :: atom()}.
collect_keys(P, Result) ->
case get_result(P) of
diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl
index d41aeefa59..c82c8159b6 100644
--- a/lib/stdlib/src/zip.erl
+++ b/lib/stdlib/src/zip.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -203,6 +203,9 @@
zip_comment_length}).
+-type zip_file() :: #zip_file{}.
+-type zip_comment() :: #zip_comment{}.
+
%% Open a zip archive with options
%%
@@ -220,7 +223,7 @@ openzip_open(F, Options) ->
do_openzip_open(F, Options) ->
Opts = get_openzip_options(Options),
#openzip_opts{output = Output, open_opts = OpO, cwd = CWD} = Opts,
- Input = get_zip_input(F),
+ Input = get_input(F),
In0 = Input({open, F, OpO -- [write]}, []),
{[#zip_comment{comment = C} | Files], In1} =
get_central_dir(In0, fun raw_file_info_etc/5, Input),
@@ -323,8 +326,33 @@ openzip_close(_) ->
%% Accepted options:
%% verbose, cooked, file_list, keep_old_files, file_filter, memory
+-spec(unzip(Archive) -> RetValue when
+ Archive :: file:name() | binary(),
+ RetValue :: {ok, FileList}
+ | {ok, FileBinList}
+ | {error, Reason :: term()}
+ | {error, {Name :: file:name(), Reason :: term()}},
+ FileList :: [file:name()],
+ FileBinList :: [{file:name(),binary()}]).
+
unzip(F) -> unzip(F, []).
+-spec(unzip(Archive, Options) -> RetValue when
+ Archive :: file:name() | binary(),
+ Options :: [Option],
+ Option :: {file_list, FileList}
+ | keep_old_files | verbose | memory |
+ {file_filter, FileFilter} | {cwd, CWD},
+ FileList :: [file:name()],
+ FileBinList :: [{file:name(),binary()}],
+ FileFilter :: fun((ZipFile) -> boolean()),
+ CWD :: string(),
+ ZipFile :: zip_file(),
+ RetValue :: {ok, FileList}
+ | {ok, FileBinList}
+ | {error, Reason :: term()}
+ | {error, {Name :: file:name(), Reason :: term()}}).
+
unzip(F, Options) ->
case ?CATCH do_unzip(F, Options) of
{ok, R} -> {ok, R};
@@ -345,6 +373,18 @@ do_unzip(F, Options) ->
{ok, Files}.
%% Iterate over all files in a zip archive
+-spec(foldl(Fun, Acc0, Archive) -> {ok, Acc1} | {error, Reason} when
+ Fun :: fun((FileInArchive, GetInfo, GetBin, AccIn) -> AccOut),
+ FileInArchive :: file:name(),
+ GetInfo :: fun(() -> file:file_info()),
+ GetBin :: fun(() -> binary()),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ Archive :: file:name() | {file:name(), binary()},
+ Reason :: term()).
+
foldl(Fun, Acc0, Archive) when is_function(Fun, 4) ->
ZipFun =
fun({Name, GetInfo, GetBin}, A) ->
@@ -368,8 +408,33 @@ foldl(_,_, _) ->
%% Accepted options:
%% verbose, cooked, memory, comment
+-spec(zip(Name, FileList) -> RetValue when
+ Name :: file:name(),
+ FileList :: [FileSpec],
+ FileSpec :: file:name() | {file:name(), binary()}
+ | {file:name(), binary(), file:file_info()},
+ RetValue :: {ok, FileName :: file:name()}
+ | {ok, {FileName :: file:name(), binary()}}
+ | {error, Reason :: term()}).
+
zip(F, Files) -> zip(F, Files, []).
+-spec(zip(Name, FileList, Options) -> RetValue when
+ Name :: file:name(),
+ FileList :: [FileSpec],
+ FileSpec :: file:name() | {file:name(), binary()}
+ | {file:name(), binary(), file:file_info()},
+ Options :: [Option],
+ Option :: memory | cooked | verbose | {comment, Comment}
+ | {cwd, CWD} | {compress, What} | {uncompress, What},
+ What :: all | [Extension] | {add, [Extension]} | {del, [Extension]},
+ Extension :: string(),
+ Comment :: string(),
+ CWD :: string(),
+ RetValue :: {ok, FileName :: file:name()}
+ | {ok, {FileName :: file:name(), binary()}}
+ | {error, Reason :: term()}).
+
zip(F, Files, Options) ->
case ?CATCH do_zip(F, Files, Options) of
{ok, R} -> {ok, R};
@@ -392,8 +457,20 @@ do_zip(F, Files, Options) ->
%% Accepted options:
%% cooked, file_filter, file_output (latter 2 undocumented)
+-spec(list_dir(Archive) -> RetValue when
+ Archive :: file:name() | binary(),
+ RetValue :: {ok, CommentAndFiles} | {error, Reason :: term()},
+ CommentAndFiles :: [zip_comment() | zip_file()]).
+
list_dir(F) -> list_dir(F, []).
+-spec(list_dir(Archive, Options) -> RetValue when
+ Archive :: file:name() | binary(),
+ RetValue :: {ok, CommentAndFiles} | {error, Reason :: term()},
+ CommentAndFiles :: [zip_comment() | zip_file()],
+ Options :: [Option],
+ Option :: cooked).
+
list_dir(F, Options) ->
case ?CATCH do_list_dir(F, Options) of
{ok, R} -> {ok, R};
@@ -411,6 +488,10 @@ do_list_dir(F, Options) ->
%% Print zip directory in short form
+-spec(t(Archive) -> ok when
+ Archive :: file:name() | binary() | ZipHandle,
+ ZipHandle :: pid()).
+
t(F) when is_pid(F) -> zip_t(F);
t(F) when is_record(F, openzip) -> openzip_t(F);
t(F) -> t(F, fun raw_short_print_info_etc/5).
@@ -431,6 +512,10 @@ do_t(F, RawPrint) ->
%% Print zip directory in long form (like ls -l)
+-spec(tt(Archive) -> ok when
+ Archive :: file:name() | binary() | ZipHandle,
+ ZipHandle :: pid()).
+
tt(F) when is_pid(F) -> zip_tt(F);
tt(F) when is_record(F, openzip) -> openzip_tt(F);
tt(F) -> t(F, fun raw_long_print_info_etc/5).
@@ -605,11 +690,78 @@ get_list_dir_options(F, Options) ->
get_list_dir_opt(Options, Opts).
%% aliases for erl_tar compatibility
+-spec(table(Archive) -> RetValue when
+ Archive :: file:name() | binary(),
+ RetValue :: {ok, CommentAndFiles} | {error, Reason :: term()},
+ CommentAndFiles :: [zip_comment() | zip_file()]).
+
table(F) -> list_dir(F).
+
+-spec(table(Archive, Options) -> RetValue when
+ Archive :: file:name() | binary(),
+ RetValue :: {ok, CommentAndFiles} | {error, Reason :: term()},
+ CommentAndFiles :: [zip_comment() | zip_file()],
+
+ Options :: [Option],
+ Option :: cooked).
+
table(F, O) -> list_dir(F, O).
+
+-spec(create(Name, FileList) -> RetValue when
+ Name :: file:name(),
+ FileList :: [FileSpec],
+ FileSpec :: file:name() | {file:name(), binary()}
+ | {file:name(), binary(), file:file_info()},
+ RetValue :: {ok, FileName :: file:name()}
+ | {ok, {FileName :: file:name(), binary()}}
+ | {error, Reason :: term()}).
+
create(F, Fs) -> zip(F, Fs).
+
+-spec(create(Name, FileList, Options) -> RetValue when
+ Name :: file:name(),
+ FileList :: [FileSpec],
+ FileSpec :: file:name() | {file:name(), binary()}
+ | {file:name(), binary(), file:file_info()},
+ Options :: [Option],
+ Option :: memory | cooked | verbose | {comment, Comment}
+ | {cwd, CWD} | {compress, What} | {uncompress, What},
+ What :: all | [Extension] | {add, [Extension]} | {del, [Extension]},
+ Extension :: string(),
+ Comment :: string(),
+ CWD :: string(),
+ RetValue :: {ok, FileName :: file:name()}
+ | {ok, {FileName :: file:name(), binary()}}
+ | {error, Reason :: term()}).
create(F, Fs, O) -> zip(F, Fs, O).
+
+-spec(extract(Archive) -> RetValue when
+ Archive :: file:name() | binary(),
+ RetValue :: {ok, FileList}
+ | {ok, FileBinList}
+ | {error, Reason :: term()}
+ | {error, {Name :: file:name(), Reason :: term()}},
+ FileList :: [file:name()],
+ FileBinList :: [{file:name(),binary()}]).
+
extract(F) -> unzip(F).
+
+-spec(extract(Archive, Options) -> RetValue when
+ Archive :: file:name() | binary(),
+ Options :: [Option],
+ Option :: {file_list, FileList}
+ | keep_old_files | verbose | memory |
+ {file_filter, FileFilter} | {cwd, CWD},
+ FileList :: [file:name()],
+ FileBinList :: [{file:name(),binary()}],
+ FileFilter :: fun((ZipFile) -> boolean()),
+ CWD :: string(),
+ ZipFile :: zip_file(),
+ RetValue :: {ok, FileList}
+ | {ok, FileBinList}
+ | {error, Reason :: term()}
+ | {error, {Name :: file:name(), Reason :: term()}}).
+
extract(F, O) -> unzip(F, O).
@@ -990,21 +1142,52 @@ server_loop(OpenZip) ->
{error, bad_msg}
end.
+-spec(zip_open(Archive) -> {ok, ZipHandle} | {error, Reason} when
+ Archive :: file:name() | binary(),
+ ZipHandle :: pid(),
+ Reason :: term()).
+
zip_open(Archive) -> zip_open(Archive, []).
+-spec(zip_open(Archive, Options) -> {ok, ZipHandle} | {error, Reason} when
+ Archive :: file:name() | binary(),
+ ZipHandle :: pid(),
+ Options :: [Option],
+ Option :: cooked | memory | {cwd, CWD :: string()},
+ Reason :: term()).
+
zip_open(Archive, Options) ->
Pid = spawn(fun() -> server_loop(not_open) end),
request(self(), Pid, {open, Archive, Options}).
+-spec(zip_get(ZipHandle) -> {ok, [Result]} | {error, Reason} when
+ ZipHandle :: pid(),
+ Result :: file:name() | {file:name(), binary()},
+ Reason :: term()).
+
zip_get(Pid) when is_pid(Pid) ->
request(self(), Pid, get).
+-spec(zip_close(ZipHandle) -> ok | {error, einval} when
+ ZipHandle :: pid()).
+
zip_close(Pid) when is_pid(Pid) ->
request(self(), Pid, close).
+-spec(zip_get(FileName, ZipHandle) -> {ok, Result} | {error, Reason} when
+ FileName :: file:name(),
+ ZipHandle :: pid(),
+ Result :: file:name() | {file:name(), binary()},
+ Reason :: term()).
+
zip_get(FileName, Pid) when is_pid(Pid) ->
request(self(), Pid, {get, FileName}).
+-spec(zip_list_dir(ZipHandle) -> {ok, Result} | {error, Reason} when
+ Result :: [zip_comment() | zip_file()],
+ ZipHandle :: pid(),
+ Reason :: term()).
+
zip_list_dir(Pid) when is_pid(Pid) ->
request(self(), Pid, list_dir).