diff options
author | Lukas Larsson <[email protected]> | 2011-05-18 16:21:34 +0200 |
---|---|---|
committer | Lukas Larsson <[email protected]> | 2011-05-18 16:21:34 +0200 |
commit | 15426ac367eed736c165a5bdbb1c051a87944f68 (patch) | |
tree | fcabce7847168a8416600fe35f94a411a5f73d6e /lib/stdlib/src | |
parent | 4cd0717b717803ce8f03a12de4bf89f452ed1df7 (diff) | |
parent | f44bbb331fb517e989d4d906b7f63ec110bbbc18 (diff) | |
download | otp-15426ac367eed736c165a5bdbb1c051a87944f68.tar.gz otp-15426ac367eed736c165a5bdbb1c051a87944f68.tar.bz2 otp-15426ac367eed736c165a5bdbb1c051a87944f68.zip |
Merge branch 'dev' of super:otp into dev
* 'dev' of super:otp: (166 commits)
Corrected documentation error and added examples to Users Guide
In TLS 1.1, failure to properly close a connection no longer requires that a session not be resumed. This is a change from TLS 1.0 to conform with widespread implementation practice. Erlang ssl will now in TLS 1.0 conform to the widespread implementation practice instead of the specification to avoid performance issues.
Add escript to bootstrap/bin
Remove unused variable warning in inet_res
Remove unused variable in epmd_port
Remove compiler warnings in inet_drv
Add SASL test suite
Allow same module name in multiple applications if explicitely excluded
Fix bugs concerning the option report_missing_types
Fix default encoding in SAX parser.
re: remove gratuitous "it " in manpage
Spelling in (backward *compatibility*) comment.
Improve erl_docgen's support for Dialyzer specs and types
dialyzer warning on mnesia_tm
Add documentation text about majority checking
add mnesia_majority_test suite
where_to_wlock optimization + change_table_majority/2
bug in mnesia_tm:needs_majority/2
optimize sticky_lock maj. check
check majority for sticky locks
...
Diffstat (limited to 'lib/stdlib/src')
57 files changed, 4677 insertions, 1121 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..d9c645d787 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,8 +218,10 @@ 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 @@ -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). 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..febfdd6285 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). diff --git a/lib/stdlib/src/calendar.erl b/lib/stdlib/src/calendar.erl index 33725d999c..8d1071209e 100644 --- a/lib/stdlib/src/calendar.erl +++ b/lib/stdlib/src/calendar.erl @@ -63,6 +63,8 @@ %% Types %%---------------------------------------------------------------------- +-export_type([t_now/0]). + -type year() :: non_neg_integer(). -type year1970() :: 1970..10000. % should probably be 1970.. -type month() :: 1..12. @@ -74,7 +76,9 @@ -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_now() :: {MegaSecs :: non_neg_integer(), + Secs :: non_neg_integer(), + MicroSecs :: non_neg_integer()}. -type t_date() :: {year(),month(),day()}. -type t_time() :: {hour(),minute(),second()}. @@ -106,7 +110,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 +122,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 :: t_date(), + Days :: non_neg_integer(). date_to_gregorian_days({Year, Month, Day}) -> date_to_gregorian_days(Year, Month, Day). @@ -124,7 +134,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 :: t_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 +147,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:: t_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) -> t_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 +172,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) -> t_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 +182,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). @@ -188,7 +207,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) -> t_yearweeknum() when + Date :: t_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 +236,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). @@ -244,7 +267,9 @@ local_time() -> %% 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 :: t_datetime1970(), + DateTime2 :: t_datetime1970(). local_time_to_universal_time(DateTime) -> erlang:localtime_to_universaltime(DateTime). @@ -254,7 +279,9 @@ local_time_to_universal_time(DateTime) -> 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 :: t_datetime1970(), + DateTime :: t_datetime1970(). local_time_to_universal_time_dst(DateTime) -> UtDst = erlang:localtime_to_universaltime(DateTime, true), Ut = erlang:localtime_to_universaltime(DateTime, false), @@ -282,12 +309,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) -> t_datetime1970() when + Now :: t_now(). 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) -> t_datetime1970() when + Now :: t_now(). now_to_universal_time(Now) -> now_to_datetime(Now). @@ -296,7 +325,8 @@ now_to_universal_time(Now) -> %% %% Args: Now = now() %% --spec now_to_local_time(t_now()) -> t_datetime1970(). +-spec now_to_local_time(Now) -> t_datetime1970() when + Now :: t_now(). now_to_local_time({MSec, Sec, _uSec}) -> erlang:universaltime_to_localtime( now_to_universal_time({MSec, Sec, _uSec})). @@ -305,7 +335,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 :: t_time(). seconds_to_daystime(Secs) -> Days0 = Secs div ?SECONDS_PER_DAY, Secs0 = Secs rem ?SECONDS_PER_DAY, @@ -323,7 +356,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) -> t_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 +374,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 :: t_datetime(), + T2 :: t_datetime(), + Days :: integer(), + Time :: t_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 +389,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 :: t_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. @@ -368,7 +406,8 @@ universal_time() -> %% universal_time_to_local_time(DateTime) %% --spec universal_time_to_local_time(t_datetime()) -> t_datetime(). +-spec universal_time_to_local_time(DateTime) -> t_datetime() when + DateTime :: t_datetime1970(). universal_time_to_local_time(DateTime) -> erlang:universaltime_to_localtime(DateTime). @@ -376,7 +415,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 +428,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 :: t_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..671b5a9dd4 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,26 @@ 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 :: [{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 +428,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 +453,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 +477,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 +495,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 +559,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 +624,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 +655,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 +683,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 +754,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 +854,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 +868,16 @@ to_ets(DTab, ETab) -> foldl(Fun, ETab, DTab) end. +-spec traverse(Name, Fun) -> Return | {'error', Reason} when + Name :: tab_name(), + Fun :: fun((Object) -> FunReturn), + FunReturn :: 'continue' | {'continue', Val} | {'done', Value}, + Val :: term(), + Value :: term(), + Object :: object(), + Return :: [term()], + Reason :: term(). + traverse(Tab, Fun) -> Ref = make_ref(), TFun = @@ -638,6 +895,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]). 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..d804c1dee5 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} -> diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index ea1b179ee5..46288cf467 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()}]). +-opaque(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) -> @@ -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). @@ -973,18 +1083,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..eada563914 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 @@ -38,6 +38,10 @@ checked_ra=[] % succesfully 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..478f05e792 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. diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index cfb9f0ca98..dd0b9bc2ab 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -128,10 +128,15 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) -> }). -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}) -> @@ -419,16 +424,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. @@ -1877,6 +1905,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()). diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 15b45d72f4..bd5d65a1e1 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -511,6 +511,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 +543,19 @@ 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(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 +563,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]}]}} -> @@ -830,6 +851,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 +868,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 +910,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 +981,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..718ca2e91a 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). @@ -374,7 +415,7 @@ set_attr(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 +1326,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/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/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_event.erl b/lib/stdlib/src/gen_event.erl index b00910771f..1c4a73680b 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 @@ -44,6 +44,9 @@ 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}). @@ -113,7 +116,11 @@ behaviour_info(_Other) -> %%--------------------------------------------------------------------------- --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()}. 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..54c7283abf 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 :: chars(), 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, String, Format) -> Return when + Continuation :: continuation() | [], + String :: string(), + Format :: string(), + Return :: {'more', Continuation1 :: continuation()} + | {'done', Result, LeftOverChars :: string()}, + Result :: {'ok', InputList :: chars()} + | '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..52aa4d073c 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,36 +22,24 @@ -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()}. - -%%----------------------------------------------------------------------- %% fread(Continuation, CharList, FormatString) %% This is the main function into the re-entrant formatted reader. It %% 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,7 +94,14 @@ 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, []). diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl index b2cfb00de9..c303ae60b5 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 -> diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl index c669c1f7c1..bba46e4cb6 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,12 @@ 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(). keyreplace(K, N, L, New) when is_integer(N), N > 0, is_tuple(New) -> keyreplace3(K, N, L, New). @@ -502,8 +641,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 +657,12 @@ 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(). keystore(K, N, L, New) when is_integer(N), N > 0, is_tuple(New) -> keystore2(K, N, L, New). @@ -526,7 +674,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 +735,13 @@ 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(). keymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> case L2 of @@ -611,7 +768,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 +837,13 @@ 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(). ukeymerge(Index, L1, T2) when is_integer(Index), Index > 0 -> case L1 of @@ -704,7 +870,11 @@ 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()]. keymap(Fun, Index, [Tup|Tail]) -> [setelement(Index, Tup, Fun(element(Index, Tup)))|keymap(Fun, Index, Tail)]; @@ -713,7 +883,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 +901,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 +923,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 +954,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 +979,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 +1037,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 +1050,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 +1082,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 +1133,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 +1145,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 +1157,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 +1217,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 +1248,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 +1275,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 +1292,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 +1305,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 +1318,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 +1336,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..39d017d430 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) -> 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 a3c9927ee9..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), 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..68697d0da2 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). @@ -53,14 +53,8 @@ -type property() :: atom() | tuple(). --type aliases() :: [{any(), any()}]. --type negations() :: [{any(), any()}]. --type expansions() :: [{property(), [any()]}]. - %% --------------------------------------------------------------------- -%% @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 +62,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 +71,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 +78,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 +91,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 +108,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 <- 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 +123,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 +132,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 +148,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 +172,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 +194,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 +213,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 +235,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 +242,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 +262,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 +271,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 +296,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 +304,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 +328,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 +351,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 +372,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 +387,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 +409,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 +430,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 +462,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 +496,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 +577,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 +598,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 +619,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 +633,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..5ca04ff023 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 @@ -125,6 +125,8 @@ -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}}, 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..4c6b4d710b 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,16 @@ new() -> {[],[]}. %{RearList,FrontList} %% O(1) --spec is_queue(term()) -> boolean(). +-spec is_queue(Term) -> boolean() when + Term :: term(). 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) -> boolean() when + Q :: queue(). is_empty({[],[]}) -> true; is_empty({In,Out}) when is_list(In), is_list(Out) -> @@ -72,14 +74,16 @@ is_empty(Q) -> erlang:error(badarg, [Q]). %% O(len(Q)) --spec len(queue()) -> non_neg_integer(). +-spec len(Q) -> non_neg_integer() when + Q :: queue(). 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) -> list() when + Q :: queue(). to_list({In,Out}) when is_list(In), is_list(Out) -> Out++lists:reverse(In, []); to_list(Q) -> @@ -88,7 +92,8 @@ to_list(Q) -> %% Create queue from list %% %% O(length(L)) --spec from_list(list()) -> queue(). +-spec from_list(L) -> queue() when + L :: list(). from_list(L) when is_list(L) -> f2r(L); from_list(L) -> @@ -97,7 +102,9 @@ 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, Q) -> boolean() when + Item :: term(), + Q :: queue(). 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 +117,10 @@ 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, Q1) -> Q2 when + Item :: term(), + Q1 :: queue(), + Q2 :: queue(). in(X, {[_]=In,[]}) -> {[X], In}; in(X, {In,Out}) when is_list(In), is_list(Out) -> @@ -122,7 +132,10 @@ 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, Q1) -> Q2 when + 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 +146,10 @@ 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) -> Result when + Q1 :: queue(), + Q2 :: queue(), + Result :: {{value, Item :: term()}, Q2} | {empty, Q1}. out({[],[]}=Q) -> {empty,Q}; out({[V],[]}) -> @@ -151,7 +167,10 @@ 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) -> Result when + Q1 :: queue(), + Q2 :: queue(), + Result :: {{value, Item :: term()}, Q2} | {empty, Q1}. out_r({[],[]}=Q) -> {empty,Q}; out_r({[],[V]}) -> @@ -172,7 +191,9 @@ 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) -> Item when + Q :: queue(), + Item :: term(). get({[],[]}=Q) -> erlang:error(empty, [Q]); get({R,F}) when is_list(R), is_list(F) -> @@ -191,7 +212,9 @@ 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) -> Item when + Q :: queue(), + Item :: term(). get_r({[],[]}=Q) -> erlang:error(empty, [Q]); get_r({[H|_],F}) when is_list(F) -> @@ -206,7 +229,9 @@ 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) -> 'empty' | {'value',Item} when + Q :: queue(), + Item :: term(). peek({[],[]}) -> empty; peek({R,[H|_]}) when is_list(R) -> @@ -221,7 +246,9 @@ 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) -> 'empty' | {'value',Item} when + Q :: queue(), + Item :: term(). peek_r({[],[]}) -> empty; peek_r({[H|_],F}) when is_list(F) -> @@ -236,7 +263,9 @@ peek_r(Q) -> %% Remove the first element and return resulting queue %% %% O(1) amortized --spec drop(queue()) -> queue(). +-spec drop(Q1) -> Q2 when + Q1 :: queue(), + Q2 :: queue(). drop({[],[]}=Q) -> erlang:error(empty, [Q]); drop({[_],[]}) -> @@ -254,7 +283,9 @@ drop(Q) -> %% Remove the last element and return resulting queue %% %% O(1) amortized --spec drop_r(queue()) -> queue(). +-spec drop_r(Q1) -> Q2 when + Q1 :: queue(), + Q2 :: queue(). drop_r({[],[]}=Q) -> erlang:error(empty, [Q]); drop_r({[],[_]}) -> @@ -275,7 +306,9 @@ drop_r(Q) -> %% Return reversed queue %% %% O(1) --spec reverse(queue()) -> queue(). +-spec reverse(Q1) -> Q2 when + Q1 :: queue(), + Q2 :: queue(). reverse({R,F}) when is_list(R), is_list(F) -> {F,R}; reverse(Q) -> @@ -285,7 +318,10 @@ reverse(Q) -> %% %% Q2 empty: O(1) %% else: O(len(Q1)) --spec join(queue(), queue()) -> queue(). +-spec join(Q1, Q2) -> Q3 when + 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 +335,11 @@ join(Q1, Q2) -> %% %% N = 0..len(Q) %% O(max(N, len(Q))) --spec split(non_neg_integer(), queue()) -> {queue(),queue()}. +-spec split(N, Q1) -> {Q2,Q3} when + 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 +380,10 @@ 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) -> Q2 when + Fun :: fun((Item :: term()) -> boolean() | list()), + Q1 :: queue(), + Q2 :: queue(). 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 +459,10 @@ filter_r(Fun, [X|R0]) -> %% Cons to head %% --spec cons(term(), queue()) -> queue(). +-spec cons(Item, Q1) -> Q2 when + Item :: term(), + Q1 :: queue(), + Q2 :: queue(). cons(X, Q) -> in_r(X, Q). @@ -425,7 +471,9 @@ 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) -> Item when + Q :: queue(), + Item :: term(). head({[],[]}=Q) -> erlang:error(empty, [Q]); head({R,F}) when is_list(R), is_list(F) -> @@ -435,7 +483,9 @@ head(Q) -> %% Remove head element and return resulting queue %% --spec tail(queue()) -> queue(). +-spec tail(Q1) -> Q2 when + Q1 :: queue(), + Q2 :: queue(). tail(Q) -> drop(Q). @@ -443,22 +493,35 @@ tail(Q) -> %% Cons to tail %% --spec snoc(queue(), term()) -> queue(). +-spec snoc(Q1, Item) -> Q2 when + Q1 :: queue(), + Q2 :: queue(), + Item :: term(). snoc(Q, X) -> in(X, Q). %% Return last element --spec daeh(queue()) -> term(). +-spec daeh(Q) -> Item when + Q :: queue(), + Item :: term(). daeh(Q) -> get_r(Q). --spec last(queue()) -> term(). +-spec last(Q) -> Item when + Q :: queue(), + Item :: term(). last(Q) -> get_r(Q). %% Remove last element and return resulting queue --spec liat(queue()) -> queue(). +-spec liat(Q1) -> Q2 when + Q1 :: queue(), + Q2 :: queue(). liat(Q) -> drop_r(Q). --spec lait(queue()) -> queue(). +-spec lait(Q1) -> Q2 when + Q1 :: queue(), + Q2 :: queue(). lait(Q) -> drop_r(Q). %% Oops, mis-spelled 'tail' reversed. Forget this one. --spec init(queue()) -> queue(). +-spec init(Q1) -> Q2 when + Q1 :: queue(), + Q2 :: queue(). init(Q) -> drop_r(Q). %%-------------------------------------------------------------------------- diff --git a/lib/stdlib/src/random.erl b/lib/stdlib/src/random.erl index 01227c29b4..dbb524cc74 100644 --- a/lib/stdlib/src/random.erl +++ b/lib/stdlib/src/random.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 @@ -49,7 +49,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). @@ -57,7 +60,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) -> put(random_seed, @@ -93,7 +99,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. @@ -104,7 +111,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 30269, @@ -117,7 +126,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..02dbe60741 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(), + 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(), + 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} = 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..e3e23e09bc 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} @@ -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..d79ee676d9 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) -> none() 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..d38b8ab37a 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,13 @@ -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(), 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 +113,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 +159,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 +176,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 +202,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 +234,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 +257,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 +272,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 +285,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 +298,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 +312,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 +325,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 +339,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 +373,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 :: pos_integer()). no_elements(S) when ?IS_SET(S) -> length(?LIST(S)); no_elements(S) when ?IS_ORDSET(S), is_tuple(?ORDTYPE(S)) -> @@ -296,6 +383,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 +402,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 +468,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 +485,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 +505,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 +524,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 +544,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 +578,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 +588,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 +602,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 +644,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 +654,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 +729,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 +756,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 +774,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 +800,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 +834,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 +848,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 +884,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 +894,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 +909,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 +983,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 +1053,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 +1072,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 +1116,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 +1143,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 +1216,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 +1253,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 +1274,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 +1292,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 +1315,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 +1326,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 +1341,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 +1352,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 +1368,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 +1380,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 +1392,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 +1424,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 +1479,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 +1496,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 +1507,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 +1517,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 +1539,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 +1622,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 +1650,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 +1671,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 +1721,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 +1742,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 +1923,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 +1938,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 +1949,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 +1998,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 +2007,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 +2090,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 +2108,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 +2136,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 +2150,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 +2198,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 +2247,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 +2270,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 +2293,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 +2318,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 +2378,7 @@ external_fun({external, Function}) when is_atom(Function) -> false; external_fun({external, Fun}) -> Fun; -external_fun(_) -> +external_fun(_) -> false. %% Inlined. @@ -2121,7 +2458,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 +2483,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 +2529,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 +2634,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 +2708,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 +2734,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 +2761,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 +2814,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 09a01a9aea..e60706ed05 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -35,19 +35,28 @@ %%-------------------------------------------------------------------------- --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,14 +64,14 @@ %%-------------------------------------------------------------------------- -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). @@ -70,7 +79,7 @@ -record(state, {name, strategy :: strategy(), - children = [] :: [child()], + children = [] :: [child_rec()], dynamics :: ?DICT() | ?SET(), intensity :: non_neg_integer(), period :: pos_integer(), @@ -99,11 +108,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}, []). @@ -111,24 +125,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}). @@ -139,22 +162,39 @@ delete_child(Supervisor, Name) -> %% way (maybe killed). %%----------------------------------------------------------------- --type term_err() :: 'not_found' | 'simple_one_for_one'. --spec terminate_child(sup_ref(), pid() | 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; @@ -222,12 +262,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). @@ -687,9 +727,9 @@ 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) -> @@ -958,7 +998,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..555cb5a66f 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 @@ -49,9 +49,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..8ab72c9b50 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], + 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], + 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 78e897b877..89fae05e4f 100644 --- a/lib/stdlib/src/timer.erl +++ b/lib/stdlib/src/timer.erl @@ -46,56 +46,108 @@ %% -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 @@ -104,7 +156,10 @@ sleep(T) -> %% %% Measure the execution time (in microseconds) for Fun(). %% --spec tc(function()) -> {time(), term()}. +-spec tc(Fun) -> {Time, Value} when + Fun :: function(), + Time :: integer(), + Value :: term(). tc(F) -> Before = os:timestamp(), Val = F(), @@ -114,7 +169,11 @@ tc(F) -> %% %% 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 = os:timestamp(), Val = apply(F, A), @@ -124,7 +183,12 @@ tc(F, A) -> %% %% 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 = os:timestamp(), Val = apply(M, F, A), @@ -135,23 +199,36 @@ tc(M, F, A) -> %% Calculate the time difference (in microseconds) of two %% erlang:now() timestamps, T2-T1. %% --spec now_diff(timestamp(), timestamp()) -> integer(). +-spec now_diff(T1, T2) -> Tdiff when + T1 :: calendar:t_now(), + T2 :: calendar:t_now(), + 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..a5d9965ca2 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). @@ -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) @@ -104,6 +133,15 @@ characters_to_binary_int(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)) -> @@ -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..524d709431 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 %% @@ -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) -> 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). |