From 76ca320fd37cecdcf225ddcc094bc72a607b0453 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Fri, 6 May 2011 15:11:15 +0200 Subject: Types and specifications have been modified and added --- lib/stdlib/src/array.erl | 111 +++---- lib/stdlib/src/base64.erl | 24 +- lib/stdlib/src/beam_lib.erl | 117 +++++--- lib/stdlib/src/binary.erl | 37 ++- lib/stdlib/src/c.erl | 66 ++-- lib/stdlib/src/calendar.erl | 91 ++++-- lib/stdlib/src/dets.erl | 301 +++++++++++++++++-- lib/stdlib/src/dict.erl | 99 ++++-- lib/stdlib/src/digraph.erl | 159 +++++++--- lib/stdlib/src/digraph_utils.erl | 84 ++++-- lib/stdlib/src/epp.erl | 43 ++- lib/stdlib/src/erl_eval.erl | 134 ++++++++- lib/stdlib/src/erl_expand_records.erl | 6 +- lib/stdlib/src/erl_internal.erl | 39 ++- lib/stdlib/src/erl_lint.erl | 31 ++ lib/stdlib/src/erl_parse.yrl | 39 ++- lib/stdlib/src/erl_pp.erl | 65 ++++ lib/stdlib/src/erl_scan.erl | 115 ++++--- lib/stdlib/src/ets.erl | 148 ++++++--- lib/stdlib/src/file_sorter.erl | 119 +++++++- lib/stdlib/src/filelib.erl | 39 ++- lib/stdlib/src/filename.erl | 84 ++++-- lib/stdlib/src/gb_sets.erl | 147 ++++++--- lib/stdlib/src/gb_trees.erl | 109 +++++-- lib/stdlib/src/gen_event.erl | 11 +- lib/stdlib/src/io.erl | 195 ++++++++---- lib/stdlib/src/io_lib.erl | 78 +++-- lib/stdlib/src/io_lib_fread.erl | 41 ++- lib/stdlib/src/lib.erl | 20 +- lib/stdlib/src/lists.erl | 425 +++++++++++++++++++++----- lib/stdlib/src/log_mf_h.erl | 21 +- lib/stdlib/src/ms_transform.erl | 16 + lib/stdlib/src/orddict.erl | 98 ++++-- lib/stdlib/src/ordsets.erl | 72 ++++- lib/stdlib/src/pg.erl | 28 +- lib/stdlib/src/pool.erl | 24 +- lib/stdlib/src/proc_lib.erl | 138 +++++++-- lib/stdlib/src/proplists.erl | 151 +++++----- lib/stdlib/src/qlc.erl | 304 +++++++++++++++++-- lib/stdlib/src/qlc_pt.erl | 18 +- lib/stdlib/src/queue.erl | 123 ++++++-- lib/stdlib/src/random.erl | 24 +- lib/stdlib/src/re.erl | 47 +++ lib/stdlib/src/regexp.erl | 69 ++++- lib/stdlib/src/sets.erl | 74 +++-- lib/stdlib/src/shell.erl | 23 +- lib/stdlib/src/slave.erl | 52 +++- lib/stdlib/src/sofs.erl | 545 +++++++++++++++++++++++++++------- lib/stdlib/src/string.erl | 175 ++++++++--- lib/stdlib/src/supervisor.erl | 98 ++++-- lib/stdlib/src/supervisor_bridge.erl | 18 +- lib/stdlib/src/sys.erl | 182 +++++++++++- lib/stdlib/src/timer.erl | 142 +++++++-- lib/stdlib/src/unicode.erl | 51 +++- lib/stdlib/src/win32reg.erl | 70 +++-- lib/stdlib/src/zip.erl | 185 +++++++++++- 56 files changed, 4598 insertions(+), 1127 deletions(-) (limited to 'lib/stdlib/src') 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..1b81862940 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() :: atom() | reference(). +-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,28 +22,8 @@ -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) @@ -51,7 +31,15 @@ %% repeatedly collects lines and calls fread/2 to format the input until %% all the format string has been used. And it counts the characters. --spec fread(io_lib_fread:continuation(), string(), string()) -> fread_3_ret(). +-spec fread(Continuation, String, Format) -> Return when + Continuation :: io_lib:continuation() | [], + String :: string(), + Format :: string(), + Return :: {'more', Continuation1 :: io_lib:continuation()} + | {'done', Result, LeftOverChars :: string()}, + Result :: {'ok', InputList :: io_lib:chars()} + | 'eof' + | {'error', What :: term()}. fread([], Chars, Format) -> %%io:format("FREAD: ~w `~s'~n", [Format,Chars]), @@ -106,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/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.

%% -%% @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 %% P is {Key, true} where Key is %% an atom, this returns Key, 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 Key if Value is %% true and Key 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 List to tuples %% {Atom, true}. %% %% @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 [property(P) || P <- List]. %% %% @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 Key in %% List, if one exists, otherwise returns %% none. For an atom A 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 Key %% in List. 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 true if List contains at least %% one entry associated with Key, otherwise %% false 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 %% List. If lookup(Key, List) would yield %% {Key, Value}, 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 get_value/2, but returns the list of %% values for all entries {Key, Value} in %% List. 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 get_all_values/2, 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 %% lookup(Key, List) would yield {Key, true}, %% this function returns true; otherwise false @@ -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 List, %% 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 Key from %% List. --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 %% List, if it is associated with some key K1 %% such that {K1, K2} occurs in Aliases, 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 List, if it is %% associated with some key K1 such that {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 {Property, %% Expansion} in Expansions, if E 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 List through a sequence of %% substitution/expansion stages. For an aliases operation, %% the function substitute_aliases/2 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 List into a list of sublists and a %% remainder. Lists contains one sublist for each key in %% Keys, 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]} %%

--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 b456c5d6c1..89fae05e4f 100644 --- a/lib/stdlib/src/timer.erl +++ b/lib/stdlib/src/timer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ send_after/3, send_after/2, exit_after/3, exit_after/2, kill_after/2, kill_after/1, apply_interval/4, send_interval/3, send_interval/2, - cancel/1, sleep/1, tc/2, tc/3, now_diff/2, + cancel/1, sleep/1, tc/1, tc/2, tc/3, now_diff/2, seconds/1, minutes/1, hours/1, hms/3]). -export([start_link/0, start/0, @@ -46,103 +46,189 @@ %% -opaque tref() :: {integer(), reference()}. -type time() :: non_neg_integer(). --type timestamp() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}. %% %% Interface functions %% --spec apply_after(time(), atom(), atom(), [term()]) -> {'ok', tref()} | {'error', term()}. +-spec apply_after(Time, Module, Function, Arguments) -> + {'ok', TRef} | {'error', Reason} when + Time :: time(), + Module :: module(), + Function :: atom(), + Arguments :: [term()], + TRef :: tref(), + Reason :: term(). + apply_after(Time, M, F, A) -> req(apply_after, {Time, {M, F, A}}). --spec send_after(time(), pid() | atom(), term()) -> {'ok', tref()} | {'error', term()}. +-spec send_after(Time, Pid, Message) -> {'ok', TRef} | {'error', Reason} when + Time :: time(), + Pid :: pid() | (RegName :: atom()), + Message :: term(), + TRef :: tref(), + Reason :: term(). send_after(Time, Pid, Message) -> req(apply_after, {Time, {?MODULE, send, [Pid, Message]}}). --spec send_after(time(), term()) -> {'ok', tref()} | {'error', term()}. +-spec send_after(Time, Message) -> {'ok', TRef} | {'error', Reason} when + Time :: time(), + Message :: term(), + TRef :: tref(), + Reason :: term(). send_after(Time, Message) -> send_after(Time, self(), Message). --spec exit_after(time(), pid() | atom(), term()) -> {'ok', tref()} | {'error', term()}. +-spec exit_after(Time, Pid, Reason1) -> {'ok', TRef} | {'error', Reason2} when + Time :: time(), + Pid :: pid() | (RegName :: atom()), + TRef :: tref(), + Reason1 :: term(), + Reason2 :: term(). exit_after(Time, Pid, Reason) -> req(apply_after, {Time, {erlang, exit, [Pid, Reason]}}). --spec exit_after(time(), term()) -> {'ok', tref()} | {'error', term()}. +-spec exit_after(Time, Reason1) -> {'ok', TRef} | {'error', Reason2} when + Time :: time(), + TRef :: tref(), + Reason1 :: term(), + Reason2 :: term(). exit_after(Time, Reason) -> exit_after(Time, self(), Reason). --spec kill_after(time(), pid() | atom()) -> {'ok', tref()} | {'error', term()}. +-spec kill_after(Time, Pid) -> {'ok', TRef} | {'error', Reason2} when + Time :: time(), + Pid :: pid() | (RegName :: atom()), + TRef :: tref(), + Reason2 :: term(). kill_after(Time, Pid) -> exit_after(Time, Pid, kill). --spec kill_after(time()) -> {'ok', tref()} | {'error', term()}. +-spec kill_after(Time) -> {'ok', TRef} | {'error', Reason2} when + Time :: time(), + TRef :: tref(), + Reason2 :: term(). kill_after(Time) -> exit_after(Time, self(), kill). --spec apply_interval(time(), atom(), atom(), [term()]) -> {'ok', tref()} | {'error', term()}. +-spec apply_interval(Time, Module, Function, Arguments) -> + {'ok', TRef} | {'error', Reason} when + Time :: time(), + Module :: module(), + Function :: atom(), + Arguments :: [term()], + TRef :: tref(), + Reason :: term(). apply_interval(Time, M, F, A) -> req(apply_interval, {Time, self(), {M, F, A}}). --spec send_interval(time(), pid() | atom(), term()) -> {'ok', tref()} | {'error', term()}. +-spec send_interval(Time, Pid, Message) -> + {'ok', TRef} | {'error', Reason} when + Time :: time(), + Pid :: pid() | (RegName :: atom()), + Message :: term(), + TRef :: tref(), + Reason :: term(). send_interval(Time, Pid, Message) -> req(apply_interval, {Time, Pid, {?MODULE, send, [Pid, Message]}}). --spec send_interval(time(), term()) -> {'ok', tref()} | {'error', term()}. +-spec send_interval(Time, Message) -> {'ok', TRef} | {'error', Reason} when + Time :: time(), + Message :: term(), + TRef :: tref(), + Reason :: term(). send_interval(Time, Message) -> send_interval(Time, self(), Message). --spec cancel(tref()) -> {'ok', 'cancel'} | {'error', term()}. +-spec cancel(TRef) -> {'ok', 'cancel'} | {'error', Reason} when + TRef :: tref(), + Reason :: term(). cancel(BRef) -> req(cancel, BRef). --spec sleep(timeout()) -> 'ok'. +-spec sleep(Time) -> 'ok' when + Time :: timeout(). sleep(T) -> receive after T -> ok end. +%% +%% Measure the execution time (in microseconds) for Fun(). +%% +-spec tc(Fun) -> {Time, Value} when + Fun :: function(), + Time :: integer(), + Value :: term(). +tc(F) -> + Before = os:timestamp(), + Val = F(), + After = os:timestamp(), + {now_diff(After, Before), Val}. %% %% Measure the execution time (in microseconds) for Fun(Args). %% --spec tc(function(), [_]) -> {time(), term()}. +-spec tc(Fun, Arguments) -> {Time, Value} when + Fun :: function(), + Arguments :: [term()], + Time :: integer(), + Value :: term(). tc(F, A) -> - Before = erlang:now(), - Val = (catch apply(F, A)), - After = erlang:now(), + Before = os:timestamp(), + Val = apply(F, A), + After = os:timestamp(), {now_diff(After, Before), Val}. %% %% Measure the execution time (in microseconds) for an MFA. %% --spec tc(atom(), atom(), [term()]) -> {time(), term()}. +-spec tc(Module, Function, Arguments) -> {Time, Value} when + Module :: module(), + Function :: atom(), + Arguments :: [term()], + Time :: integer(), + Value :: term(). tc(M, F, A) -> - Before = erlang:now(), - Val = (catch apply(M, F, A)), - After = erlang:now(), + Before = os:timestamp(), + Val = apply(M, F, A), + After = os:timestamp(), {now_diff(After, Before), Val}. %% %% Calculate the time difference (in microseconds) of two %% erlang:now() timestamps, T2-T1. %% --spec now_diff(timestamp(), timestamp()) -> integer(). +-spec now_diff(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). -- cgit v1.2.3