diff options
Diffstat (limited to 'lib/stdlib')
-rw-r--r-- | lib/stdlib/doc/src/lists.xml | 8 | ||||
-rw-r--r-- | lib/stdlib/doc/src/unicode_usage.xml | 44 | ||||
-rw-r--r-- | lib/stdlib/src/edlin_expand.erl | 8 | ||||
-rw-r--r-- | lib/stdlib/src/erl_eval.erl | 30 | ||||
-rw-r--r-- | lib/stdlib/src/erl_lint.erl | 21 | ||||
-rw-r--r-- | lib/stdlib/src/lists.erl | 15 | ||||
-rw-r--r-- | lib/stdlib/test/edlin_expand_SUITE.erl | 11 | ||||
-rw-r--r-- | lib/stdlib/test/erl_eval_SUITE.erl | 19 | ||||
-rw-r--r-- | lib/stdlib/test/erl_lint_SUITE.erl | 19 | ||||
-rw-r--r-- | lib/stdlib/test/expand_test.erl | 6 | ||||
-rw-r--r-- | lib/stdlib/test/expand_test1.erl | 4 | ||||
-rw-r--r-- | lib/stdlib/test/lists_SUITE.erl | 12 |
12 files changed, 144 insertions, 53 deletions
diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml index 251a383cf8..ee3c51c62c 100644 --- a/lib/stdlib/doc/src/lists.xml +++ b/lib/stdlib/doc/src/lists.xml @@ -123,6 +123,14 @@ </desc> </func> <func> + <name name="droplast" arity="1"/> + <fsummary>Drop the last element of a list</fsummary> + <desc> + <p>Drops the last element of a <c><anno>List</anno></c>. The list should + be non-empty, otherwise the function will crash with a <c>function_clause</c></p> + </desc> + </func> + <func> <name name="dropwhile" arity="2"/> <fsummary>Drop elements from a list while a predicate is true</fsummary> <desc> diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml index ee7dd128f1..75505d7d84 100644 --- a/lib/stdlib/doc/src/unicode_usage.xml +++ b/lib/stdlib/doc/src/unicode_usage.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>1999</year> - <year>2013</year> + <year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -41,10 +41,10 @@ future.</p> <p>The functionality described in EEP10 was implemented in Erlang/OTP - as of R13A, but that was by no means the end of it. In R14B01 support + R13A, but that was by no means the end of it. In Erlang/OTP R14B01 support for Unicode file names was added, although it was in no way complete and was by default disabled on platforms where no guarantee was given - for the file name encoding. With R16A came support for UTF-8 encoded + for the file name encoding. With Erlang/OTP R16A came support for UTF-8 encoded source code, among with enhancements to many of the applications to support both Unicode encoded file names as well as support for UTF-8 encoded files in several circumstances. Most notable is the support @@ -52,8 +52,8 @@ for UTF-8 and more support for Unicode character sets in the I/O-system.</p> - <p>In 17.0, the encoding default for Erlang source files was - switched to UTF-8 and in 18.0 Erlang will support atoms in the full + <p>In Erlang/OTP 17.0, the encoding default for Erlang source files was + switched to UTF-8 and in Erlang/OTP 18.0 Erlang will support atoms in the full Unicode range, meaning full Unicode function and module names</p> @@ -222,7 +222,7 @@ <tag>Representation</tag> <item>To handle Unicode characters in Erlang, we have to have a common representation both in lists and binaries. The EEP (10) and - the subsequent initial implementation in R13A settled a standard + the subsequent initial implementation in Erlang/OTP R13A settled a standard representation of Unicode characters in Erlang.</item> <tag>Manipulation</tag> <item>The Unicode characters need to be processed by the Erlang @@ -274,9 +274,9 @@ (<c>+fnu</c>) on platforms where this is not the default.</item> <tag>Source code encoding</tag> <item>When it comes to the Erlang source code, there is support - for the UTF-8 encoding and bytewise encoding. The default in R16B - is bytewise (or latin1) encoding. You can control the encoding by - a comment like: + for the UTF-8 encoding and bytewise encoding. The default in + Erlang/OTP R16B was bytewise (or latin1) encoding; in Erlang/OTP 17.0 + it was changed to UTF-8. You can control the encoding by a comment like: <code> %% -*- coding: utf-8 -*- </code> @@ -290,7 +290,7 @@ <item>Having the source code in UTF-8 also allows you to write string literals containing Unicode characters with code points > 255, although atoms, module names and function names will be - restricted to the ISO-Latin-1 range until the 18.0 release. Binary + restricted to the ISO-Latin-1 range until the Erlang/OTP 18.0 release. Binary literals where you use the <c>/utf8</c> type, can also be expressed using Unicode characters > 255. Having module names using characters other than 7-bit ASCII can cause trouble on @@ -304,7 +304,7 @@ <section> <title>Standard Unicode Representation</title> <p>In Erlang, strings are actually lists of integers. A string was - up until R13 defined to be encoded in the ISO-latin-1 (ISO8859-1) + up until Erlang/OTP R13 defined to be encoded in the ISO-latin-1 (ISO8859-1) character set, which is, code point by code point, a sub-range of the Unicode character set.</p> <p>The standard list encoding for strings was therefore easily @@ -321,7 +321,7 @@ encoding has to be decided upon and the string should be converted to a binary in the preferred encoding using <c>unicode:characters_to_binary/{1,2,3}</c>. Strings are not - generally lists of bytes, as they were before R13. They are lists of + generally lists of bytes, as they were before Erlang/OTP R13. They are lists of characters. Characters are not generally bytes, they are Unicode code points.</p> @@ -447,8 +447,8 @@ Bin4 = <<"Hello"/utf16>>,</code> probably will not appreciate). Another way is to keep it backwards compatible so that only the ISO-Latin-1 character set is used to detect a string. A third way would be to let the user decide - exactly what Unicode ranges are to be viewed as characters. In - R16B you can select either the whole Unicode range or the + exactly what Unicode ranges are to be viewed as characters. Since + Erlang/OTP R16B you can select either the whole Unicode range or the ISO-Latin-1 range by supplying the startup flag <c>+pc </c><i>Range</i>, where <i>Range</i> is either <c>latin1</c> or <c>unicode</c>. For backwards compatibility, the default is @@ -685,7 +685,7 @@ Eshell V5.10.1 (abort with ^G) </item> </taglist> - <p>The Unicode file naming support was introduced with OTP release + <p>The Unicode file naming support was introduced with Erlang/OTP R14B01. A VM operating in Unicode file name translation mode can work with files having names in any language or character set (as long as it is supported by the underlying OS and file system). The @@ -709,7 +709,7 @@ Eshell V5.10.1 (abort with ^G) problem even if it uses transparent file naming. Very few systems have mixed file name encodings. A consistent UTF-8 named system will work perfectly in Unicode file name mode. It was still however - considered experimental in R14B01 and is still not the default on + considered experimental in Erlang/OTP R14B01 and is still not the default on such systems. Unicode file name translation is turned on with the <c>+fnu</c> switch to the On Linux, a VM started without explicitly stating the file name translation mode will default to <c>latin1</c> @@ -757,7 +757,7 @@ Eshell V5.10.1 (abort with ^G) <title>Notes About Raw File Names</title> <marker id="notes-about-raw-filenames"/> <p>Raw file names were introduced together with Unicode file name - support in erts-5.8.2 (OTP R14B01). The reason "raw file + support in erts-5.8.2 (Erlang/OTP R14B01). The reason "raw file names" was introduced in the system was to be able to consistently represent file names given in different encodings on the same system. Having the VM automatically translate a file name @@ -798,10 +798,10 @@ Eshell V5.10.1 (abort with ^G) the argument as a binary.</p> <p>To force Unicode file name translation mode on systems where this - is not the default was considered experimental in OTP R14B01 due to + is not the default was considered experimental in Erlang/OTP R14B01 due to the fact that the initial implementation did not ignore wrongly encoded file names, so that raw file names could spread unexpectedly - throughout the system. Beginning with R16B, the wrongly encoded file + throughout the system. Beginning with Erlang/OTP R16B, the wrongly encoded file names are only retrieved by special functions (e.g. <c>file:list_dir_all/1</c>), so the impact on existing code is much lower, why it is now supported. Unicode file name translation @@ -1032,7 +1032,7 @@ ok <c>io</c>/<c>io_lib:format</c> with the <c>"~tp"</c> and <c>~tP</c> formatting instructions, as described above.</p> <p>You can check this option by calling io:printable_range/0, - which in R16B will return <c>unicode</c> or <c>latin1</c>. To be + which will return <c>unicode</c> or <c>latin1</c>. To be compatible with future (expected) extensions to the settings, one should rather use <c>io_lib:printable_list/1</c> to check if a list is printable according to the setting. That function will @@ -1070,8 +1070,8 @@ ok <item> <p>This function returns the default encoding for Erlang source files (if no encoding comment is present) in the currently - running release. For R16 this returns <c>latin1</c> (meaning - bytewise encoding). In 17.0 and forward it returns + running release. In Erlang/OTP R16B <c>latin1</c> was returned (meaning + bytewise encoding). In Erlang/OTP 17.0 and forward it returns <c>utf8</c>.</p> <p>The encoding of each file can be specified using comments as described in diff --git a/lib/stdlib/src/edlin_expand.erl b/lib/stdlib/src/edlin_expand.erl index 516c0aa30b..0033010dce 100644 --- a/lib/stdlib/src/edlin_expand.erl +++ b/lib/stdlib/src/edlin_expand.erl @@ -89,7 +89,13 @@ match(Prefix, Alts, Extra) -> {yes, Remain, []} end; {complete, Str} -> - {yes, nthtail(Len, Str) ++ Extra, []}; + {_, Arity} = lists:keyfind(Str, 1, Matches), + case {Arity, Extra} of + {0, "("} -> + {yes, nthtail(Len, Str) ++ "()", []}; + _ -> + {yes, nthtail(Len, Str) ++ Extra, []} + end; no -> {no, [], []} end. diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index 5f96795d92..63e7be4b74 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -241,23 +241,15 @@ expr({record,_,_,Name,_}, _Bs, _Lf, _Ef, _RBs) -> erlang:raise(error, {undef_record,Name}, stacktrace()); %% map -expr({map_field_assoc,_,EK, EV}, Bs0, Lf, Ef, RBs) -> - {value,K,Bs1} = expr(EK, Bs0, Lf, Ef, none), - {value,V,Bs2} = expr(EV, Bs0, Lf, Ef, none), - ret_expr({map_assoc,K,V}, merge_bindings(Bs1,Bs2), RBs); -expr({map_field_exact,_,EK, EV}, Bs0, Lf, Ef, RBs) -> - {value,K,Bs1} = expr(EK, Bs0, Lf, Ef, none), - {value,V,Bs2} = expr(EV, Bs0, Lf, Ef, none), - ret_expr({map_exact,K,V}, merge_bindings(Bs1,Bs2), RBs); expr({map,_, Binding,Es}, Bs0, Lf, Ef, RBs) -> {value, Map0, Bs1} = expr(Binding, Bs0, Lf, Ef, RBs), - {Vs,Bs} = expr_list(Es, Bs1, Lf, Ef), + {Vs,Bs} = eval_map_fields(Es, Bs1, Lf, Ef), ret_expr(lists:foldl(fun ({map_assoc,K,V}, Mi) -> maps:put(K,V,Mi); ({map_exact,K,V}, Mi) -> maps:update(K,V,Mi) end, Map0, Vs), Bs, RBs); expr({map,_,Es}, Bs0, Lf, Ef, RBs) -> - {Vs,Bs} = expr_list(Es, Bs0, Lf, Ef), + {Vs,Bs} = eval_map_fields(Es, Bs0, Lf, Ef), ret_expr(lists:foldl(fun ({map_assoc,K,V}, Mi) -> maps:put(K,V,Mi) end, maps:new(), Vs), Bs, RBs); @@ -749,6 +741,24 @@ eval_filter(F, Bs0, Lf, Ef, CompFun, Acc) -> end end. +%% eval_map_fields([Field], Bindings, LocalFunctionHandler, +%% ExternalFuncHandler) -> +%% {[{map_assoc | map_exact,Key,Value}],Bindings} + +eval_map_fields(Fs, Bs, Lf, Ef) -> + eval_map_fields(Fs, Bs, Lf, Ef, []). + +eval_map_fields([{map_field_assoc,_,K0,V0}|Fs], Bs0, Lf, Ef, Acc) -> + {value,K1,Bs1} = expr(K0, Bs0, Lf, Ef, none), + {value,V1,Bs2} = expr(V0, Bs1, Lf, Ef, none), + eval_map_fields(Fs, Bs2, Lf, Ef, [{map_assoc,K1,V1}|Acc]); +eval_map_fields([{map_field_exact,_,K0,V0}|Fs], Bs0, Lf, Ef, Acc) -> + {value,K1,Bs1} = expr(K0, Bs0, Lf, Ef, none), + {value,V1,Bs2} = expr(V0, Bs1, Lf, Ef, none), + eval_map_fields(Fs, Bs2, Lf, Ef, [{map_exact,K1,V1}|Acc]); +eval_map_fields([], Bs, _Lf, _Ef, Acc) -> + {lists:reverse(Acc),Bs}. + %% RBs is the bindings to return when the evalution of a function %% (fun) has finished. If RBs =:= none, then the evalution took place diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index f630db6032..0c6f41f594 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -100,7 +100,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) -> compile=[], %Compile flags records=dict:new() :: dict(), %Record definitions locals=gb_sets:empty() :: gb_set(), %All defined functions (prescanned) - no_auto=gb_sets:empty() :: gb_set(), %Functions explicitly not autoimported + no_auto=gb_sets:empty() :: gb_set() | 'all', %Functions explicitly not autoimported defined=gb_sets:empty() :: gb_set(), %Defined fuctions on_load=[] :: [fa()], %On-load function on_load_line=0 :: line(), %Line for on_load @@ -3648,15 +3648,22 @@ is_imported_from_erlang(ImportSet,{Func,Arity}) -> {ok,erlang} -> true; _ -> false end. -%% Build set of functions where auto-import is explicitly supressed +%% Build set of functions where auto-import is explicitly suppressed auto_import_suppressed(CompileFlags) -> - L0 = [ X || {no_auto_import,X} <- CompileFlags ], - L1 = [ {Y,Z} || {Y,Z} <- lists:flatten(L0), is_atom(Y), is_integer(Z) ], - gb_sets:from_list(L1). -%% Predicate to find out if autoimport is explicitly supressed for a function + case lists:member(no_auto_import, CompileFlags) of + true -> + all; + false -> + L0 = [ X || {no_auto_import,X} <- CompileFlags ], + L1 = [ {Y,Z} || {Y,Z} <- lists:flatten(L0), is_atom(Y), is_integer(Z) ], + gb_sets:from_list(L1) + end. +%% Predicate to find out if autoimport is explicitly suppressed for a function +is_autoimport_suppressed(all,{_Func,_Arity}) -> + true; is_autoimport_suppressed(NoAutoSet,{Func,Arity}) -> gb_sets:is_element({Func,Arity},NoAutoSet). -%% Predicate to find out if a function specific bif-clash supression (old deprecated) is present +%% Predicate to find out if a function specific bif-clash suppression (old deprecated) is present bif_clash_specifically_disabled(St,{F,A}) -> Nowarn = nowarn_function(nowarn_bif_clash, St#lint.compile), lists:member({F,A},Nowarn). diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl index d6a9f4645d..6303465d3d 100644 --- a/lib/stdlib/src/lists.erl +++ b/lib/stdlib/src/lists.erl @@ -22,7 +22,7 @@ -compile({no_auto_import,[min/2]}). -export([append/2, append/1, subtract/2, reverse/1, - nth/2, nthtail/2, prefix/2, suffix/2, last/1, + nth/2, nthtail/2, prefix/2, suffix/2, droplast/1, last/1, seq/2, seq/3, sum/1, duplicate/2, min/1, max/1, sublist/2, sublist/3, delete/2, unzip/1, unzip3/1, zip/2, zip3/3, zipwith/3, zipwith3/4, @@ -203,6 +203,19 @@ suffix(Suffix, List) -> Delta = length(List) - length(Suffix), Delta >= 0 andalso nthtail(Delta, List) =:= Suffix. +%% droplast(List) returns the list dropping its last element + +-spec droplast(List) -> InitList when + List :: [T, ...], + InitList :: [T], + T :: term(). + +%% This is the simple recursive implementation +%% reverse(tl(reverse(L))) is faster on average, +%% but creates more garbage. +droplast([_T]) -> []; +droplast([H|T]) -> [H|droplast(T)]. + %% last(List) returns the last element in a list. -spec last(List) -> Last when diff --git a/lib/stdlib/test/edlin_expand_SUITE.erl b/lib/stdlib/test/edlin_expand_SUITE.erl index 0cd2688e2e..2c1c5acf5a 100644 --- a/lib/stdlib/test/edlin_expand_SUITE.erl +++ b/lib/stdlib/test/edlin_expand_SUITE.erl @@ -76,11 +76,14 @@ normal(Config) when is_list(Config) -> [{"a_fun_name",1}, {"a_less_fun_name",1}, {"b_comes_after_a",1}, + {"expand0arity_entirely",0}, {"module_info",0}, {"module_info",1}]} = edlin_expand:expand(lists:reverse("expand_test:")), ?line {yes,[],[{"a_fun_name",1}, {"a_less_fun_name",1}]} = edlin_expand:expand( lists:reverse("expand_test:a_")), + ?line {yes,"arity_entirely()",[]} = edlin_expand:expand( + lists:reverse("expand_test:expand0")), ok. quoted_fun(doc) -> @@ -93,7 +96,7 @@ quoted_fun(Config) when is_list(Config) -> %% should be no colon after test this time ?line {yes, "test", []} = edlin_expand:expand(lists:reverse("expand_")), ?line {no, [], []} = edlin_expand:expand(lists:reverse("expandXX_")), - ?line {no,[],[{"'#weird-fun-name'",0}, + ?line {no,[],[{"'#weird-fun-name'",1}, {"'Quoted_fun_name'",0}, {"'Quoted_fun_too'",0}, {"a_fun_name",1}, @@ -108,7 +111,7 @@ quoted_fun(Config) when is_list(Config) -> {"a_less_fun_name",1}]} = edlin_expand:expand( lists:reverse("expand_test1:a_")), ?line {yes,[], - [{"'#weird-fun-name'",0}, + [{"'#weird-fun-name'",1}, {"'Quoted_fun_name'",0}, {"'Quoted_fun_too'",0}]} = edlin_expand:expand( lists:reverse("expand_test1:'")), @@ -172,6 +175,6 @@ quoted_both(Config) when is_list(Config) -> [{"'Quoted_fun_name'",0}, {"'Quoted_fun_too'",0}]} = edlin_expand:expand( lists:reverse("'ExpandTestCaps1':'Quoted_fun_")), - ?line {yes,"weird-fun-name'(",[]} = edlin_expand:expand( - lists:reverse("'ExpandTestCaps1':'#")), + ?line {yes,"weird-fun-name'()",[]} = edlin_expand:expand( + lists:reverse("'ExpandTestCaps1':'#")), ok. diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index c4b6b35e72..b194c7cb41 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -42,7 +42,8 @@ try_catch/1, eval_expr_5/1, zero_width/1, - eep37/1]). + eep37/1, + eep43/1]). %% %% Define to run outside of test server @@ -82,7 +83,7 @@ all() -> simple_cases, unary_plus, apply_atom, otp_5269, otp_6539, otp_6543, otp_6787, otp_6977, otp_7550, otp_8133, otp_10622, funs, try_catch, eval_expr_5, zero_width, - eep37]. + eep37, eep43]. groups() -> []. @@ -1424,6 +1425,20 @@ eep37(Config) when is_list(Config) -> 720), ok. +eep43(Config) when is_list(Config) -> + check(fun () -> #{} end, " #{}.", #{}), + check(fun () -> #{a => b} end, "#{a => b}.", #{a => b}), + check(fun () -> + Map = #{a => b}, + {Map#{a := b},Map#{a => c},Map#{d => e}} + end, + "begin " + " Map = #{a => B=b}, " + " {Map#{a := B},Map#{a => c},Map#{d => e}} " + "end.", + {#{a => b},#{a => c},#{a => b,d => e}}), + ok. + %% Check the string in different contexts: as is; in fun; from compiled code. check(F, String, Result) -> check1(F, String, Result), diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 6e9a9dd7bf..48f50d5f43 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -2827,7 +2827,24 @@ bif_clash(Config) when is_list(Config) -> {6,erl_lint,{illegal_guard_local_call,{is_tuple,1}}}, {7,erl_lint,{illegal_guard_local_call,{is_list,1}}}, {8,erl_lint,{illegal_guard_local_call,{is_record,3}}}, - {9,erl_lint,{illegal_guard_local_call,{is_record,3}}}],[]}} + {9,erl_lint,{illegal_guard_local_call,{is_record,3}}}],[]}}, + %% We can also suppress all auto imports at once + {clash22, + <<"-export([size/1, binary_part/2]). + -compile(no_auto_import). + size([]) -> + 0; + size({N,_}) -> + N; + size([_|T]) -> + 1+size(T). + binary_part({B,_},{X,Y}) -> + binary_part(B,{X,Y}); + binary_part(B,{X,Y}) -> + binary:part(B,X,Y). + ">>, + [], + []} ], ?line [] = run(Config, Ts), diff --git a/lib/stdlib/test/expand_test.erl b/lib/stdlib/test/expand_test.erl index 63e4bc3aa0..b9db32c352 100644 --- a/lib/stdlib/test/expand_test.erl +++ b/lib/stdlib/test/expand_test.erl @@ -20,7 +20,8 @@ -export([a_fun_name/1, a_less_fun_name/1, - b_comes_after_a/1]). + b_comes_after_a/1, + expand0arity_entirely/0]). a_fun_name(X) -> X. @@ -30,3 +31,6 @@ a_less_fun_name(X) -> b_comes_after_a(X) -> X. + +expand0arity_entirely () -> + ok. diff --git a/lib/stdlib/test/expand_test1.erl b/lib/stdlib/test/expand_test1.erl index 11b6fec0f3..1d375e5677 100644 --- a/lib/stdlib/test/expand_test1.erl +++ b/lib/stdlib/test/expand_test1.erl @@ -23,7 +23,7 @@ b_comes_after_a/1, 'Quoted_fun_name'/0, 'Quoted_fun_too'/0, - '#weird-fun-name'/0]). + '#weird-fun-name'/1]). a_fun_name(X) -> X. @@ -40,5 +40,5 @@ b_comes_after_a(X) -> 'Quoted_fun_too'() -> too. -'#weird-fun-name'() -> +'#weird-fun-name'(_) -> weird. diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl index 92253ef5b9..f4589a8e24 100644 --- a/lib/stdlib/test/lists_SUITE.erl +++ b/lib/stdlib/test/lists_SUITE.erl @@ -61,7 +61,7 @@ zip_unzip/1, zip_unzip3/1, zipwith/1, zipwith3/1, filter_partition/1, otp_5939/1, otp_6023/1, otp_6606/1, otp_7230/1, - suffix/1, subtract/1]). + suffix/1, subtract/1, droplast/1]). %% Sort randomized lists until stopped. %% @@ -2641,4 +2641,12 @@ sub_non_matching(A, B) -> sub(A, B) -> Res = A -- B, Res = lists:subtract(A, B). - + +%% Test lists:droplast/1 +droplast(Config) when is_list(Config) -> + ?line [] = lists:droplast([x]), + ?line [x] = lists:droplast([x, y]), + ?line {'EXIT', {function_clause, _}} = (catch lists:droplast([])), + ?line {'EXIT', {function_clause, _}} = (catch lists:droplast(x)), + + ok. |