diff options
Diffstat (limited to 'lib')
66 files changed, 810 insertions, 651 deletions
diff --git a/lib/Makefile b/lib/Makefile index 5128241563..6301c882b2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -25,12 +25,12 @@ ERTS_APPLICATIONS = stdlib sasl kernel compiler # Then these have to be build ERLANG_APPLICATIONS = tools test_server common_test runtime_tools \ - inets xmerl edoc erl_docgen + inets xmerl edoc erl_docgen parsetools # These are only build if -a is given to otp_build or make is used directly ALL_ERLANG_APPLICATIONS = snmp otp_mibs erl_interface asn1 jinterface \ wx debugger reltool gs \ - ic mnesia crypto orber os_mon parsetools syntax_tools \ + ic mnesia crypto orber os_mon syntax_tools \ public_key ssl observer odbc diameter \ cosTransactions cosEvent cosTime cosNotification \ cosProperty cosFileTransfer cosEventDomain et megaco webtool \ diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl index f94f3b56bc..df034c96ad 100644 --- a/lib/asn1/src/asn1ct_check.erl +++ b/lib/asn1/src/asn1ct_check.erl @@ -2642,16 +2642,19 @@ normalize_objectdescriptor(Value) -> normalize_real(Value) -> Value. -normalize_enumerated(S, Id, {Base,Ext}) -> +normalize_enumerated(S, Id0, NNL) -> + {Id,_} = lookup_enum_value(S, Id0, NNL), + Id. + +lookup_enum_value(S, Id, {Base,Ext}) -> %% Extensible ENUMERATED. - normalize_enumerated(S, Id, Base++Ext); -normalize_enumerated(S, #'Externalvaluereference'{value=Id}, - NamedNumberList) -> - normalize_enumerated(S, Id, NamedNumberList); -normalize_enumerated(S, Id, NamedNumberList) when is_atom(Id) -> - case lists:keymember(Id, 1, NamedNumberList) of - true -> - Id; + lookup_enum_value(S, Id, Base++Ext); +lookup_enum_value(S, #'Externalvaluereference'{value=Id}, NNL) -> + lookup_enum_value(S, Id, NNL); +lookup_enum_value(S, Id, NNL) when is_atom(Id) -> + case lists:keyfind(Id, 1, NNL) of + {_,_}=Ret -> + Ret; false -> throw(asn1_error(S, S#state.value, {undefined,Id})) end. @@ -3786,8 +3789,9 @@ resolv_value(S,Val) -> resolv_value1(S,Id). resolv_value1(S, ERef = #'Externalvaluereference'{value=Name}) -> - case catch resolve_namednumber(S,S#state.type,Name) of - V when is_integer(V) -> V; + case catch resolve_namednumber(S, S#state.type, Name) of + V when is_integer(V) -> + V; _ -> case get_referenced_type(S,ERef) of {Err,_Reason} when Err == error; Err == 'EXIT' -> @@ -3840,21 +3844,20 @@ resolve_value_from_object(S,Object,FieldName) -> end. - resolve_namednumber(S,#typedef{typespec=Type},Name) -> case Type#type.def of {'ENUMERATED',NameList} -> - NamedNumberList=check_enumerated(S,NameList,Type#type.constraint), - N = normalize_enumerated(S,Name,NamedNumberList), - {value,{_,V}} = lists:keysearch(N,1,NamedNumberList), - V; + resolve_namednumber_1(S, Name, NameList, Type); {'INTEGER',NameList} -> - NamedNumberList = check_enumerated(S,NameList,Type#type.constraint), - {value,{_,V}} = lists:keysearch(Name,1,NamedNumberList), - V; + resolve_namednumber_1(S, Name, NameList, Type); _ -> not_enumerated end. + +resolve_namednumber_1(S, Name, NameList, Type) -> + NamedNumberList = check_enumerated(S, NameList, Type#type.constraint), + {_,N} = lookup_enum_value(S, Name, NamedNumberList), + N. check_constraints(S,[{'ContainedSubtype',Type} | Rest], Acc) -> {RefMod,CTDef} = get_referenced_type(S,Type#type.def), diff --git a/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1 b/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1 index 8dc5f3d7e1..74fa97e7aa 100644 --- a/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1 +++ b/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1 @@ -18,6 +18,8 @@ Ext1 ::= ENUMERATED { magenta(9) } +SubExt1 ::= Ext1 ( blue | orange | black ) + Noext ::= ENUMERATED { blue(0), red(1), diff --git a/lib/asn1/test/testEnumExt.erl b/lib/asn1/test/testEnumExt.erl index c66adaf949..878518be11 100644 --- a/lib/asn1/test/testEnumExt.erl +++ b/lib/asn1/test/testEnumExt.erl @@ -59,6 +59,10 @@ main(ber) -> common(ber). common(Erule) -> + roundtrip('SubExt1', blue), + roundtrip('SubExt1', orange), + roundtrip('SubExt1', black), + roundtrip('Seq', {'Seq',blue,42}), roundtrip('Seq', {'Seq',red,42}), roundtrip('Seq', {'Seq',green,42}), diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 682f7adbc2..2486d486ed 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -882,7 +882,7 @@ valfun_4(_, _) -> verify_put_map(Fail, Src, Dst, Live, List, Vst0) -> verify_live(Live, Vst0), verify_y_init(Vst0), - [assert_term(Term, Vst0) || Term <- List], + foreach(fun (Term) -> assert_term(Term, Vst0) end, List), assert_term(Src, Vst0), Vst1 = heap_alloc(0, Vst0), Vst2 = branch_state(Fail, Vst1), @@ -909,7 +909,7 @@ validate_bs_skip_utf(Fail, Ctx, Live, Vst0) -> branch_state(Fail, Vst). %% -%% Special state handling for setelement/3 and the set_tuple_element/3 instruction. +%% Special state handling for setelement/3 and set_tuple_element/3 instructions. %% A possibility for garbage collection must not occur between setelement/3 and %% set_tuple_element/3. %% diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index 5588f1fbe5..e79fe41f9b 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -626,7 +626,8 @@ core_passes() -> {iff,dcorefold,{listing,"corefold"}}, {core_inline_module,fun test_core_inliner/1,fun core_inline_module/1}, {iff,dinline,{listing,"inline"}}, - {core_fold_after_inlining,fun test_core_inliner/1,fun core_fold_module_after_inlining/1}, + {core_fold_after_inlining,fun test_any_inliner/1, + fun core_fold_module_after_inlining/1}, ?pass(core_transforms)]}, {iff,dcopt,{listing,"copt"}}, {iff,'to_core',{done,"core"}}]} @@ -1172,6 +1173,9 @@ test_core_inliner(#compile{options=Opts}) -> end, Opts) end. +test_any_inliner(St) -> + test_old_inliner(St) orelse test_core_inliner(St). + core_old_inliner(#compile{code=Code0,options=Opts}=St) -> {ok,Code} = sys_core_inline:module(Code0, Opts), {ok,St#compile{code=Code}}. diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index e302e2324d..e2b9213891 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -353,7 +353,12 @@ expr(#c_case{}=Case0, Ctxt, Sub) -> Case = Case1#c_case{arg=Arg2,clauses=Cs2}, warn_no_clause_match(Case1, Case), Expr = eval_case(Case, Sub), - bsm_an(Expr); + case move_case_into_arg(Case, Sub) of + impossible -> + bsm_an(Expr); + Other -> + expr(Other, Ctxt, sub_new_preserve_types(Sub)) + end; Other -> expr(Other, Ctxt, Sub) end; @@ -1940,7 +1945,9 @@ opt_bool_case_guard(Arg, [#c_clause{pats=[#c_literal{val=false}]}=Fc,Tc]) -> %% last clause is guaranteed to match so if there is only one clause %% with a pattern containing only variables then rewrite to a let. -eval_case(#c_case{arg=E,clauses=[#c_clause{pats=Ps0,body=B}]}, Sub) -> +eval_case(#c_case{arg=E,clauses=[#c_clause{pats=Ps0, + guard=#c_literal{val=true}, + body=B}]}=Case, Sub) -> Es = case cerl:is_c_values(E) of true -> cerl:values_es(E); false -> [E] @@ -1955,7 +1962,7 @@ eval_case(#c_case{arg=E,clauses=[#c_clause{pats=Ps0,body=B}]}, Sub) -> %% %% let <X,Y> = <SomeSideEffect(),SomeSideEffect()> in ... %% - %% because SomeSideEffect() would be called evaluated twice. + %% because SomeSideEffect() would be evaluated twice. %% %% Instead we must evaluate the case expression in an outer let %% like this: @@ -1964,11 +1971,19 @@ eval_case(#c_case{arg=E,clauses=[#c_clause{pats=Ps0,body=B}]}, Sub) -> %% let <X,Y> = <NewVar,NewVar> in ... %% Vs = make_vars([], length(Es)), - {true,Bs} = cerl_clauses:match_list(Ps0, Vs), - {Ps,As} = unzip(Bs), - InnerLet = cerl:c_let(Ps, core_lib:make_values(As), B), - Let = cerl:c_let(Vs, E, InnerLet), - expr(Let, sub_new(Sub)); + case cerl_clauses:match_list(Ps0, Vs) of + {false,_} -> + %% This can only happen if the Core Erlang code is + %% handwritten or generated by another code generator + %% than v3_core. Assuming that the Core Erlang program + %% is correct, the clause will always match at run-time. + Case; + {true,Bs} -> + {Ps,As} = unzip(Bs), + InnerLet = cerl:c_let(Ps, core_lib:make_values(As), B), + Let = cerl:c_let(Vs, E, InnerLet), + expr(Let, sub_new(Sub)) + end; eval_case(Case, _) -> Case. %% case_opt(CaseArg, [Clause]) -> {CaseArg,[Clause]}. @@ -2596,6 +2611,77 @@ opt_simple_let_2(Let, Vs0, Arg0, Body, value, Sub) -> value, Sub) end. +move_case_into_arg(#c_case{arg=#c_let{vars=OuterVars0,arg=OuterArg, + body=InnerArg0}=Outer, + clauses=InnerClauses}=Inner, Sub) -> + %% + %% case let <OuterVars> = <OuterArg> in <InnerArg> of + %% <InnerClauses> + %% end + %% + %% ==> + %% + %% let <OuterVars> = <OuterArg> + %% in case <InnerArg> of <InnerClauses> end + %% + ScopeSub0 = sub_subst_scope(Sub#sub{t=[]}), + {OuterVars,ScopeSub} = pattern_list(OuterVars0, ScopeSub0), + InnerArg = body(InnerArg0, ScopeSub), + Outer#c_let{vars=OuterVars,arg=OuterArg, + body=Inner#c_case{arg=InnerArg,clauses=InnerClauses}}; +move_case_into_arg(#c_case{arg=#c_case{arg=OuterArg, + clauses=[OuterCa0,OuterCb]}=Outer, + clauses=InnerClauses}=Inner0, Sub) -> + case is_failing_clause(OuterCb) of + true -> + #c_clause{pats=OuterPats0,guard=OuterGuard0, + body=InnerArg0} = OuterCa0, + %% + %% case case <OuterArg> of + %% <OuterPats> when <OuterGuard> -> <InnerArg> + %% <OuterCb> + %% ... + %% end of + %% <InnerClauses> + %% end + %% + %% ==> + %% + %% case <OuterArg> of + %% <OuterPats> when <OuterGuard> -> + %% case <InnerArg> of <InnerClauses> end + %% <OuterCb> + %% end + %% + ScopeSub0 = sub_subst_scope(Sub#sub{t=[]}), + {OuterPats,ScopeSub} = pattern_list(OuterPats0, ScopeSub0), + OuterGuard = guard(OuterGuard0, ScopeSub), + InnerArg = body(InnerArg0, ScopeSub), + Inner = Inner0#c_case{arg=InnerArg,clauses=InnerClauses}, + OuterCa = OuterCa0#c_clause{pats=OuterPats,guard=OuterGuard, + body=Inner}, + Outer#c_case{arg=OuterArg, + clauses=[OuterCa,OuterCb]}; + false -> + impossible + end; +move_case_into_arg(#c_case{arg=#c_seq{arg=OuterArg,body=InnerArg}=Outer, + clauses=InnerClauses}=Inner, _Sub) -> + %% + %% case do <OuterArg> <InnerArg> of + %% <InnerClauses> + %% end + %% + %% ==> + %% + %% do <OuterArg> + %% case <InnerArg> of <InerClauses> end + %% + Outer#c_seq{arg=OuterArg, + body=Inner#c_case{arg=InnerArg,clauses=InnerClauses}}; +move_case_into_arg(_, _) -> + impossible. + %% In guards only, rewrite a case in a let argument like %% %% let <Var> = case <> of diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 291443f824..ec5deb6905 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -900,6 +900,7 @@ lc_tq(Line, E, [{generate,Lg,P,G}|Qs0], Mc, St0) -> {Head,St2} = new_var(St1), {Tname,St3} = new_var_name(St2), LA = lineno_anno(Line, St3), + CGAnno = #a{anno=[list_comprehension|LA]}, LAnno = #a{anno=LA}, Tail = #c_var{anno=LA,name=Tname}, {Arg,St4} = new_var(St3), @@ -937,7 +938,7 @@ lc_tq(Line, E, [{generate,Lg,P,G}|Qs0], Mc, St0) -> body=Lps ++ [Lc]}|Cs0] end, Fun = #ifun{anno=LAnno,id=[],vars=[Arg],clauses=Cs,fc=Fc}, - {#iletrec{anno=LAnno,defs=[{{Name,1},Fun}], + {#iletrec{anno=CGAnno,defs=[{{Name,1},Fun}], body=Gps ++ [#iapply{anno=LAnno, op=#c_var{anno=LA,name={Name,1}}, args=[Gc]}]}, @@ -947,6 +948,7 @@ lc_tq(Line, E, [{b_generate,Lg,P,G}|Qs0], Mc, St0) -> {Name,St1} = new_fun_name("blc", St0), LA = lineno_anno(Line, St1), LAnno = #a{anno=LA}, + CGAnno = #a{anno=[list_comprehension|LA]}, HeadBinPattern = pattern(P, St1), #c_binary{segments=Ps0} = HeadBinPattern, {Ps,Tail,St2} = append_tail_segment(Ps0, St1), @@ -975,7 +977,7 @@ lc_tq(Line, E, [{b_generate,Lg,P,G}|Qs0], Mc, St0) -> pats=[#c_binary{anno=LA,segments=TailSegList}],guard=[], body=[Mc]}], Fun = #ifun{anno=LAnno,id=[],vars=[Arg],clauses=Cs,fc=Fc}, - {#iletrec{anno=LAnno,defs=[{{Name,1},Fun}], + {#iletrec{anno=CGAnno,defs=[{{Name,1},Fun}], body=Gps ++ [#iapply{anno=LAnno, op=#c_var{anno=LA,name={Name,1}}, args=[Gc]}]}, @@ -984,12 +986,13 @@ lc_tq(Line, E, [Fil0|Qs0], Mc, St0) -> %% Special case sequences guard tests. LA = lineno_anno(element(2, Fil0), St0), LAnno = #a{anno=LA}, + CGAnno = #a{anno=[list_comprehension|LA]}, case is_guard_test(Fil0) of true -> {Gs0,Qs1} = splitwith(fun is_guard_test/1, Qs0), {Lc,Lps,St1} = lc_tq(Line, E, Qs1, Mc, St0), {Gs,St2} = lc_guard_tests([Fil0|Gs0], St1), %These are always flat! - {#icase{anno=LAnno, + {#icase{anno=CGAnno, args=[], clauses=[#iclause{anno=LAnno,pats=[], guard=Gs,body=Lps ++ [Lc]}], @@ -1003,7 +1006,7 @@ lc_tq(Line, E, [Fil0|Qs0], Mc, St0) -> c_tuple([#c_literal{val=case_clause},Fpat])), %% Do a novars little optimisation here. {Filc,Fps,St3} = novars(Fil0, St2), - {#icase{anno=LAnno, + {#icase{anno=CGAnno, args=[Filc], clauses=[#iclause{anno=LAnno, pats=[#c_literal{anno=LA,val=true}], @@ -1047,6 +1050,7 @@ bc_tq1(Line, E, [{generate,Lg,P,G}|Qs0], AccExpr, St0) -> LA = lineno_anno(Line, St1), {[Head,Tail,AccVar],St2} = new_vars(LA, 3, St1), LAnno = #a{anno=LA}, + CGAnno = #a{anno=[list_comprehension|LA]}, {Arg,St3} = new_var(St2), NewMore = {call,Lg,{atom,Lg,Name},[{var,Lg,Tail#c_var.name}, {var,Lg,AccVar#c_var.name}]}, @@ -1080,7 +1084,7 @@ bc_tq1(Line, E, [{generate,Lg,P,G}|Qs0], AccExpr, St0) -> body=Body}|Cs0] end, Fun = #ifun{anno=LAnno,id=[],vars=[Arg,AccVar],clauses=Cs,fc=Fc}, - {#iletrec{anno=LAnno,defs=[{{Name,2},Fun}], + {#iletrec{anno=CGAnno,defs=[{{Name,2},Fun}], body=Gps ++ [#iapply{anno=LAnno, op=#c_var{anno=LA,name={Name,2}}, args=[Gc,AccExpr]}]}, @@ -1091,6 +1095,7 @@ bc_tq1(Line, E, [{b_generate,Lg,P,G}|Qs0], AccExpr, St0) -> LA = lineno_anno(Line, St1), {AccVar,St2} = new_var(LA, St1), LAnno = #a{anno=LA}, + CGAnno = #a{anno=[list_comprehension|LA]}, HeadBinPattern = pattern(P, St2), #c_binary{segments=Ps0} = HeadBinPattern, {Ps,Tail,St3} = append_tail_segment(Ps0, St2), @@ -1119,7 +1124,7 @@ bc_tq1(Line, E, [{b_generate,Lg,P,G}|Qs0], AccExpr, St0) -> pats=[#c_binary{anno=LA,segments=TailSegList},AccVar], guard=[], body=[AccVar]}], - Fun = #ifun{anno=LAnno,id=[],vars=[Arg,AccVar],clauses=Cs,fc=Fc}, + Fun = #ifun{anno=CGAnno,id=[],vars=[Arg,AccVar],clauses=Cs,fc=Fc}, {#iletrec{anno=LAnno,defs=[{{Name,2},Fun}], body=Gps ++ [#iapply{anno=LAnno, op=#c_var{anno=LA,name={Name,2}}, @@ -1129,12 +1134,13 @@ bc_tq1(Line, E, [Fil0|Qs0], AccVar, St0) -> %% Special case sequences guard tests. LA = lineno_anno(element(2, Fil0), St0), LAnno = #a{anno=LA}, + CGAnno = #a{anno=[list_comprehension|LA]}, case is_guard_test(Fil0) of true -> {Gs0,Qs1} = splitwith(fun is_guard_test/1, Qs0), {Bc,Bps,St1} = bc_tq1(Line, E, Qs1, AccVar, St0), {Gs,St} = lc_guard_tests([Fil0|Gs0], St1), %These are always flat! - {#icase{anno=LAnno, + {#icase{anno=CGAnno, args=[], clauses=[#iclause{anno=LAnno, pats=[], @@ -1149,7 +1155,7 @@ bc_tq1(Line, E, [Fil0|Qs0], AccVar, St0) -> c_tuple([#c_literal{val=case_clause},Fpat])), %% Do a novars little optimisation here. {Filc,Fps,St} = novars(Fil0, St2), - {#icase{anno=LAnno, + {#icase{anno=CGAnno, args=[Filc], clauses=[#iclause{anno=LAnno, pats=[#c_literal{anno=LA,val=true}], diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl index 1a521c3591..aa222c48de 100644 --- a/lib/compiler/test/core_SUITE.erl +++ b/lib/compiler/test/core_SUITE.erl @@ -24,7 +24,7 @@ dehydrated_itracer/1,nested_tries/1, seq_in_guard/1,make_effect_seq/1,eval_is_boolean/1, unsafe_case/1,nomatch_shadow/1,reversed_annos/1, - map_core_test/1]). + map_core_test/1,eval_case/1]). -include_lib("test_server/include/test_server.hrl"). @@ -50,7 +50,7 @@ groups() -> [{p,test_lib:parallel(), [dehydrated_itracer,nested_tries,seq_in_guard,make_effect_seq, eval_is_boolean,unsafe_case,nomatch_shadow,reversed_annos, - map_core_test + map_core_test,eval_case ]}]. @@ -76,6 +76,7 @@ end_per_group(_GroupName, Config) -> ?comp(nomatch_shadow). ?comp(reversed_annos). ?comp(map_core_test). +?comp(eval_case). try_it(Mod, Conf) -> Src = filename:join(?config(data_dir, Conf), atom_to_list(Mod)), diff --git a/lib/compiler/test/core_SUITE_data/eval_case.core b/lib/compiler/test/core_SUITE_data/eval_case.core new file mode 100644 index 0000000000..f2776e2b1f --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/eval_case.core @@ -0,0 +1,34 @@ +module 'eval_case' ['eval_case'/0] + attributes [] +'eval_case'/0 = + fun () -> + case <> of + <> when 'true' -> + case apply 'do_case'/0() of + <'ok'> when 'true' -> + 'ok' + ( <_cor0> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor0}) + -| ['compiler_generated'] ) + end + ( <> when 'true' -> + ( primop 'match_fail' + ({'function_clause'}) + -| [{'function_name',{'eval_case',0}}] ) + -| ['compiler_generated'] ) + end +'do_case'/0 = + fun () -> + case let <_cor0> = + apply 'id'/1(42) + in let <_cor1> = + call 'erlang':'+' + (_cor0, 7) + in {'x',_cor1} of + <{'x',49}> when 'true' -> + 'ok' + end +'id'/1 = + fun (_cor0) -> _cor0 +end diff --git a/lib/debugger/src/dbg_wx_filedialog_win.erl b/lib/debugger/src/dbg_wx_filedialog_win.erl index c8ecb7b5d4..ea34295067 100644 --- a/lib/debugger/src/dbg_wx_filedialog_win.erl +++ b/lib/debugger/src/dbg_wx_filedialog_win.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2012. All Rights Reserved. +%% Copyright Ericsson AB 2009-2014. 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 @@ -242,16 +242,13 @@ handle_event(#wx{event=#wxList{itemIndex=Index}}, {noreply, State0} end; -handle_event(#wx{event=#wxCommand{type=command_text_updated, cmdString=Wanted}}, +handle_event(#wx{event=#wxCommand{type=command_text_updated, cmdString=Wanted}}, State = #state{ptext=Previous, completion=Comp}) -> case Previous =:= undefined orelse lists:prefix(Wanted, Previous) of - true -> - case Comp of - {Temp,_} -> wxWindow:destroy(Temp); - undefined -> ok - end, + true -> + destroy_completion(Comp), {noreply, State#state{ptext=Wanted,completion=undefined}}; - false -> + false -> {noreply, show_completion(Wanted, State)} end; @@ -310,8 +307,7 @@ handle_event(#wx{event=#wxSize{size={Width,_}}}, State = #state{list=LC}) -> end), {noreply, State}; -handle_event(Event,State) -> - io:format("~p Got ~p ~n",[self(), Event]), +handle_event(_Event,State) -> {noreply, State}. handle_info(_Msg, State) -> @@ -419,8 +415,9 @@ show_completion(Wanted, State = #state{text=TC, win=Win, list=LC, completion=Com end. destroy_completion(undefined) -> ok; -destroy_completion({Window, _}) -> +destroy_completion({Window, _LB}) -> Parent = wxWindow:getParent(Window), + wxWindow:hide(Window), wxWindow:destroy(Window), wxWindow:refresh(Parent). diff --git a/lib/debugger/src/dbg_wx_mon.erl b/lib/debugger/src/dbg_wx_mon.erl index 4a01492cf5..4ab03985d3 100644 --- a/lib/debugger/src/dbg_wx_mon.erl +++ b/lib/debugger/src/dbg_wx_mon.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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 @@ -148,7 +148,7 @@ init2(CallingPid, Mode, SFile, GS) -> win = Win, focus = undefined, - coords = {20,20}, + coords = {-1,-1}, intdir = element(2, file:get_cwd()), pinfos = [], diff --git a/lib/debugger/src/dbg_wx_mon_win.erl b/lib/debugger/src/dbg_wx_mon_win.erl index 0071b27027..d94eb14937 100644 --- a/lib/debugger/src/dbg_wx_mon_win.erl +++ b/lib/debugger/src/dbg_wx_mon_win.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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 @@ -617,8 +617,6 @@ handle_event(#wx{userData=Data, _WinInfo) -> Data; handle_event(_Event, _WinInfo) -> -%% FIXME - io:format("Ev: ~p~n",[_Event]), ignore. %%==================================================================== diff --git a/lib/debugger/src/dbg_wx_trace.erl b/lib/debugger/src/dbg_wx_trace.erl index 1ac796bb4c..4438466bb0 100644 --- a/lib/debugger/src/dbg_wx_trace.erl +++ b/lib/debugger/src/dbg_wx_trace.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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 @@ -125,7 +125,7 @@ init(Pid, Parent, Meta, TraceWin, BackTrace, Strings) -> dbg_wx_winman:insert(Title, Window), %% Initial process state - State1 = #state{win=Win, coords={0,0}, pid=Pid, meta=Meta, + State1 = #state{win=Win, coords={-1,-1}, pid=Pid, meta=Meta, status={idle,null,null}, stack={1,1}, strings=[str_on]}, diff --git a/lib/debugger/src/dbg_wx_view.erl b/lib/debugger/src/dbg_wx_view.erl index 6242b9d0e0..fc7ffc0d56 100644 --- a/lib/debugger/src/dbg_wx_view.erl +++ b/lib/debugger/src/dbg_wx_view.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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 @@ -72,7 +72,7 @@ init(GS, Env, Mod, Title) -> Win2, int:all_breaks(Mod)), - try loop(#state{gs=GS, win=Win3, coords={0,0}, mod=Mod}) + try loop(#state{gs=GS, win=Win3, coords={-1,-1}, mod=Mod}) catch _E:normal -> exit(normal); _E:_R -> diff --git a/lib/edoc/src/edoc_tags.erl b/lib/edoc/src/edoc_tags.erl index 74702102f0..264a533a52 100644 --- a/lib/edoc/src/edoc_tags.erl +++ b/lib/edoc/src/edoc_tags.erl @@ -454,7 +454,7 @@ check_type(#tag{line = L, data = Data}, P0, Ls, Ts) -> check_type(#t_def{type = Type}, P, Ls, Ts) -> check_type(Type, P, Ls, Ts); check_type(#t_type{name = Name, args = Args}, P, Ls, Ts) -> - check_used_type(Name, Args, P, Ls), + _ = check_used_type(Name, Args, P, Ls), check_types3(Args++Ts, P, Ls); check_type(#t_var{}, P, Ls, Ts) -> check_types3(Ts, P, Ls); diff --git a/lib/gs/doc/src/gs.xml b/lib/gs/doc/src/gs.xml index e0d7fb20da..7b589d002d 100644 --- a/lib/gs/doc/src/gs.xml +++ b/lib/gs/doc/src/gs.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2000</year> - <year>2013</year> + <year>2014</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -39,7 +39,7 @@ graphical user interface. </p> <p> - GS is deprecated and will be removed in the R16 release. + GS is deprecated and will be removed in the 18.0 release. </p> </warning> <p>The Graphics System, GS, is easy to learn and diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl index 4e8ba1b78a..c3bf1ac012 100644 --- a/lib/kernel/src/application.erl +++ b/lib/kernel/src/application.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -132,7 +132,7 @@ ensure_all_started(Application, Type) -> {ok, Started} -> {ok, lists:reverse(Started)}; {error, Reason, Started} -> - [stop(App) || App <- Started], + _ = [stop(App) || App <- Started], {error, Reason} end. diff --git a/lib/observer/src/cdv_bin_cb.erl b/lib/observer/src/cdv_bin_cb.erl index 0266047ee3..d5fbceff1e 100644 --- a/lib/observer/src/cdv_bin_cb.erl +++ b/lib/observer/src/cdv_bin_cb.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013. All Rights Reserved. +%% Copyright Ericsson AB 2013-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,26 +21,26 @@ detail_pages/0]). %% Callbacks for cdv_detail_wx -get_details({_, {T,Key}}) -> +get_details({Type, {T,Key}}) -> [{Key,Term}] = ets:lookup(T,Key), - {ok,{"Expanded Binary", Term, []}}; + {ok,{"Expanded Binary", {Type, Term}, []}}; get_details({cdv, Id}) -> {ok,Bin} = crashdump_viewer:expand_binary(Id), - {ok,{"Expanded Binary", Bin, []}}. + {ok,{"Expanded Binary", {cvd, Bin}, []}}. detail_pages() -> [{"Binary", fun init_bin_page/2}]. -init_bin_page(Parent,Bin) -> +init_bin_page(Parent,{Type,Bin}) -> cdv_multi_wx:start_link( Parent, - [{"Format \~p",cdv_html_wx,format_bin_fun("~p",Bin)}, - {"Format \~tp",cdv_html_wx,format_bin_fun("~tp",Bin)}, - {"Format \~w",cdv_html_wx,format_bin_fun("~w",Bin)}, - {"Format \~s",cdv_html_wx,format_bin_fun("~s",Bin)}, - {"Format \~ts",cdv_html_wx,format_bin_fun("~ts",Bin)}, - {"Hex",cdv_html_wx,hex_binary_fun(Bin)}, - {"Term",cdv_html_wx,binary_to_term_fun(Bin)}]). + [{"Format \~p",cdv_html_wx,{Type,format_bin_fun("~p",Bin)}}, + {"Format \~tp",cdv_html_wx,{Type,format_bin_fun("~tp",Bin)}}, + {"Format \~w",cdv_html_wx,{Type,format_bin_fun("~w",Bin)}}, + {"Format \~s",cdv_html_wx,{Type,format_bin_fun("~s",Bin)}}, + {"Format \~ts",cdv_html_wx,{Type,format_bin_fun("~ts",Bin)}}, + {"Hex",cdv_html_wx,{Type,hex_binary_fun(Bin)}}, + {"Term",cdv_html_wx,{Type,binary_to_term_fun(Bin)}}]). format_bin_fun(Format,Bin) -> fun() -> diff --git a/lib/observer/src/cdv_html_wx.erl b/lib/observer/src/cdv_html_wx.erl index fe77a41f59..b79c647f63 100644 --- a/lib/observer/src/cdv_html_wx.erl +++ b/lib/observer/src/cdv_html_wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013. All Rights Reserved. +%% Copyright Ericsson AB 2013-2014. 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 @@ -30,6 +30,7 @@ %% Records -record(state, {panel, + app, %% which tool is the user expand_table, expand_wins=[]}). @@ -38,16 +39,21 @@ start_link(ParentWin, Info) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -init([ParentWin, Fun]) when is_function(Fun) -> - init([ParentWin, Fun()]); +init([ParentWin, {App, Fun}]) when is_function(Fun) -> + init([ParentWin, {App, Fun()}]); init([ParentWin, {expand,HtmlText,Tab}]) -> - HtmlWin = observer_lib:html_window(ParentWin), - wxHtmlWindow:setPage(HtmlWin,HtmlText), - {HtmlWin, #state{panel=HtmlWin,expand_table=Tab}}; + init(ParentWin, HtmlText, Tab, cdv); +init([ParentWin, {App, {expand,HtmlText,Tab}}]) -> + init(ParentWin, HtmlText, Tab, App); +init([ParentWin, {App,HtmlText}]) -> + init(ParentWin, HtmlText, undefined, App); init([ParentWin, HtmlText]) -> + init(ParentWin, HtmlText, undefined, cdv). + +init(ParentWin, HtmlText, Tab, App) -> HtmlWin = observer_lib:html_window(ParentWin), wxHtmlWindow:setPage(HtmlWin,HtmlText), - {HtmlWin, #state{panel=HtmlWin}}. + {HtmlWin, #state{panel=HtmlWin,expand_table=Tab,app=App}}. %%%%%%%%%%%%%%%%%%%%%%% Callbacks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -78,7 +84,7 @@ handle_cast(Msg, State) -> handle_event(#wx{event=#wxHtmlLink{type=command_html_link_clicked, linkInfo=#wxHtmlLinkInfo{href=Target}}}, - #state{expand_table=Tab}=State) -> + #state{expand_table=Tab, app=App}=State) -> NewState= case Target of "#Binary?" ++ BinSpec -> @@ -102,10 +108,12 @@ handle_event(#wx{event=#wxHtmlLink{type=command_html_link_clicked, list_to_integer(Key2), list_to_integer(Key3)}}}, expand(Id,cdv_term_cb,State); + _ when App =:= obs -> + observer ! {open_link, Target}; _ -> cdv_virtual_list_wx:start_detail_win(Target), State - end, + end, {noreply, NewState}; handle_event(Event, State) -> diff --git a/lib/observer/src/cdv_term_cb.erl b/lib/observer/src/cdv_term_cb.erl index 6426cc0803..4451045012 100644 --- a/lib/observer/src/cdv_term_cb.erl +++ b/lib/observer/src/cdv_term_cb.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013. All Rights Reserved. +%% Copyright Ericsson AB 2013-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,23 +21,23 @@ detail_pages/0]). %% Callbacks for cdv_detail_wx -get_details({_, {T,Key}}) -> +get_details({Type, {T,Key}}) -> [{Key,Term}] = ets:lookup(T,Key), - {ok,{"Expanded Term", [Term, T], []}}. + {ok,{"Expanded Term", {Type,[Term, T]}, []}}. detail_pages() -> [{"Term", fun init_term_page/2}]. -init_term_page(ParentWin, [Term, Tab]) -> +init_term_page(ParentWin, {Type, [Term, Tab]}) -> Expanded = expand(Term, true), BinSaved = expand(Term, Tab), cdv_multi_wx:start_link( ParentWin, - [{"Format \~p",cdv_html_wx,format_term_fun("~p",BinSaved,Tab)}, - {"Format \~tp",cdv_html_wx,format_term_fun("~tp",BinSaved,Tab)}, - {"Format \~w",cdv_html_wx,format_term_fun("~w",BinSaved,Tab)}, - {"Format \~s",cdv_html_wx,format_term_fun("~s",Expanded,Tab)}, - {"Format \~ts",cdv_html_wx,format_term_fun("~ts",Expanded,Tab)}]). + [{"Format \~p",cdv_html_wx,{Type, format_term_fun("~p",BinSaved,Tab)}}, + {"Format \~tp",cdv_html_wx,{Type,format_term_fun("~tp",BinSaved,Tab)}}, + {"Format \~w",cdv_html_wx,{Type,format_term_fun("~w",BinSaved,Tab)}}, + {"Format \~s",cdv_html_wx,{Type,format_term_fun("~s",Expanded,Tab)}}, + {"Format \~ts",cdv_html_wx,{Type,format_term_fun("~ts",Expanded,Tab)}}]). format_term_fun(Format,Term,Tab) -> fun() -> @@ -56,8 +56,9 @@ expand(['#CDVBin',Offset,Size,Pos], true) -> {ok,Bin} = crashdump_viewer:expand_binary({Offset,Size,Pos}), Bin; expand(Bin, Tab) when is_binary(Bin), not is_boolean(Tab) -> - <<Preview:80, _/binary>> = Bin, Size = byte_size(Bin), + PrevSize = min(Size, 10) * 8, + <<Preview:PrevSize, _/binary>> = Bin, Hash = erlang:phash2(Bin), Key = {Preview, Size, Hash}, ets:insert(Tab, {Key,Bin}), diff --git a/lib/observer/src/observer_html_lib.erl b/lib/observer/src/observer_html_lib.erl index 9f77891426..c279218707 100644 --- a/lib/observer/src/observer_html_lib.erl +++ b/lib/observer/src/observer_html_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2013. All Rights Reserved. +%% Copyright Ericsson AB 2003-2014. 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 @@ -146,7 +146,8 @@ all_or_expand(Tab,Term) -> Check = io_lib:format("~P",[Term,100]), Exp = Preview=/=Check, all_or_expand(Tab,Term,Preview,Exp). -all_or_expand(_Tab,_Term,Str,false) -> +all_or_expand(_Tab,Term,Str,false) + when not is_binary(Term) -> href_proc_port(lists:flatten(Str)); all_or_expand(Tab,Term,Preview,true) when not is_binary(Term) -> @@ -158,20 +159,16 @@ all_or_expand(Tab,Term,Preview,true) "&key2="++integer_to_list(Key2)++ "&key3="++integer_to_list(Key3)], "Click to expand above term")]; -all_or_expand(Tab,Bin,PreviewStr,true) when is_binary(Bin) -> - <<Preview:80, _/binary>> = Bin, +all_or_expand(Tab,Bin,_PreviewStr,_Expand) + when is_binary(Bin) -> Size = byte_size(Bin), + PrevSize = min(Size, 10) * 8, + <<Preview:PrevSize, _/binary>> = Bin, Hash = erlang:phash2(Bin), Key = {Preview, Size, Hash}, ets:insert(Tab,{Key,Bin}), - [href_proc_port(lists:flatten(PreviewStr), false), $\n, - href("TARGET=\"expanded\"", - ["#OBSBinary?key1="++integer_to_list(Preview)++ - "&key2="++integer_to_list(Size)++ - "&key3="++integer_to_list(Hash)], - "Click to expand above term")]. - - + Term = io_lib:format("~p", [['#OBSBin',Preview,Size,Hash]]), + href_proc_port(lists:flatten(Term), true). color(true) -> io_lib:format("BGCOLOR=\"#~2.16.0B~2.16.0B~2.16.0B\"", tuple_to_list(?BG_EVEN)); color(false) -> io_lib:format("BGCOLOR=\"#~2.16.0B~2.16.0B~2.16.0B\"", tuple_to_list(?BG_ODD)). @@ -242,7 +239,7 @@ href(Args,Link,Text) -> ["<A HREF=\"",Link,"\" ",Args,">",Text,"</A>"]. font(Args,Text) -> ["<FONT ",Args,">\n",Text,"\n</FONT>\n"]. -p(Text) -> +p(Text) -> ["<P>",Text,"</P>\n"]. br() -> "<BR>\n". @@ -336,34 +333,28 @@ href_proc_bin(From, T, Acc, LTB) -> {OffsetSizePos,Rest} = split($],T), BinStr = case string:tokens(OffsetSizePos,",.| \n") of - [Offset,Size,Pos] when From =:= cdv -> + [Offset,SizeStr,Pos] when From =:= cdv -> Id = {list_to_integer(Offset),10,list_to_integer(Pos)}, {ok,PreviewBin} = crashdump_viewer:expand_binary(Id), - PreviewStr = ["<<", - [integer_to_list(X)++"," || <<X:8>> <= PreviewBin], - "...(", - observer_lib:to_str({bytes,Size}), - ")>>"], + PreviewStr = preview_string(list_to_integer(SizeStr), PreviewBin), if LTB -> href("TARGET=\"expanded\"", ["#Binary?offset="++Offset++ - "&size="++Size++ + "&size="++SizeStr++ "&pos="++Pos], PreviewStr); true -> PreviewStr end; - [Preview,Size,Md5] when From =:= obs -> - PreviewBin = <<(list_to_integer(Preview)):80>>, - PreviewStr = ["<<", - [integer_to_list(X)++"," || <<X:8>> <= PreviewBin], - "...(", - observer_lib:to_str({bytes,list_to_integer(Size)}), - ")>>"], + [Preview,SizeStr,Md5] when From =:= obs -> + Size = list_to_integer(SizeStr), + PrevSize = min(Size, 10) * 8, + PreviewStr = preview_string(Size, + <<(list_to_integer(Preview)):PrevSize>>), if LTB -> href("TARGET=\"expanded\"", ["#OBSBinary?key1="++Preview++ - "&key2="++Size++ + "&key2="++SizeStr++ "&key3="++Md5], PreviewStr); true -> @@ -374,6 +365,35 @@ href_proc_bin(From, T, Acc, LTB) -> end, href_proc_port(Rest,[BinStr|Acc],LTB). +preview_string(Size, PreviewBin) when Size > 10 -> + ["<<", + remove_lgt(io_lib:format("~p",[PreviewBin])), + "...(", + observer_lib:to_str({bytes,Size}), + ")", + ">>"]; +preview_string(_, PreviewBin) -> + ["<<", + remove_lgt(io_lib:format("~p",[PreviewBin])), + ">>"]. + +remove_lgt(Deep) -> + remove_lgt_1(lists:flatten(Deep)). + +remove_lgt_1([$<,$<|Rest]) -> + [$>,$>|BinStr] = lists:reverse(Rest), + replace_lgt(lists:reverse(BinStr)). + +replace_lgt([$<|R]) -> + ["<"|replace_lgt(R)]; +replace_lgt([$>|R]) -> + [">"|replace_lgt(R)]; +replace_lgt([L=[_|_]|R]) -> + [replace_lgt(L)|replace_lgt(R)]; +replace_lgt([A|R]) -> + [A|replace_lgt(R)]; +replace_lgt([]) -> []. + split(Char,Str) -> split(Char,Str,[]). split(Char,[Char|Str],Acc) -> % match Char @@ -381,7 +401,6 @@ split(Char,[Char|Str],Acc) -> % match Char split(Char,[H|T],Acc) -> split(Char,T,[H|Acc]). - warn([]) -> []; warn(Warning) -> diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl index e0f7bf482b..cedaf7d2b8 100644 --- a/lib/observer/src/observer_lib.erl +++ b/lib/observer/src/observer_lib.erl @@ -699,7 +699,9 @@ progress_handler(Caller,Env,Title,Str) -> register(?progress_handler,self()), wx:set_env(Env), PD = progress_dialog(Env,Title,Str), - progress_loop(Title,PD,Caller). + try progress_loop(Title,PD,Caller) + catch closed -> normal end. + progress_loop(Title,PD,Caller) -> receive {progress,{ok,done}} -> % to make wait_for_progress/0 return @@ -738,8 +740,12 @@ progress_dialog(_Env,Title,Str) -> PD. update_progress(PD,Value) -> - wxProgressDialog:update(PD,Value). + try wxProgressDialog:update(PD,Value) + catch _:_ -> throw(closed) %% Port or window have died + end. update_progress_text(PD,Text) -> - wxProgressDialog:update(PD,0,[{newmsg,Text}]). + try wxProgressDialog:update(PD,0,[{newmsg,Text}]) + catch _:_ -> throw(closed) %% Port or window have died + end. finish_progress(PD) -> wxProgressDialog:destroy(PD). diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl index 988e04993c..3ffa5fc77d 100644 --- a/lib/observer/src/observer_procinfo.erl +++ b/lib/observer/src/observer_procinfo.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2013. All Rights Reserved. +%% Copyright Ericsson AB 2011-2014. 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 @@ -136,9 +136,9 @@ handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Href}}}, {noreply, State}; Callback -> [{"key1",Key1},{"key2",Key2},{"key3",Key3}] = httpd:parse_query(Rest), - Id = {observer, {T,{list_to_integer(Key1), - list_to_integer(Key2), - list_to_integer(Key3)}}}, + Id = {obs, {T,{list_to_integer(Key1), + list_to_integer(Key2), + list_to_integer(Key3)}}}, Opened = case lists:keyfind(Id,1,Opened0) of false -> diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl index 4c385b76aa..ecb8e132fe 100644 --- a/lib/observer/src/observer_wx.erl +++ b/lib/observer/src/observer_wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2013. All Rights Reserved. +%% Copyright Ericsson AB 2011-2014. 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 @@ -214,7 +214,7 @@ handle_event(#wx{event = #wxClose{}}, State) -> {stop, normal, State}; handle_event(#wx{id = ?ID_CDV, event = #wxCommand{type = command_menu_selected}}, State) -> - crashdump_viewer:start(), + spawn(crashdump_viewer, start, []), {noreply, State}; handle_event(#wx{id = ?wxID_EXIT, event = #wxCommand{type = command_menu_selected}}, State) -> diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl index b698beb558..f4657663e6 100644 --- a/lib/parsetools/src/yecc.erl +++ b/lib/parsetools/src/yecc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -423,7 +423,7 @@ infile(Parent, Infilex, Options) -> end, case {St#yecc.errors, werror(St)} of {[], false} -> ok; - _ -> _ = file:delete(St#yecc.outfile) + _ -> _ = file:delete(St#yecc.outfile), ok end, Parent ! {self(), yecc_ret(St)}. diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index 7e9d7c984a..ad2a8005b9 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2013. All Rights Reserved. +%% Copyright Ericsson AB 2011-2014. 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 @@ -1781,37 +1781,46 @@ otp_10463_upgrade_script_regexp(_Config) -> ok. no_dot_erlang(Conf) -> - PrivDir = priv_dir(Conf), + PrivDir = ?config(data_dir,Conf), {ok, OrigWd} = file:get_cwd(), try ok = file:set_cwd(PrivDir), - Erl = "\"" ++ filename:join([code:root_dir(),"bin","erl"]) ++ "\"", - Args = " -noinput -run io put_chars \"TESTOK\" -run erlang halt", + {ok, Wd} = file:get_cwd(), + io:format("Dir ~ts~n", [Wd]), + + Erl0 = filename:join([code:root_dir(),"bin","erl"]), + Erl = filename:nativename(Erl0), + Quote = "\"", + Args = " -noinput -run c pwd -run erlang halt", ok = file:write_file(".erlang", <<"io:put_chars(\"DOT_ERLANG_READ\\n\").\n">>), - case os:cmd(Erl ++ Args) of + CMD1 = Quote ++ Erl ++ Quote ++ Args , + case os:cmd(CMD1) of "DOT_ERLANG_READ" ++ _ -> ok; Other1 -> - io:format("Failed: ~ts~n",[Erl ++ Args]), + io:format("Failed: ~ts~n",[CMD1]), io:format("Expected: ~s ++ _~n",["DOT_ERLANG_READ "]), io:format("Got: ~ts~n",[Other1]), - exit(failed_to_start, test_error) + exit({failed_to_start, test_error}) end, NO_DOT_ERL = " -boot no_dot_erlang", - case os:cmd(Erl ++ NO_DOT_ERL ++ Args) of - "TESTOK" ++ _ -> ok; - Other2 -> - io:format("Failed: ~ts~n",[Erl ++ Args]), + CMD2 = Quote ++ Erl ++ Quote ++ NO_DOT_ERL ++ Args, + case lists:prefix(Wd, Other2 = os:cmd(CMD2)) of + true -> ok; + false -> + io:format("Failed: ~ts~n",[CMD2]), io:format("Expected: ~s~n",["TESTOK"]), io:format("Got: ~ts~n",[Other2]), - exit(failed_to_start, no_dot_erlang) + exit({failed_to_start, no_dot_erlang}) end after _ = file:delete(".erlang"), - ok = file:set_cwd(OrigWd) + ok = file:set_cwd(OrigWd), + ok end. + %%%================================================================= %%% Misceleaneous functions %%%================================================================= diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl index fa4397b2f5..8d6c77c0ed 100644 --- a/lib/ssh/src/ssh_message.erl +++ b/lib/ssh/src/ssh_message.erl @@ -380,27 +380,30 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_BANNER), language = Lang }; +decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_REQUEST), ?UINT32(Len0), Name:Len0/binary, + ?UINT32(Len1), Inst:Len1/binary, ?UINT32(Len2), Lang:Len2/binary, + ?UINT32(NumPromtps), Data/binary>>) -> + #ssh_msg_userauth_info_request{ + name = Name, + instruction = Inst, + language_tag = Lang, + num_prompts = NumPromtps, + data = Data}; + +%%% Unhandled message, also masked by same 1:st byte value as ?SSH_MSG_USERAUTH_INFO_REQUEST: decode(<<?BYTE(?SSH_MSG_USERAUTH_PK_OK), ?UINT32(Len), Alg:Len/binary, KeyBlob/binary>>) -> #ssh_msg_userauth_pk_ok{ algorithm_name = Alg, key_blob = KeyBlob }; +%%% Unhandled message, also masked by same 1:st byte value as ?SSH_MSG_USERAUTH_INFO_REQUEST: decode(<<?BYTE(?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ), ?UINT32(Len0), Prompt:Len0/binary, ?UINT32(Len1), Lang:Len1/binary>>) -> #ssh_msg_userauth_passwd_changereq{ prompt = Prompt, languge = Lang }; -decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_REQUEST), ?UINT32(Len0), Name:Len0/binary, - ?UINT32(Len1), Inst:Len1/binary, ?UINT32(Len2), Lang:Len2/binary, - ?UINT32(NumPromtps), Data/binary>>) -> - #ssh_msg_userauth_info_request{ - name = Name, - instruction = Inst, - language_tag = Lang, - num_prompts = NumPromtps, - data = Data}; decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_RESPONSE), ?UINT32(Num), Data/binary>>) -> #ssh_msg_userauth_info_response{ @@ -424,8 +427,9 @@ decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST_OLD), ?UINT32(N)>>) -> #ssh_msg_kex_dh_gex_request_old{ n = N }; -decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP), ?UINT32(Len0), Prime:Len0/big-signed-integer, - ?UINT32(Len1), Generator:Len1/big-signed-integer>>) -> +decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP), + ?UINT32(Len0), Prime:Len0/big-signed-integer-unit:8, + ?UINT32(Len1), Generator:Len1/big-signed-integer-unit:8>>) -> #ssh_msg_kex_dh_gex_group{ p = Prime, g = Generator 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_pp.erl b/lib/stdlib/src/erl_pp.erl index 8a1d8e0440..9dbe89da91 100644 --- a/lib/stdlib/src/erl_pp.erl +++ b/lib/stdlib/src/erl_pp.erl @@ -479,6 +479,15 @@ lexpr({record_field, _, Rec, F}, Prec, Opts) -> {L,P,R} = inop_prec('.'), El = [lexpr(Rec, L, Opts),$.,lexpr(F, R, Opts)], maybe_paren(P, Prec, El); +lexpr({map, _, Fs}, Prec, Opts) -> + {P,_R} = preop_prec('#'), + El = {first,leaf("#"),map_fields(Fs, Opts)}, + maybe_paren(P, Prec, El); +lexpr({map, _, Map, Fs}, Prec, Opts) -> + {L,P,_R} = inop_prec('#'), + Rl = lexpr(Map, L, Opts), + El = {first,[Rl,leaf("#")],map_fields(Fs, Opts)}, + maybe_paren(P, Prec, El); lexpr({block,_,Es}, _, Opts) -> {list,[{step,'begin',body(Es, Opts)},'end']}; lexpr({'if',_,Cs}, _, Opts) -> @@ -671,6 +680,16 @@ record_field({typed_record_field,Field,Type}, Opts) -> record_field({record_field,_,F}, Opts) -> lexpr(F, 0, Opts). +map_fields(Fs, Opts) -> + tuple(Fs, fun map_field/2, Opts). + +map_field({map_field_assoc,_,K,V}, Opts) -> + Pl = lexpr(K, 0, Opts), + {list,[{step,[Pl,leaf(" =>")],lexpr(V, 0, Opts)}]}; +map_field({map_field_exact,_,K,V}, Opts) -> + Pl = lexpr(K, 0, Opts), + {list,[{step,[Pl,leaf(" :=")],lexpr(V, 0, Opts)}]}. + list({cons,_,H,T}, Es, Opts) -> list(T, [H|Es], Opts); list({nil,_}, Es, Opts) -> diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl index afc63496d0..7f3cd8f592 100644 --- a/lib/stdlib/src/re.erl +++ b/lib/stdlib/src/re.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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 @@ -19,7 +19,6 @@ -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. 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_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index cc744ee76b..390322a5fa 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -46,6 +46,7 @@ import_export/1, misc_attrs/1, dialyzer_attrs/1, hook/1, neg_indent/1, + maps_syntax/1, otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1, otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1, @@ -76,7 +77,8 @@ groups() -> [{expr, [], [func, call, recs, try_catch, if_then, receive_after, bits, head_tail, cond1, block, case1, ops, - messages, old_mnemosyne_syntax]}, + messages, old_mnemosyne_syntax, maps_syntax + ]}, {attributes, [], [misc_attrs, import_export, dialyzer_attrs]}, {tickets, [], [otp_6321, otp_6911, otp_6914, otp_8150, otp_8238, @@ -975,6 +977,25 @@ count_atom(L, A) when is_list(L) -> count_atom(_, _) -> 0. +maps_syntax(doc) -> "Maps syntax"; +maps_syntax(suite) -> []; +maps_syntax(Config) when is_list(Config) -> + Ts = [{map_fun_1, + <<"t() ->\n" + " M0 = #{ 1 => hi, hi => 42, 1.0 => {hi,world}},\n" + " M1 = M0#{ 1 := hello, new_val => 1337 },\n" + " map_fun_2:val(M1).\n">>}, + {map_fun_2, + <<"val(#{ 1 := V1, hi := V2, new_val := V3}) -> {V1,V2,V3}.\n">>}], + compile(Config, Ts), + + ok = pp_expr(<<"#{}">>), + ok = pp_expr(<<"#{ a => 1, <<\"hi\">> => \"world\", 33 => 1.0 }">>), + ok = pp_expr(<<"#{ a := V1, <<\"hi\">> := V2 } = M">>), + ok = pp_expr(<<"M#{ a => V1, <<\"hi\">> := V2 }">>), + ok. + + otp_8567(doc) -> "OTP_8567. Avoid duplicated 'undefined' in record field types."; otp_8567(suite) -> []; diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index bc83739ba6..d367e7b5d6 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -176,8 +176,6 @@ module_names(Beams) -> do_cover_compile(Modules) -> do_cover_compile1(lists:usort(Modules)). % remove duplicates -do_cover_compile1([Dont|Rest]) when Dont=:=cover -> - do_cover_compile1(Rest); do_cover_compile1([M|Rest]) -> case {code:is_sticky(M),code:is_loaded(M)} of {true,_} -> diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index d26b8adfcd..a24d70ed92 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -89,8 +89,9 @@ flush/1, stop/0, stop/1]). -export([remote_start/1,get_main_node/0]). -%-export([bump/5]). --export([transform/4]). % for test purposes + +%% Used internally to ensure we upgrade the code to the latest version. +-export([main_process_loop/1,remote_process_loop/1]). -record(main_state, {compiled=[], % [{Module,File}] imported=[], % [{Module,File,ImportFile}] @@ -110,7 +111,6 @@ -define(BUMP_REC_NAME,bump). -record(vars, {module, % atom() Module name - vsn, % atom() init_info=[], % [{M,F,A,C,L}] @@ -230,25 +230,9 @@ compile_directory(Dir) when is_list(Dir) -> compile_directory(Dir, Options) when is_list(Dir), is_list(Options) -> case file:list_dir(Dir) of {ok, Files} -> - - %% Filter out all erl files (except cover.erl) - ErlFileNames = - lists:filter(fun("cover.erl") -> - false; - (File) -> - case filename:extension(File) of - ".erl" -> true; - _ -> false - end - end, - Files), - - %% Create a list of .erl file names (incl path) and call - %% compile_modules/2 with the list of file names. - ErlFiles = lists:map(fun(ErlFileName) -> - filename:join(Dir, ErlFileName) - end, - ErlFileNames), + ErlFiles = [filename:join(Dir, File) || + File <- Files, + filename:extension(File) =:= ".erl"], compile_modules(ErlFiles, Options); Error -> Error @@ -262,7 +246,7 @@ compile_modules([File|Files], Options, Result) -> R = call({compile, File, Options}), compile_modules(Files,Options,[R|Result]); compile_modules([],_Opts,Result) -> - reverse(Result). + lists:reverse(Result). filter_options(Options) -> lists:filter(fun(Option) -> @@ -320,25 +304,9 @@ compile_beam_directory() -> compile_beam_directory(Dir) when is_list(Dir) -> case file:list_dir(Dir) of {ok, Files} -> - - %% Filter out all beam files (except cover.beam) - BeamFileNames = - lists:filter(fun("cover.beam") -> - false; - (File) -> - case filename:extension(File) of - ".beam" -> true; - _ -> false - end - end, - Files), - - %% Create a list of .beam file names (incl path) and call - %% compile_beam/1 for each such file name - BeamFiles = lists:map(fun(BeamFileName) -> - filename:join(Dir, BeamFileName) - end, - BeamFileNames), + BeamFiles = [filename:join(Dir, File) || + File <- Files, + filename:extension(File) =:= ".beam"], compile_beams(BeamFiles); Error -> Error @@ -350,7 +318,7 @@ compile_beams([File|Files],Result) -> R = compile_beam(File), compile_beams(Files,[R|Result]); compile_beams([],Result) -> - reverse(Result). + lists:reverse(Result). %% analyse(Module) -> @@ -613,8 +581,11 @@ main_process_loop(State) -> Compiled = add_compiled(Module, File, State#main_state.compiled), Imported = remove_imported(Module,State#main_state.imported), - main_process_loop(State#main_state{compiled = Compiled, - imported = Imported}); + NewState = State#main_state{compiled = Compiled, + imported = Imported}, + %% This module (cover) could have been reloaded. Make + %% sure we run the new code. + ?MODULE:main_process_loop(NewState); error -> reply(From, {error, File}), main_process_loop(State) @@ -639,8 +610,11 @@ main_process_loop(State) -> end, reply(From,Reply), Imported = remove_imported(Module,State#main_state.imported), - main_process_loop(State#main_state{compiled = Compiled, - imported = Imported}); + NewState = State#main_state{compiled = Compiled, + imported = Imported}, + %% This module (cover) could have been reloaded. Make + %% sure we run the new code. + ?MODULE:main_process_loop(NewState); {error,no_beam} -> %% The module has first been compiled from .erl, and now %% someone tries to compile it from .beam @@ -857,7 +831,7 @@ remote_process_loop(State) -> {remote,load_compiled,Compiled} -> Compiled1 = load_compiled(Compiled,State#remote_state.compiled), remote_reply(State#remote_state.main_node, ok), - remote_process_loop(State#remote_state{compiled=Compiled1}); + ?MODULE:remote_process_loop(State#remote_state{compiled=Compiled1}); {remote,unload,UnloadedModules} -> unload(UnloadedModules), @@ -1257,12 +1231,12 @@ add_imported(M, F1, ImportFile, [{M,_F2,ImportFiles}|Imported], Acc) -> dont_import; false -> NewEntry = {M, F1, [ImportFile | ImportFiles]}, - {ok, reverse([NewEntry | Acc]) ++ Imported} + {ok, lists:reverse([NewEntry | Acc]) ++ Imported} end; add_imported(M, F, ImportFile, [H|Imported], Acc) -> add_imported(M, F, ImportFile, Imported, [H|Acc]); add_imported(M, F, ImportFile, [], Acc) -> - {ok, reverse([{M, F, [ImportFile]} | Acc])}. + {ok, lists:reverse([{M, F, [ImportFile]} | Acc])}. %% Removes a module from the list of imported modules and writes a warning %% This is done when a module is compiled. @@ -1383,9 +1357,9 @@ do_compile_beam(Module,Beam,UserOptions) -> {error,E}; encrypted_abstract_code=E -> {error,E}; - {Vsn,Code} -> + {raw_abstract_v1,Code} -> Forms0 = epp:interpret_file_attribute(Code), - {Forms,Vars} = transform(Vsn, Forms0, Module, Beam), + {Forms,Vars} = transform(Forms0, Module), %% We need to recover the source from the compilation %% info otherwise the newly compiled module will have @@ -1400,7 +1374,7 @@ do_compile_beam(Module,Beam,UserOptions) -> {module, Module} -> %% Store info about all function clauses in database - InitInfo = reverse(Vars#vars.init_info), + InitInfo = lists:reverse(Vars#vars.init_info), ets:insert(?COVER_CLAUSE_TABLE, {Module, InitInfo}), %% Store binary code so it can be loaded on remote nodes @@ -1411,7 +1385,11 @@ do_compile_beam(Module,Beam,UserOptions) -> _Error -> do_clear(Module), error - end + end; + {_VSN,_Code} -> + %% Wrong version of abstract code. Just report that there + %% is no abstract code. + {error,no_abstract_code} end. get_abstract_code(Module, Beam) -> @@ -1445,28 +1423,9 @@ get_compile_info(Module, Beam) -> [] end. -transform(Vsn, Code, Module, Beam) when Vsn=:=abstract_v1; Vsn=:=abstract_v2 -> - Vars0 = #vars{module=Module, vsn=Vsn}, - MainFile=find_main_filename(Code), - {ok, MungedForms,Vars} = transform_2(Code,[],Vars0,MainFile,on), - - %% Add module and export information to the munged forms - %% Information about module_info must be removed as this function - %% is added at compilation - {ok, {Module, [{exports,Exports1}]}} = beam_lib:chunks(Beam, [exports]), - Exports2 = lists:filter(fun(Export) -> - case Export of - {module_info,_} -> false; - _ -> true - end - end, - Exports1), - Forms = [{attribute,1,module,Module}, - {attribute,2,export,Exports2}]++ MungedForms, - {Forms,Vars}; -transform(Vsn=raw_abstract_v1, Code, Module, _Beam) -> +transform(Code, Module) -> MainFile=find_main_filename(Code), - Vars0 = #vars{module=Module, vsn=Vsn}, + Vars0 = #vars{module=Module}, {ok,MungedForms,Vars} = transform_2(Code,[],Vars0,MainFile,on), {MungedForms,Vars}. @@ -1486,7 +1445,7 @@ transform_2([Form0|Forms],MungedForms,Vars,MainFile,Switch) -> transform_2(Forms,[MungedForm|MungedForms],Vars2,MainFile,NewSwitch) end; transform_2([],MungedForms,Vars,_,_) -> - {ok, reverse(MungedForms), Vars}. + {ok, lists:reverse(MungedForms), Vars}. %% Expand short-circuit Boolean expressions. expand(Expr) -> @@ -1553,14 +1512,9 @@ aux_var(Vars, N) -> end. %% This code traverses the abstract code, stored as the abstract_code -%% chunk in the BEAM file, as described in absform(3) for Erlang/OTP R8B -%% (Vsn=abstract_v2). -%% The abstract format after preprocessing differs slightly from the abstract -%% format given eg using epp:parse_form, this has been noted in comments. -%% The switch is turned off when we encounter other files then the main file. +%% chunk in the BEAM file, as described in absform(3). +%% The switch is turned off when we encounter other files than the main file. %% This way we will be able to exclude functions defined in include files. -munge({function,0,module_info,_Arity,_Clauses},_Vars,_MainFile,_Switch) -> - ignore; % module_info will be added again when the forms are recompiled munge({function,Line,Function,Arity,Clauses},Vars,_MainFile,on) -> Vars2 = Vars#vars{function=Function, arity=Arity, @@ -1618,7 +1572,7 @@ munge_clauses([Clause|Clauses], Vars, Lines, MClauses) -> MClauses]) end; munge_clauses([], Vars, Lines, MungedClauses) -> - {reverse(MungedClauses), Vars#vars{lines = Lines}}. + {lists:reverse(MungedClauses), Vars#vars{lines = Lines}}. munge_body(Expr, Vars) -> munge_body(Expr, Vars, [], []). @@ -1662,7 +1616,7 @@ munge_body([Expr|Body], Vars, MungedBody, LastExprBumpLines) -> munge_body(Body, Vars3, MungedExprs1, NewBumps) end; munge_body([], Vars, MungedBody, _LastExprBumpLines) -> - {reverse(MungedBody), Vars}. + {lists:reverse(MungedBody), Vars}. %%% Fix last expression (OTP-8188). A typical example: %%% @@ -1801,16 +1755,13 @@ munge_expr({tuple,Line,Exprs}, Vars) -> {MungedExprs, Vars2} = munge_exprs(Exprs, Vars, []), {{tuple,Line,MungedExprs}, Vars2}; munge_expr({record,Line,Name,Exprs}, Vars) -> - %% Only for Vsn=raw_abstract_v1 {MungedExprFields, Vars2} = munge_exprs(Exprs, Vars, []), {{record,Line,Name,MungedExprFields}, Vars2}; munge_expr({record,Line,Arg,Name,Exprs}, Vars) -> - %% Only for Vsn=raw_abstract_v1 {MungedArg, Vars2} = munge_expr(Arg, Vars), {MungedExprFields, Vars3} = munge_exprs(Exprs, Vars2, []), {{record,Line,MungedArg,Name,MungedExprFields}, Vars3}; munge_expr({record_field,Line,ExprL,ExprR}, Vars) -> - %% Only for Vsn=raw_abstract_v1 {MungedExprR, Vars2} = munge_expr(ExprR, Vars), {{record_field,Line,ExprL,MungedExprR}, Vars2}; munge_expr({cons,Line,ExprH,ExprT}, Vars) -> @@ -1874,23 +1825,10 @@ munge_expr({'try',Line,Body,Clauses,CatchClauses,After}, Vars) -> {MungedAfter, Vars4} = munge_body(After, Vars3), {{'try',Line,MungedBody,MungedClauses,MungedCatchClauses,MungedAfter}, Vars4}; -%% Difference in abstract format after preprocessing: Funs get an extra -%% element Extra. -%% NOT NECESSARY FOR Vsn=raw_abstract_v1 -munge_expr({'fun',Line,{function,Name,Arity},_Extra}, Vars) -> - {{'fun',Line,{function,Name,Arity}}, Vars}; -munge_expr({'fun',Line,{clauses,Clauses},_Extra}, Vars) -> - {MungedClauses,Vars2}=munge_clauses(Clauses, Vars), - {{'fun',Line,{clauses,MungedClauses}}, Vars2}; munge_expr({'fun',Line,{clauses,Clauses}}, Vars) -> - %% Only for Vsn=raw_abstract_v1 {MungedClauses,Vars2}=munge_clauses(Clauses, Vars), {{'fun',Line,{clauses,MungedClauses}}, Vars2}; -munge_expr({named_fun,Line,Name,Clauses,_Extra}, Vars) -> - {MungedClauses,Vars2}=munge_clauses(Clauses, Vars), - {{named_fun,Line,Name,MungedClauses}, Vars2}; munge_expr({named_fun,Line,Name,Clauses}, Vars) -> - %% Only for Vsn=raw_abstract_v1 {MungedClauses,Vars2}=munge_clauses(Clauses, Vars), {{named_fun,Line,Name,MungedClauses}, Vars2}; munge_expr({bin,Line,BinElements}, Vars) -> @@ -1911,7 +1849,7 @@ munge_exprs([Expr|Exprs], Vars, MungedExprs) -> {MungedExpr, Vars2} = munge_expr(Expr, Vars), munge_exprs(Exprs, Vars2, [MungedExpr|MungedExprs]); munge_exprs([], Vars, MungedExprs) -> - {reverse(MungedExprs), Vars}. + {lists:reverse(MungedExprs), Vars}. %% Every qualifier is decorated with a counter. munge_qualifiers(Qualifiers, Vars) -> @@ -1930,7 +1868,7 @@ munge_qs([Expr|Qs], Vars, MQs) -> {MungedExpr, Vars2} = munge_expr(Expr, Vars), munge_qs1(Qs, L, MungedExpr, Vars, Vars2, MQs); munge_qs([], Vars, MQs) -> - {reverse(MQs), Vars}. + {lists:reverse(MQs), Vars}. munge_qs1(Qs, Line, NQ, Vars, Vars2, MQs) -> case new_bumps(Vars2, Vars) of @@ -2123,7 +2061,7 @@ merge_clauses([{{M,F,A,_C1},R1},{{M,F,A,C2},R2}|Clauses], MFun, Result) -> merge_clauses([{{M,F,A,_C},R}|Clauses], MFun, Result) -> merge_clauses(Clauses, MFun, [{{M,F,A},R}|Result]); merge_clauses([], _Fun, Result) -> - reverse(Result). + lists:reverse(Result). merge_functions([{_MFA,R}|Functions], MFun) -> merge_functions(Functions, MFun, R); @@ -2444,14 +2382,6 @@ not_loaded(_Module,_Else, State) -> %%%--Div----------------------------------------------------------------- -reverse(List) -> - reverse(List,[]). -reverse([H|T],Acc) -> - reverse(T,[H|Acc]); -reverse([],Acc) -> - Acc. - - escape_lt_and_gt(Rawline,HTML) when HTML =/= true -> Rawline; escape_lt_and_gt(Rawline,_HTML) -> diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl index bd71218474..ec61c57cec 100644 --- a/lib/tools/test/cover_SUITE.erl +++ b/lib/tools/test/cover_SUITE.erl @@ -22,7 +22,8 @@ suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]). --export([start/1, compile/1, analyse/1, misc/1, stop/1, +-export([coverage/1, coverage_analysis/1, + start/1, compile/1, analyse/1, misc/1, stop/1, distribution/1, reconnect/1, die_and_reconnect/1, dont_reconnect_after_stop/1, stop_node_after_disconnect/1, export_import/1, @@ -30,6 +31,8 @@ otp_8188/1, otp_8270/1, otp_8273/1, otp_8340/1, otp_10979_hanging_node/1, compile_beam_opts/1, eep37/1]). +-export([do_coverage/1]). + -include_lib("test_server/include/test_server.hrl"). %%---------------------------------------------------------------------- @@ -46,25 +49,25 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> + NoStartStop = [eif,otp_5305,otp_5418,otp_7095,otp_8273, + otp_8340,otp_8188,compile_beam_opts,eep37], + StartStop = [start, compile, analyse, misc, stop, + distribution, reconnect, die_and_reconnect, + dont_reconnect_after_stop, stop_node_after_disconnect, + export_import, otp_5031, otp_6115, + otp_8270, otp_10979_hanging_node], case whereis(cover_server) of undefined -> - [start, compile, analyse, misc, stop, - distribution, reconnect, die_and_reconnect, - dont_reconnect_after_stop, stop_node_after_disconnect, - export_import, otp_5031, eif, otp_5305, otp_5418, - otp_6115, otp_7095, otp_8188, otp_8270, otp_8273, - otp_8340, otp_10979_hanging_node, compile_beam_opts, eep37]; + [coverage,StartStop ++ NoStartStop]; _pid -> - {skip, - "It looks like the test server is running " - "cover. Can't run cover test."} + [coverage|NoStartStop++[coverage_analysis]] end. groups() -> []. init_per_suite(Config) -> - Config. + [{ct_is_running_cover,whereis(cover_server) =/= undefined}|Config]. end_per_suite(_Config) -> ok. @@ -90,13 +93,64 @@ init_per_testcase(TC, Config) when TC =:= misc; init_per_testcase(_TestCase, Config) -> Config. -end_per_testcase(TestCase, _Config) -> - case lists:member(TestCase,[start,compile,analyse,misc]) of +end_per_testcase(TestCase, Config) -> + NoStop = [start,compile,analyse,misc], + DontStop = proplists:get_bool(ct_is_running_cover, Config) orelse + lists:member(TestCase, NoStop), + case DontStop of true -> ok; false -> cover:stop() end, ok. +coverage(Config) when is_list(Config) -> + {ok,?MODULE} = cover:compile_beam(?MODULE), + ?MODULE:do_coverage(Config). + +do_coverage(Config) -> + Outdir = ?config(priv_dir, Config), + ExportFile = filename:join(Outdir, "export"), + ok = cover:export(ExportFile, ?MODULE), + {error,{already_started,_}} = cover:start(), + {error,_} = cover:compile_beam(non_existing_module), + _ = cover:which_nodes(), + _ = cover:modules(), + _ = cover:imported(), + {error,{not_cover_compiled,lists}} = cover:analyze(lists), + + %% Cover escaping of '&' in HTML files. + + case proplists:get_bool(ct_is_running_cover, Config) of + false -> + %% Cover server was implicitly started when this module + %% was cover-compiled. We must stop the cover server, but + %% we must ensure that this module is not on the call + %% stack when it is unloaded. Therefore, the call that + %% follows MUST be tail-recursive. + cover:stop(); + true -> + %% Cover server was started by common_test; don't stop it. + ok + end. + +%% This test case will only be run when common_test is running cover. +coverage_analysis(Config) when is_list(Config) -> + {ok,Analysis1} = cover:analyze(?MODULE), + io:format("~p\n", [Analysis1]), + {ok,Analysis2} = cover:analyze(?MODULE, calls), + io:format("~p\n", [Analysis2]), + {ok,_Analysis3} = cover:analyze(?MODULE, calls, line), + + Outdir = ?config(priv_dir, Config), + Outfile = filename:join(Outdir, ?MODULE), + + {ok,Outfile} = cover:analyze_to_file(?MODULE, Outfile), + {ok,Contents} = file:read_file(Outfile), + ok = file:delete(Outfile), + ok = io:put_chars(Contents), + {ok,Outfile} = cover:analyze_to_file(?MODULE, Outfile, [html]), + ok. + start(suite) -> []; start(Config) when is_list(Config) -> ?line ok = file:set_cwd(?config(data_dir, Config)), @@ -759,7 +813,6 @@ eif(Config) when is_list(Config) -> %% in cover_inc.beam - not the ones from the included file. ?line cover_inc:func(), ?line {ok, [_, _]} = cover:analyse(cover_inc, line), - ?line cover:stop(), ok. otp_5305(suite) -> []; @@ -775,7 +828,6 @@ otp_5305(Config) when is_list(Config) -> ">>, ?line ok = file:write_file(File, Test), ?line {ok, t} = cover:compile(File), - ?line cover:stop(), ?line ok = file:delete(File), ok. @@ -790,7 +842,6 @@ otp_5418(Config) when is_list(Config) -> ?line ok = file:write_file(File, Test), ?line {ok, t} = cover:compile(File), ?line {ok,{t,{0,0}}} = cover:analyse(t, module), - ?line cover:stop(), ?line ok = file:delete(File), ok. @@ -952,7 +1003,6 @@ otp_7095(Config) when is_list(Config) -> {{t,67},1},{{t,69},1},{{t,71},1},{{t,74},1}, {{t,76},0},{{t,78},1}, {{t,82},2}]} = cover:analyse(t, calls, line), - ?line cover:stop(), ?line ok = file:delete(File), ok. @@ -1028,7 +1078,6 @@ otp_8273(Config) when is_list(Config) -> ">>, ?line File = cc_mod(t, Test, Config), ?line ok = t:t(), - ?line cover:stop(), ?line ok = file:delete(File), ok. @@ -1066,7 +1115,6 @@ otp_8188(Config) when is_list(Config) -> ?line File = cc_mod(t, Test, Config), ?line false = t:test(nok), ?line {ok,[{{t,11},1},{{t,12},1}]} = cover:analyse(t, calls, line), - ?line cover:stop(), ?line ok = file:delete(File), %% Bit string comprehensions are now traversed; @@ -1433,6 +1481,8 @@ compile_beam_opts(Config) when is_list(Config) -> export_all, debug_info, return_errors]), + code:purge(t), + code:delete(t), Exports = [{func1,0}, {macro, 0}, @@ -1443,7 +1493,6 @@ compile_beam_opts(Config) when is_list(Config) -> Exports = t:module_info(exports), {ok, t} = cover:compile_beam("t"), Exports = t:module_info(exports), - cover:stop(), ok = file:delete("t.beam"), ok = file:set_cwd(Cwd), ok. diff --git a/lib/wx/api_gen/Makefile b/lib/wx/api_gen/Makefile index 8adb485ba9..3e41ac7bc5 100644 --- a/lib/wx/api_gen/Makefile +++ b/lib/wx/api_gen/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2012. All Rights Reserved. +# Copyright Ericsson AB 2008-2014. 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 @@ $(GL): glxml_generated $(GL_COMP_T) glapi.conf erl -noshell -run gl_gen code && touch gl_code_generated %.beam: %.erl wx_gen.hrl gl_gen.hrl - $(ERLC) -W $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) $< -o$(EBIN) + $(ERLC) -W $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $< # TODO split cleans into separate targets? complete_clean: diff --git a/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src b/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src index 9c5f46b253..5d20019d8f 100644 --- a/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src +++ b/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src @@ -1,17 +1,5 @@ -case 98: { // wxeEvtListener::wxeEvtListener - wxeEvtListener *Result = new wxeEvtListener(Ecmd.port); - rt.addRef(getRef((void *)Result,memenv), "wxeEvtListener"); - break; -} -case 99: { // wxeEvtListener::destroy - wxObject *This = (wxObject *) getPtr(bp,memenv); - rt.addAtom("ok"); - delete This; - break; -} -case 100: { // wxEvtHandler::Connect - wxeEvtListener *Listener = (wxeEvtListener *) getPtr(bp,memenv); bp += 4; +case 100: { // wxEvtHandler::Connect wxEvtHandler *This = (wxEvtHandler *) getPtr(bp, memenv); bp += 4; int * winid = (int *) bp; bp += 4; int * lastId = (int *) bp; bp += 4; @@ -22,20 +10,22 @@ case 100: { // wxEvtHandler::Connect int * eventTypeLen = (int *) bp; bp += 4; int * class_nameLen = (int *) bp; bp += 4; - if(*haveUserData) { + if(*haveUserData) { userData = new wxeErlTerm(Ecmd.bin[0]); } int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen; char *class_name = bp; bp+= *class_nameLen; if(eventType > 0 ) { - wxeCallbackData * Evt_cb = new wxeCallbackData(Ecmd.caller,getRef(This, memenv), - class_name,*fun_cb, - *skip, userData, Listener); + wxeEvtListener * Evt_cb = new wxeEvtListener(Ecmd.caller,getRef(This, memenv), + class_name,*fun_cb, + *skip, userData, Ecmd.port); This->Connect((int) *winid,(int) *lastId,eventType, (wxObjectEventFunction)(wxEventFunction) &wxeEvtListener::forward, - Evt_cb, Listener); + Evt_cb, Evt_cb); rt.addAtom("ok"); + rt.addRef(getRef((void *)Evt_cb,memenv), "wxeEvtListener"); + rt.addTupleCount(2); } else { rt.addAtom("badarg"); rt.addAtom("event_type"); @@ -43,7 +33,7 @@ case 100: { // wxEvtHandler::Connect } break; } -case 101: { // wxEvtHandler::Disconnect +case 101: { // wxEvtHandler::Disconnect wxeEvtListener *Listener = (wxeEvtListener *) getPtr(bp,memenv); bp += 4; wxEvtHandler *This = (wxEvtHandler *) getPtr(bp, memenv); bp += 4; int * winid = (int *) bp; bp += 4; @@ -53,14 +43,14 @@ case 101: { // wxEvtHandler::Disconnect int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen; if(eventType > 0) { bool Result = This->Disconnect((int) *winid,(int) *lastId,eventType, - (wxObjectEventFunction)(wxEventFunction) - &wxeEvtListener::forward, - NULL, Listener); + (wxObjectEventFunction)(wxEventFunction) + &wxeEvtListener::forward, + NULL, Listener); rt.addBool(Result); } else { rt.addAtom("badarg"); rt.addAtom("event_type"); - rt.addTupleCount(2); + rt.addTupleCount(2); } break; } diff --git a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl index c5802af679..c9726fd475 100644 --- a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl +++ b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl @@ -27,15 +27,11 @@ -export([connect/2, connect/3, disconnect/1, disconnect/2, disconnect/3]). %% internal exports --export([connect_impl/3, disconnect_impl/2, disconnect_impl/3, - new_evt_listener/0, destroy_evt_listener/1, - get_callback/1, replace_fun_with_id/2]). +-export([connect_impl/2, disconnect_impl/2]). -export_type([wxEvtHandler/0, wx/0, event/0]). -type wxEvtHandler() :: wx:wx_object(). --record(evh, {et=null,id=?wxID_ANY,lastId=?wxID_ANY,skip=undefined,userdata=[],cb=0}). - %% @doc Equivalent to {@link connect/3. connect(This, EventType, [])} -spec connect(This::wxEvtHandler(), EventType::wxEventType()) -> ok. connect(This, EventType) -> @@ -130,54 +126,34 @@ disconnect(This=#wx_ref{type=ThisT,ref=_ThisRef}, EventType, Opts) -> %% @hidden -connect_impl(#wx_ref{type=wxeEvtListener,ref=EvtList}, - #wx_ref{type=ThisT,ref=ThisRef}, - #evh{id=Winid, lastId=LastId, et=EventType, - skip=Skip, userdata=Userdata, cb=FunID}) +connect_impl(#wx_ref{type=ThisT,ref=ThisRef}, + #evh{id=Winid, lastId=LastId, et=EventType, + skip=Skip, userdata=Userdata, cb=FunID}) when is_integer(FunID)-> EventTypeBin = list_to_binary([atom_to_list(EventType)|[0]]), ThisTypeBin = list_to_binary([atom_to_list(ThisT)|[0]]), UD = if Userdata =:= [] -> 0; - true -> + true -> wxe_util:send_bin(term_to_binary(Userdata)), 1 end, - wxe_util:call(100, <<EvtList:32/?UI,ThisRef:32/?UI, + wxe_util:call(100, <<ThisRef:32/?UI, Winid:32/?UI,LastId:32/?UI, (wxe_util:from_bool(Skip)):32/?UI, UD:32/?UI, FunID:32/?UI, (size(EventTypeBin)):32/?UI, - (size(ThisTypeBin)):32/?UI, + (size(ThisTypeBin)):32/?UI, %% Note no alignment EventTypeBin/binary,ThisTypeBin/binary>>). %% @hidden -disconnect_impl(Listener, Object) -> - disconnect_impl(Listener, Object, #evh{}). -%% @hidden -disconnect_impl(#wx_ref{type=wxeEvtListener,ref=EvtList}, - #wx_ref{type=_ThisT,ref=ThisRef}, - #evh{id=Winid, lastId=LastId, et=EventType}) -> +disconnect_impl(#wx_ref{type=_ThisT,ref=ThisRef}, + #evh{id=Winid, lastId=LastId, et=EventType, + handler=#wx_ref{type=wxeEvtListener,ref=EvtList}}) -> EventTypeBin = list_to_binary([atom_to_list(EventType)|[0]]), - wxe_util:call(101, <<EvtList:32/?UI, + wxe_util:call(101, <<EvtList:32/?UI, ThisRef:32/?UI,Winid:32/?UI,LastId:32/?UI, (size(EventTypeBin)):32/?UI, %% Note no alignment EventTypeBin/binary>>). - -%% @hidden -new_evt_listener() -> - wxe_util:call(98, <<>>). - -%% @hidden -destroy_evt_listener(#wx_ref{type=wxeEvtListener,ref=EvtList}) -> - wxe_util:call(99, <<EvtList:32/?UI>>). - -%% @hidden -get_callback(#evh{cb=Callback}) -> - Callback. - -%% @hidden -replace_fun_with_id(Evh, Id) -> - Evh#evh{cb=Id}. diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl index 5ac57e4929..ea5d89be72 100644 --- a/lib/wx/api_gen/wx_gen_cpp.erl +++ b/lib/wx/api_gen/wx_gen_cpp.erl @@ -1190,15 +1190,6 @@ find_id(OtherClass) -> encode_events(Evs) -> ?WTC("encode_events"), - w("void wxeEvtListener::forward(wxEvent& event)~n" - "{~n" - "#ifdef DEBUG~n" - " if(!sendevent(&event, port))~n" - " fprintf(stderr, \"Couldn't send event!\\r\\n\");~n" - "#else~n" - "sendevent(&event, port);~n" - "#endif~n" - "}~n~n"), w("int getRef(void* ptr, wxeMemEnv* memenv)~n" "{~n" " WxeApp * app = (WxeApp *) wxTheApp;~n" @@ -1209,7 +1200,7 @@ encode_events(Evs) -> " char * evClass = NULL;~n" " wxMBConvUTF32 UTFconverter;~n" " wxeEtype *Etype = etmap[event->GetEventType()];~n" - " wxeCallbackData *cb = (wxeCallbackData *)event->m_callbackUserData;~n" + " wxeEvtListener *cb = (wxeEvtListener *)event->m_callbackUserData;~n" " WxeApp * app = (WxeApp *) wxTheApp;~n" " wxeMemEnv *memenv = app->getMemEnv(port);~n" " if(!memenv) return 0;~n~n" diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl index c87187edc5..a4b03d3fd1 100644 --- a/lib/wx/api_gen/wx_gen_erl.erl +++ b/lib/wx/api_gen/wx_gen_erl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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 @@ -137,15 +137,27 @@ gen_class1(C=#class{name=Name,parent=Parent,methods=Ms,options=Opts}) -> w("%% inherited exports~n",[]), Done0 = ["Destroy", "New", "Create", "destroy", "new", "create"], Done = gb_sets:from_list(Done0 ++ [M|| #method{name=M} <- lists:append(Ms)]), - {_, InExported} = gen_inherited(Parents, Done, []), - w("-export([~s]).~n~n", [args(fun(EF) -> EF end, ",", - lists:usort(["parent_class/1"|InExported]), + {_, InExported0} = gen_inherited(Parents, Done, []), + InExported = lists:ukeysort(2, [{?MODULE,{"parent_class","1"},false}|InExported0]), + w("-export([~s]).~n~n", [args(fun({_M,{F,A},_Dep}) -> F ++ "/" ++ A end, ",", + InExported, 60)]), w("-export_type([~s/0]).~n", [Name]), case lists:filter(fun({_F,Depr}) -> Depr end, ExportList) of [] -> ok; Depr -> w("-deprecated([~s]).~n~n", [args(fun({EF,_}) -> EF end, ",", Depr, 60)]) end, + case lists:filter(fun({_,_,Depr}) -> Depr end, InExported) of + [] -> ok; + NoWDepr -> w("-compile([~s]).~n~n", + [args(fun({M,{F,A},_}) -> + DStr=io_lib:format("{nowarn_deprecated_function, {~s,~s,~s}}", + [M,F,A]), + lists:flatten(DStr) + end, ",", NoWDepr, 60)]) + end, + + w("%% @hidden~n", []), parents_check(Parents), w("-type ~s() :: wx:wx_object().~n", [Name]), @@ -375,7 +387,7 @@ gen_inherited([Parent|Ps], Done0, Exported0) -> {Done,Exported} = gen_inherited_ms(Ms, Class, Done0, gb_sets:empty(), Exported0), gen_inherited(Ps, gb_sets:union(Done,Done0), Exported). -gen_inherited_ms([[#method{name=Name,alias=A,params=Ps0,where=W,method_type=MT}|_]|R], +gen_inherited_ms([[M=#method{name=Name,alias=A,params=Ps0,where=W,method_type=MT}|_]|R], Class,Skip,Done, Exported) when W =/= merged_c -> case gb_sets:is_member(Name,Skip) of @@ -399,8 +411,10 @@ gen_inherited_ms([[#method{name=Name,alias=A,params=Ps0,where=W,method_type=MT}| _ when W =:= erl_no_opt -> 0; _ -> 1 end, - Export = erl_func_name(Name,A) ++ "/" ++ integer_to_list(length(Args) + OptLen), - gen_inherited_ms(R,Class,Skip, gb_sets:add(Name,Done), [Export|Exported]); + {_, Depr} = deprecated(M,ignore), + Export = {Class,{erl_func_name(Name,A),integer_to_list(length(Args) + OptLen)}, Depr}, + gen_inherited_ms(R,Class,Skip, gb_sets:add(Name,Done), + [Export|Exported]); _ -> gen_inherited_ms(R,Class, Skip, Done, Exported) end; diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp index a1b4d090b3..1bd17366a2 100644 --- a/lib/wx/c_src/gen/wxe_events.cpp +++ b/lib/wx/c_src/gen/wxe_events.cpp @@ -316,16 +316,6 @@ void initEventTable() } } -void wxeEvtListener::forward(wxEvent& event) -{ -#ifdef DEBUG - if(!sendevent(&event, port)) - fprintf(stderr, "Couldn't send event!\r\n"); -#else -sendevent(&event, port); -#endif -} - int getRef(void* ptr, wxeMemEnv* memenv) { WxeApp * app = (WxeApp *) wxTheApp; @@ -338,7 +328,7 @@ bool sendevent(wxEvent *event, ErlDrvTermData port) char * evClass = NULL; wxMBConvUTF32 UTFconverter; wxeEtype *Etype = etmap[event->GetEventType()]; - wxeCallbackData *cb = (wxeCallbackData *)event->m_callbackUserData; + wxeEvtListener *cb = (wxeEvtListener *)event->m_callbackUserData; WxeApp * app = (WxeApp *) wxTheApp; wxeMemEnv *memenv = app->getMemEnv(port); if(!memenv) return 0; diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp index 82dd414911..3f5cb4c0f5 100644 --- a/lib/wx/c_src/gen/wxe_funcs.cpp +++ b/lib/wx/c_src/gen/wxe_funcs.cpp @@ -67,20 +67,8 @@ void WxeApp::wxe_dispatch(wxeCommand& Ecmd) case WXE_INIT_OPENGL: wxe_initOpenGL(rt, bp); break; -case 98: { // wxeEvtListener::wxeEvtListener - wxeEvtListener *Result = new wxeEvtListener(Ecmd.port); - rt.addRef(getRef((void *)Result,memenv), "wxeEvtListener"); - break; -} -case 99: { // wxeEvtListener::destroy - wxObject *This = (wxObject *) getPtr(bp,memenv); - rt.addAtom("ok"); - delete This; - break; -} -case 100: { // wxEvtHandler::Connect - wxeEvtListener *Listener = (wxeEvtListener *) getPtr(bp,memenv); bp += 4; +case 100: { // wxEvtHandler::Connect wxEvtHandler *This = (wxEvtHandler *) getPtr(bp, memenv); bp += 4; int * winid = (int *) bp; bp += 4; int * lastId = (int *) bp; bp += 4; @@ -91,20 +79,22 @@ case 100: { // wxEvtHandler::Connect int * eventTypeLen = (int *) bp; bp += 4; int * class_nameLen = (int *) bp; bp += 4; - if(*haveUserData) { + if(*haveUserData) { userData = new wxeErlTerm(Ecmd.bin[0]); } int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen; char *class_name = bp; bp+= *class_nameLen; if(eventType > 0 ) { - wxeCallbackData * Evt_cb = new wxeCallbackData(Ecmd.caller,getRef(This, memenv), - class_name,*fun_cb, - *skip, userData, Listener); + wxeEvtListener * Evt_cb = new wxeEvtListener(Ecmd.caller,getRef(This, memenv), + class_name,*fun_cb, + *skip, userData, Ecmd.port); This->Connect((int) *winid,(int) *lastId,eventType, (wxObjectEventFunction)(wxEventFunction) &wxeEvtListener::forward, - Evt_cb, Listener); + Evt_cb, Evt_cb); rt.addAtom("ok"); + rt.addRef(getRef((void *)Evt_cb,memenv), "wxeEvtListener"); + rt.addTupleCount(2); } else { rt.addAtom("badarg"); rt.addAtom("event_type"); @@ -112,7 +102,7 @@ case 100: { // wxEvtHandler::Connect } break; } -case 101: { // wxEvtHandler::Disconnect +case 101: { // wxEvtHandler::Disconnect wxeEvtListener *Listener = (wxeEvtListener *) getPtr(bp,memenv); bp += 4; wxEvtHandler *This = (wxEvtHandler *) getPtr(bp, memenv); bp += 4; int * winid = (int *) bp; bp += 4; @@ -122,14 +112,14 @@ case 101: { // wxEvtHandler::Disconnect int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen; if(eventType > 0) { bool Result = This->Disconnect((int) *winid,(int) *lastId,eventType, - (wxObjectEventFunction)(wxEventFunction) - &wxeEvtListener::forward, - NULL, Listener); + (wxObjectEventFunction)(wxEventFunction) + &wxeEvtListener::forward, + NULL, Listener); rt.addBool(Result); } else { rt.addAtom("badarg"); rt.addAtom("event_type"); - rt.addTupleCount(2); + rt.addTupleCount(2); } break; } diff --git a/lib/wx/c_src/wxe_callback_impl.cpp b/lib/wx/c_src/wxe_callback_impl.cpp index 8ba2557d82..e06f68dcbf 100644 --- a/lib/wx/c_src/wxe_callback_impl.cpp +++ b/lib/wx/c_src/wxe_callback_impl.cpp @@ -30,27 +30,27 @@ * CallbackData * * ****************************************************************************/ -wxeCallbackData::wxeCallbackData(ErlDrvTermData caller, int req, char *req_type, - int funcb, int skip_ev, wxeErlTerm * userData, - wxeEvtListener *handler_cb) - : wxObject() +wxeEvtListener::wxeEvtListener(ErlDrvTermData caller, int req, char *req_type, + int funcb, int skip_ev, wxeErlTerm * userData, + ErlDrvTermData from_port) + : wxEvtHandler() { + port=from_port; listener = caller; obj = req; fun_id = funcb; strcpy(class_name, req_type); skip = skip_ev; user_data = userData; - handler = handler_cb; } -wxeCallbackData::~wxeCallbackData() { - // fprintf(stderr, "CBD Deleteing %p %s\r\n", this, class_name); fflush(stderr); +wxeEvtListener::~wxeEvtListener() { + // fprintf(stderr, "CBD Deleteing %p %s\r\n", this, class_name); fflush(stderr); if(user_data) { delete user_data; } ptrMap::iterator it; - it = ((WxeApp *)wxTheApp)->ptr2ref.find(handler); + it = ((WxeApp *)wxTheApp)->ptr2ref.find(this); if(it != ((WxeApp *)wxTheApp)->ptr2ref.end()) { wxeRefData *refd = it->second; wxeReturn rt = wxeReturn(WXE_DRV_PORT, refd->memenv->owner, false); @@ -61,6 +61,17 @@ wxeCallbackData::~wxeCallbackData() { rt.addTupleCount(4); rt.send(); } + ((WxeApp *)wxTheApp)->clearPtr(this); +} + +void wxeEvtListener::forward(wxEvent& event) +{ +#ifdef DEBUG + if(!sendevent(&event, port)) + fprintf(stderr, "Couldn't send event!\r\n"); +#else +sendevent(&event, port); +#endif } /* *****************************************************************/ diff --git a/lib/wx/c_src/wxe_callback_impl.h b/lib/wx/c_src/wxe_callback_impl.h index c7243e23a4..1c355e4d38 100644 --- a/lib/wx/c_src/wxe_callback_impl.h +++ b/lib/wx/c_src/wxe_callback_impl.h @@ -23,6 +23,24 @@ void pre_callback(); void handle_event_callback(ErlDrvPort port, ErlDrvTermData process); +/* Fun Callback id */ +class wxeEvtListener : public wxEvtHandler +{ +public: + wxeEvtListener(ErlDrvTermData caller, int req, char *req_type, + int funcb, int skip_ev, wxeErlTerm * userData, + ErlDrvTermData Thisport); + ~wxeEvtListener(); + void forward(wxEvent& event); + ErlDrvTermData port; + ErlDrvTermData listener; + int fun_id; + int obj; + char class_name[40]; + int skip; + wxeErlTerm * user_data; +}; + class wxEPrintout : public wxPrintout { public: diff --git a/lib/wx/c_src/wxe_events.h b/lib/wx/c_src/wxe_events.h index 22a737d854..93b5551123 100644 --- a/lib/wx/c_src/wxe_events.h +++ b/lib/wx/c_src/wxe_events.h @@ -32,38 +32,7 @@ public: int cID; }; -/* One EvtListener per listening erlang process */ -/* If callbacks are used the receiver is wxe_master process */ -/* and a wxeEvtListener pre callback is registered */ -class wxeEvtListener : public wxEvtHandler -{ - public: - wxeEvtListener(ErlDrvTermData Thisport) : port(Thisport) - {} - // {fprintf(stderr, "Creating %x\r\n", (unsigned int) this); fflush(stderr);} - ~wxeEvtListener() {} - void forward(wxEvent& event); - ErlDrvTermData port; -}; - void initEventTable(); int wxeEventTypeFromAtom(char *etype_atom); -/* Fun Callback id */ -class wxeCallbackData : public wxObject -{ -public: - wxeCallbackData(ErlDrvTermData caller, int req, char *req_type, - int funcb, int skip_ev, wxeErlTerm * userData, - wxeEvtListener *handler_cb); - ~wxeCallbackData(); - wxeEvtListener * handler; - ErlDrvTermData listener; - int fun_id; - int obj; - char class_name[40]; - int skip; - wxeErlTerm * user_data; -}; - #endif diff --git a/lib/wx/src/gen/wxBufferedDC.erl b/lib/wx/src/gen/wxBufferedDC.erl index c69a426d7f..e2504bbaaa 100644 --- a/lib/wx/src/gen/wxBufferedDC.erl +++ b/lib/wx/src/gen/wxBufferedDC.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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,8 @@ setUserScale/3,startDoc/2,startPage/1]). -export_type([wxBufferedDC/0]). +-compile([{nowarn_deprecated_function, {wxDC,computeScaleAndOrigin,1}}]). + %% @hidden parent_class(wxMemoryDC) -> true; parent_class(wxDC) -> true; diff --git a/lib/wx/src/gen/wxBufferedPaintDC.erl b/lib/wx/src/gen/wxBufferedPaintDC.erl index 0e11826da0..c3fa80703c 100644 --- a/lib/wx/src/gen/wxBufferedPaintDC.erl +++ b/lib/wx/src/gen/wxBufferedPaintDC.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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,6 +56,8 @@ startPage/1]). -export_type([wxBufferedPaintDC/0]). +-compile([{nowarn_deprecated_function, {wxDC,computeScaleAndOrigin,1}}]). + %% @hidden parent_class(wxBufferedDC) -> true; parent_class(wxMemoryDC) -> true; diff --git a/lib/wx/src/gen/wxClientDC.erl b/lib/wx/src/gen/wxClientDC.erl index 45909859ce..ae16196774 100644 --- a/lib/wx/src/gen/wxClientDC.erl +++ b/lib/wx/src/gen/wxClientDC.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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,6 +56,8 @@ -export_type([wxClientDC/0]). -deprecated([new/0]). +-compile([{nowarn_deprecated_function, {wxDC,computeScaleAndOrigin,1}}]). + %% @hidden parent_class(wxWindowDC) -> true; parent_class(wxDC) -> true; diff --git a/lib/wx/src/gen/wxEvtHandler.erl b/lib/wx/src/gen/wxEvtHandler.erl index 22c203392c..44b7254cfb 100644 --- a/lib/wx/src/gen/wxEvtHandler.erl +++ b/lib/wx/src/gen/wxEvtHandler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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 @@ -46,15 +46,11 @@ -export([connect/2, connect/3, disconnect/1, disconnect/2, disconnect/3]). %% internal exports --export([connect_impl/3, disconnect_impl/2, disconnect_impl/3, - new_evt_listener/0, destroy_evt_listener/1, - get_callback/1, replace_fun_with_id/2]). +-export([connect_impl/2, disconnect_impl/2]). -export_type([wxEvtHandler/0, wx/0, event/0]). -type wxEvtHandler() :: wx:wx_object(). --record(evh, {et=null,id=?wxID_ANY,lastId=?wxID_ANY,skip=undefined,userdata=[],cb=0}). - %% @doc Equivalent to {@link connect/3. connect(This, EventType, [])} -spec connect(This::wxEvtHandler(), EventType::wxEventType()) -> ok. connect(This, EventType) -> @@ -149,55 +145,35 @@ disconnect(This=#wx_ref{type=ThisT,ref=_ThisRef}, EventType, Opts) -> %% @hidden -connect_impl(#wx_ref{type=wxeEvtListener,ref=EvtList}, - #wx_ref{type=ThisT,ref=ThisRef}, - #evh{id=Winid, lastId=LastId, et=EventType, - skip=Skip, userdata=Userdata, cb=FunID}) +connect_impl(#wx_ref{type=ThisT,ref=ThisRef}, + #evh{id=Winid, lastId=LastId, et=EventType, + skip=Skip, userdata=Userdata, cb=FunID}) when is_integer(FunID)-> EventTypeBin = list_to_binary([atom_to_list(EventType)|[0]]), ThisTypeBin = list_to_binary([atom_to_list(ThisT)|[0]]), UD = if Userdata =:= [] -> 0; - true -> + true -> wxe_util:send_bin(term_to_binary(Userdata)), 1 end, - wxe_util:call(100, <<EvtList:32/?UI,ThisRef:32/?UI, + wxe_util:call(100, <<ThisRef:32/?UI, Winid:32/?UI,LastId:32/?UI, (wxe_util:from_bool(Skip)):32/?UI, UD:32/?UI, FunID:32/?UI, (size(EventTypeBin)):32/?UI, - (size(ThisTypeBin)):32/?UI, + (size(ThisTypeBin)):32/?UI, %% Note no alignment EventTypeBin/binary,ThisTypeBin/binary>>). %% @hidden -disconnect_impl(Listener, Object) -> - disconnect_impl(Listener, Object, #evh{}). -%% @hidden -disconnect_impl(#wx_ref{type=wxeEvtListener,ref=EvtList}, - #wx_ref{type=_ThisT,ref=ThisRef}, - #evh{id=Winid, lastId=LastId, et=EventType}) -> +disconnect_impl(#wx_ref{type=_ThisT,ref=ThisRef}, + #evh{id=Winid, lastId=LastId, et=EventType, + handler=#wx_ref{type=wxeEvtListener,ref=EvtList}}) -> EventTypeBin = list_to_binary([atom_to_list(EventType)|[0]]), - wxe_util:call(101, <<EvtList:32/?UI, + wxe_util:call(101, <<EvtList:32/?UI, ThisRef:32/?UI,Winid:32/?UI,LastId:32/?UI, (size(EventTypeBin)):32/?UI, %% Note no alignment EventTypeBin/binary>>). -%% @hidden -new_evt_listener() -> - wxe_util:call(98, <<>>). - -%% @hidden -destroy_evt_listener(#wx_ref{type=wxeEvtListener,ref=EvtList}) -> - wxe_util:call(99, <<EvtList:32/?UI>>). - -%% @hidden -get_callback(#evh{cb=Callback}) -> - Callback. - -%% @hidden -replace_fun_with_id(Evh, Id) -> - Evh#evh{cb=Id}. - diff --git a/lib/wx/src/gen/wxGridCellBoolEditor.erl b/lib/wx/src/gen/wxGridCellBoolEditor.erl index bf7e21d11d..c4d6d92618 100644 --- a/lib/wx/src/gen/wxGridCellBoolEditor.erl +++ b/lib/wx/src/gen/wxGridCellBoolEditor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2014. 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,8 @@ parent_class/1,reset/1,setSize/2,show/2,show/3,startingClick/1,startingKey/2]). -export_type([wxGridCellBoolEditor/0]). +-compile([{nowarn_deprecated_function, {wxGridCellEditor,endEdit,4}},{nowarn_deprecated_function, {wxGridCellEditor,paintBackground,3}}]). + %% @hidden parent_class(wxGridCellEditor) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). diff --git a/lib/wx/src/gen/wxGridCellChoiceEditor.erl b/lib/wx/src/gen/wxGridCellChoiceEditor.erl index 08c5f9e147..a49680ffda 100644 --- a/lib/wx/src/gen/wxGridCellChoiceEditor.erl +++ b/lib/wx/src/gen/wxGridCellChoiceEditor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2014. 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,8 @@ parent_class/1,reset/1,setSize/2,show/2,show/3,startingClick/1,startingKey/2]). -export_type([wxGridCellChoiceEditor/0]). +-compile([{nowarn_deprecated_function, {wxGridCellEditor,endEdit,4}},{nowarn_deprecated_function, {wxGridCellEditor,paintBackground,3}}]). + %% @hidden parent_class(wxGridCellEditor) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). diff --git a/lib/wx/src/gen/wxGridCellFloatEditor.erl b/lib/wx/src/gen/wxGridCellFloatEditor.erl index 4b6b3b46e1..5cd0bd6cb5 100644 --- a/lib/wx/src/gen/wxGridCellFloatEditor.erl +++ b/lib/wx/src/gen/wxGridCellFloatEditor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2014. 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,8 @@ parent_class/1,reset/1,setSize/2,show/2,show/3,startingClick/1,startingKey/2]). -export_type([wxGridCellFloatEditor/0]). +-compile([{nowarn_deprecated_function, {wxGridCellEditor,endEdit,4}},{nowarn_deprecated_function, {wxGridCellEditor,paintBackground,3}}]). + %% @hidden parent_class(wxGridCellEditor) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). diff --git a/lib/wx/src/gen/wxGridCellNumberEditor.erl b/lib/wx/src/gen/wxGridCellNumberEditor.erl index 04214be6b8..7cc682a10e 100644 --- a/lib/wx/src/gen/wxGridCellNumberEditor.erl +++ b/lib/wx/src/gen/wxGridCellNumberEditor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2014. 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,6 +35,8 @@ parent_class/1,reset/1,setSize/2,show/2,show/3,startingClick/1,startingKey/2]). -export_type([wxGridCellNumberEditor/0]). +-compile([{nowarn_deprecated_function, {wxGridCellEditor,endEdit,4}},{nowarn_deprecated_function, {wxGridCellEditor,paintBackground,3}}]). + %% @hidden parent_class(wxGridCellTextEditor) -> true; parent_class(wxGridCellEditor) -> true; diff --git a/lib/wx/src/gen/wxGridCellTextEditor.erl b/lib/wx/src/gen/wxGridCellTextEditor.erl index 5755be8638..a024da56c4 100644 --- a/lib/wx/src/gen/wxGridCellTextEditor.erl +++ b/lib/wx/src/gen/wxGridCellTextEditor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2014. 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,8 @@ parent_class/1,reset/1,setSize/2,show/2,show/3,startingClick/1,startingKey/2]). -export_type([wxGridCellTextEditor/0]). +-compile([{nowarn_deprecated_function, {wxGridCellEditor,endEdit,4}},{nowarn_deprecated_function, {wxGridCellEditor,paintBackground,3}}]). + %% @hidden parent_class(wxGridCellEditor) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). diff --git a/lib/wx/src/gen/wxMemoryDC.erl b/lib/wx/src/gen/wxMemoryDC.erl index c123f0e35d..8de412bdc7 100644 --- a/lib/wx/src/gen/wxMemoryDC.erl +++ b/lib/wx/src/gen/wxMemoryDC.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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,6 +53,8 @@ startPage/1]). -export_type([wxMemoryDC/0]). +-compile([{nowarn_deprecated_function, {wxDC,computeScaleAndOrigin,1}}]). + %% @hidden parent_class(wxDC) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). diff --git a/lib/wx/src/gen/wxMirrorDC.erl b/lib/wx/src/gen/wxMirrorDC.erl index cfae34cb36..9a681bff2e 100644 --- a/lib/wx/src/gen/wxMirrorDC.erl +++ b/lib/wx/src/gen/wxMirrorDC.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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,6 +53,8 @@ startPage/1]). -export_type([wxMirrorDC/0]). +-compile([{nowarn_deprecated_function, {wxDC,computeScaleAndOrigin,1}}]). + %% @hidden parent_class(wxDC) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). diff --git a/lib/wx/src/gen/wxPaintDC.erl b/lib/wx/src/gen/wxPaintDC.erl index 3c9b321496..0ff27a8c7a 100644 --- a/lib/wx/src/gen/wxPaintDC.erl +++ b/lib/wx/src/gen/wxPaintDC.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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,6 +56,8 @@ -export_type([wxPaintDC/0]). -deprecated([new/0]). +-compile([{nowarn_deprecated_function, {wxDC,computeScaleAndOrigin,1}}]). + %% @hidden parent_class(wxWindowDC) -> true; parent_class(wxDC) -> true; diff --git a/lib/wx/src/gen/wxPostScriptDC.erl b/lib/wx/src/gen/wxPostScriptDC.erl index e0b22c87eb..e7e498efa1 100644 --- a/lib/wx/src/gen/wxPostScriptDC.erl +++ b/lib/wx/src/gen/wxPostScriptDC.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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 @@ -55,6 +55,8 @@ -export_type([wxPostScriptDC/0]). -deprecated([getResolution/0,setResolution/1]). +-compile([{nowarn_deprecated_function, {wxDC,computeScaleAndOrigin,1}}]). + %% @hidden parent_class(wxDC) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). diff --git a/lib/wx/src/gen/wxScreenDC.erl b/lib/wx/src/gen/wxScreenDC.erl index 54bdc2d351..21ca4bacfc 100644 --- a/lib/wx/src/gen/wxScreenDC.erl +++ b/lib/wx/src/gen/wxScreenDC.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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,6 +53,8 @@ startPage/1]). -export_type([wxScreenDC/0]). +-compile([{nowarn_deprecated_function, {wxDC,computeScaleAndOrigin,1}}]). + %% @hidden parent_class(wxDC) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). diff --git a/lib/wx/src/gen/wxWindowDC.erl b/lib/wx/src/gen/wxWindowDC.erl index f5c482d8ca..6bb303cfe6 100644 --- a/lib/wx/src/gen/wxWindowDC.erl +++ b/lib/wx/src/gen/wxWindowDC.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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 @@ -55,6 +55,8 @@ -export_type([wxWindowDC/0]). -deprecated([new/0]). +-compile([{nowarn_deprecated_function, {wxDC,computeScaleAndOrigin,1}}]). + %% @hidden parent_class(wxDC) -> true; parent_class(_Class) -> erlang:error({badtype, ?MODULE}). diff --git a/lib/wx/src/wxe.hrl b/lib/wx/src/wxe.hrl index bd34b13385..66ec9ac45e 100644 --- a/lib/wx/src/wxe.hrl +++ b/lib/wx/src/wxe.hrl @@ -29,6 +29,11 @@ -record(wx_mem, {bin, size}). +-record(evh, {et=null,id=-1,lastId=-1,cb=0, + skip=undefined,userdata=[], % temp + handler=undefined % added after connect + }). + -define(CLASS(Type,Class), ((Type) =:= Class) orelse (Type):parent_class(Class)). -define(CLASS_T(Type,Class), diff --git a/lib/wx/src/wxe_server.erl b/lib/wx/src/wxe_server.erl index 04e0d0faf4..aed9dca7ce 100644 --- a/lib/wx/src/wxe_server.erl +++ b/lib/wx/src/wxe_server.erl @@ -36,8 +36,8 @@ terminate/2, code_change/3]). -record(state, {port,cb_port,users,cleaners=[],cb,cb_cnt}). --record(user, {events=[], evt_handler}). --record(event, {object, callback, cb_handler}). +-record(user, {events=[]}). +%%-record(event, {object, callback, cb_handler}). -define(APPLICATION, wxe). -define(log(S,A), log(?MODULE,?LINE,S,A)). @@ -119,7 +119,7 @@ handle_call(stop,{_From,_},State = #state{users=Users0, cleaners=Cs0}) -> Env = get(?WXE_IDENTIFIER), Users = gb_trees:to_list(Users0), Cs = lists:map(fun({_Pid,User}) -> - spawn_link(fun() -> cleanup(Env,[User], false) end) + spawn_link(fun() -> cleanup(Env,[User]) end) end, Users), {noreply, State#state{users=gb_trees:empty(), cleaners=Cs ++ Cs0}}; @@ -178,13 +178,13 @@ handle_info({'DOWN',_,process,Pid,_}, State=#state{users=Users0,cleaners=Cs}) -> Users = gb_trees:delete(Pid,Users0), Env = wx:get_env(), case User of - #user{events=[], evt_handler=undefined} -> %% No need to spawn + #user{events=[]} -> %% No need to spawn case Cs =:= [] andalso gb_trees:is_empty(Users) of - true -> {stop, normal, State#state{cleaners=Cs}}; - false -> {noreply, State#state{users=Users,cleaners=Cs}} + true -> {stop, normal, State#state{users=Users}}; + false -> {noreply, State#state{users=Users}} end; _ -> - Cleaner = spawn_link(fun() -> cleanup(Env,[User],true) end), + Cleaner = spawn_link(fun() -> cleanup(Env,[User]) end), {noreply, State#state{users=Users,cleaners=[Cleaner|Cs]}} end catch _E:_R -> @@ -222,36 +222,26 @@ code_change(_OldVsn, State, _Extra) -> log(Mod,Line,Str,Args) -> error_logger:format("~p:~p: " ++ Str, [Mod,Line|Args]). -handle_connect(Object, EvData, From, State0 = #state{users=Users}) -> - User0 = #user{events=Evs0,evt_handler=Handler0} = gb_trees:get(From, Users), - Callback = wxEvtHandler:get_callback(EvData), - case Handler0 of - #wx_ref{} when Callback =:= 0 -> - CBHandler = Handler0, - Handler = Handler0; - undefined when Callback =:= 0 -> - Handler = new_evt_listener(State0, From), - CBHandler = Handler; - _ -> - CBHandler = new_evt_listener(State0, From), - Handler = Handler0 - end, - Evs = [#event{object=Object,callback=Callback, cb_handler=CBHandler}|Evs0], - User = User0#user{events=Evs, evt_handler=Handler}, - State1 = State0#state{users=gb_trees:update(From, User, Users)}, - if is_function(Callback) orelse is_pid(Callback) -> - {FunId, State} = attach_fun(Callback,State1), - Res = wxEvtHandler:connect_impl(CBHandler,Object, - wxEvtHandler:replace_fun_with_id(EvData,FunId)), - case Res of - ok -> {reply,Res,State}; - _Error -> {reply,Res,State0} - end; - - true -> - Res = {call_impl, connect_cb, CBHandler}, - {reply, Res, State1} - end. +handle_connect(Object, #evh{handler=undefined, cb=Callback} = EvData0, + From, State0) -> + %% Callback let this process listen to the events + {FunId, State} = attach_fun(Callback,State0), + EvData1 = EvData0#evh{cb=FunId}, + case wxEvtHandler:connect_impl(Object,EvData1) of + {ok, Handler} -> + EvData = EvData1#evh{handler=Handler,userdata=undefined}, + handle_connect(Object, EvData, From, State); + Error -> + {reply, Error, State0} + end; +handle_connect(Object, EvData=#evh{handler=Handler}, + From, State0 = #state{users=Users}) -> + %% Correct process is already listening just register it + put(Handler, From), + User0 = #user{events=Listeners0} = gb_trees:get(From, Users), + User = User0#user{events=[{Object,EvData}|Listeners0]}, + State = State0#state{users=gb_trees:update(From, User, Users)}, + {reply, ok, State}. invoke_cb({{Ev=#wx{}, Ref=#wx_ref{}}, FunId,_}, _S) -> %% Event callbacks @@ -329,20 +319,6 @@ get_wx_object_state(Pid) -> _ -> ignore end. -new_evt_listener(State, Owner) -> - #wx_env{port=Port} = wx:get_env(), - _ = erlang:port_control(Port,98,<<>>), - Listener = get_result(State), - put(Listener, Owner), - Listener. - -get_result(_State) -> - receive - {'_wxe_result_', Res} -> Res; - {'_wxe_error_', Op, Error} -> - erlang:error({Error, {wxEvtHandler, {internal_installer, Op}}}) - end. - attach_fun(Fun, S = #state{cb=CB,cb_cnt=Next}) -> case gb_trees:lookup(Fun,CB) of {value, ID} -> @@ -367,90 +343,72 @@ delete_fun(FunId, State = #state{cb=CB}) -> State end. -cleanup_evt_listener(U=#user{events=Evs0,evt_handler=Handler}, EvtListener, Object) -> - {Evs, Del} = lists:foldl(fun(#event{object=Obj,cb_handler=CBH}, {Acc, Delete}) - when CBH =:= EvtListener, Obj =:= Object -> - {Acc, Delete}; - (Event = #event{cb_handler=CBH}, {Acc, _Delete}) - when CBH =:= EvtListener -> - {[Event|Acc], false}; - (Event, {Acc, Delete}) -> - {[Event|Acc], Delete} - end, {[], true}, Evs0), - Del andalso wxEvtHandler:destroy_evt_listener(EvtListener), - case Del andalso Handler =:= EvtListener of - true -> - U#user{events=Evs, evt_handler=undefined}; - false -> - U#user{events=Evs} - end. +cleanup_evt_listener(U=#user{events=Evs0}, EvtListener, Object) -> + Filter = fun({Obj,#evh{handler=Evl}}) -> + not (Object =:= Obj andalso Evl =:= EvtListener) + end, + U#user{events=lists:filter(Filter, Evs0)}. -handle_disconnect(Object, Evh, From, State0 = #state{users=Users0}) -> +handle_disconnect(Object, Evh = #evh{cb=Fun}, From, + State0 = #state{users=Users0, cb=Callbacks}) -> #user{events=Evs0} = gb_trees:get(From, Users0), - Fun = wxEvtHandler:get_callback(Evh), - case find_handler(Evs0, Object, Fun) of - [] -> {reply, false, State0}; + FunId = gb_trees:lookup(Fun, Callbacks), + case find_handler(Evs0, Object, Evh#evh{cb=FunId}) of + [] -> + {reply, false, State0}; Handlers -> - case disconnect(Object,Evh, Handlers) of - #event{} -> - {reply, true, State0}; - Result -> - {reply, Result, State0} + case disconnect(Object,Handlers) of + #evh{} -> {reply, true, State0}; + Result -> {reply, Result, State0} end end. -disconnect(Object,Evh,[Ev=#event{cb_handler=Handler}|Evs]) -> - try wxEvtHandler:disconnect_impl(Handler,Object,Evh) of +disconnect(Object,[Ev|Evs]) -> + try wxEvtHandler:disconnect_impl(Object,Ev) of true -> Ev; - false -> disconnect(Object, Evh, Evs); + false -> disconnect(Object, Evs); Error -> Error catch _:_ -> false end; -disconnect(_, _, []) -> false. - -find_handler(Evs, Object, Fun) -> - find_handler(Evs, Object, Fun, []). - -find_handler([Ev =#event{object=Object,callback=FunReg}|Evs],Object,Search,Acc) -> - case FunReg =:= Search of - true -> find_handler(Evs,Object,Search,[Ev|Acc]); - false when is_function(FunReg), Search =:= 0 -> - find_handler(Evs,Object,Search,[Ev|Acc]); - _ -> - find_handler(Evs,Object,Search,Acc) +disconnect(_, []) -> false. + +find_handler([{Object,Evh}|Evs], Object, Match) -> + case match_handler(Match, Evh) of + false -> find_handler(Evs, Object, Match); + Res -> [Res|find_handler(Evs,Object,Match)] end; -find_handler([_|Evs],Object,Fun,Res) -> - find_handler(Evs,Object,Fun,Res); -find_handler([],_Object,_Fun,Res) -> - Res. +find_handler([_|Evs], Object, Match) -> + find_handler(Evs, Object, Match); +find_handler([], _, _) -> []. + +match_handler(M=#evh{et=MET, cb=MCB}, + #evh{et=ET, cb=CB, handler=Handler}) -> + %% Let wxWidgets handle the id matching + Match = match_et(MET, ET) + andalso match_cb(MCB, CB), + Match andalso M#evh{handler=Handler}. +match_et(null, _) -> true; +match_et(Met, Et) -> Met =:= Et. + +match_cb(none, _) -> true; +match_cb({value,MId}, Id) -> MId =:= Id. %% Cleanup %% The server handles callbacks from driver so every other wx call must %% be called from another process, therefore the cleaning must be spawned. %% -%% Using Disconnect when we terminate can crash, it is timing releated -%% but it seems that disconnect on windows that are being deleted are bad. -%% Since we are terminating the data will be cleaned up anyway. -cleanup(Env, Data, Disconnect) -> +cleanup(Env, Data) -> put(?WXE_IDENTIFIER, Env), - lists:foreach(fun(User) -> cleanup(User, Disconnect) end, Data), + Disconnect = fun({Object, Ev}) -> + try wxEvtHandler:disconnect_impl(Object,Ev) + catch _:_ -> ok + end + end, + + lists:foreach(fun(#user{events=Evs}) -> + [Disconnect(Ev) || Ev <- Evs] + end, Data), gen_server:cast(Env#wx_env.sv, {cleaned, self()}), normal. - -cleanup(#user{events=Evs, evt_handler=Handler}, Disconnect) -> - lists:foreach(fun(#event{object=O, callback=CB, cb_handler=CbH}) -> - Disconnect andalso (catch wxEvtHandler:disconnect_impl(CbH,O)), - case is_function(CB) of - true -> - wxEvtHandler:destroy_evt_listener(CbH); - false -> - ignore - end - end, Evs), - case Handler of - undefined -> ignore; - _ -> wxEvtHandler:destroy_evt_listener(Handler) - end, - ok. diff --git a/lib/wx/src/wxe_util.erl b/lib/wx/src/wxe_util.erl index a31c3e30b8..02ac4ddfa6 100644 --- a/lib/wx/src/wxe_util.erl +++ b/lib/wx/src/wxe_util.erl @@ -74,7 +74,7 @@ call(Op, Args) -> true -> debug_call(Dbg band 15, Op, Args, Port) end. - + rec(Op) -> receive {'_wxe_result_', Res} -> Res; @@ -108,21 +108,26 @@ send_bin(Bin) when is_binary(Bin) -> get_cbId(Fun) -> gen_server:call((wx:get_env())#wx_env.sv,{register_cb, Fun}, infinity). -connect_cb(Object,EvData) -> - handle_listener(connect_cb, Object, EvData). - -disconnect_cb(Object,EvData) -> - handle_listener(disconnect_cb, Object, EvData). - -handle_listener(Op,Object,EvData) -> - Listener = gen_server:call((wx:get_env())#wx_env.sv, {Op,Object,EvData}, infinity), - case Listener of - {call_impl, connect_cb, EvtList} -> - wxEvtHandler:connect_impl(EvtList,Object,EvData); - Res -> - Res +connect_cb(Object,EvData0 = #evh{cb=Callback}) -> + Server = (wx:get_env())#wx_env.sv, + case Callback of + 0 -> %% Message api connect from this process + case wxEvtHandler:connect_impl(Object,EvData0) of + {ok, Listener} -> + EvData = EvData0#evh{handler=Listener, userdata=undefined}, + gen_server:call(Server, {connect_cb,Object,EvData}, infinity); + Error -> + Error + end; + _ -> %% callback, fun or pid (pid for wx_object:sync_events masked callbacks) + %% let the server do the connect + gen_server:call(Server, {connect_cb,Object,EvData0}, infinity) end. +disconnect_cb(Object,EvData) -> + Server = (wx:get_env())#wx_env.sv, + gen_server:call(Server, {disconnect_cb,Object,EvData}, infinity). + debug_cast(1, Op, _Args, _Port) -> check_previous(), case ets:lookup(wx_debug_info,Op) of diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl index 79dbea0575..7bdbd4594c 100644 --- a/lib/wx/test/wx_basic_SUITE.erl +++ b/lib/wx/test/wx_basic_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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 @@ -98,8 +98,23 @@ several_apps(Config) -> Pids = [spawn_link(fun() -> several_apps(Parent, N, Config) end) || N <- lists:seq(1,4)], process_flag(trap_exit,true), - ?m_multi_receive([{complete,Pid} || Pid <- Pids]), + Wait = fun(Pid,Acc) -> + receive {complete, Pid} -> Acc + after 20000 -> [Pid|Acc] + end + end, + Res = lists:foldl(Wait, [], Pids), [Pid ! quit || Pid <- Pids], + + Dbg = fun(Pid) -> + io:format("Stack ~p~n",[erlang:process_info(Pid, current_stacktrace)]), + io:format("Stack ~p~n",[erlang:process_info(Pid)]) + end, + case Res of + [] -> ok; + Failed -> + [Dbg(Pid)|| Pid <- Failed] + end, case wx_test_lib:user_available(Config) of true -> receive {'EXIT',_,foo} -> ok end; @@ -216,7 +231,7 @@ create_menus(Frame) -> %% Test the wx_misc.erl api functionality. wx_misc(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); -wx_misc(Config) -> +wx_misc(_Config) -> wx:new([{debug, trace}]), put(wx_test_verbose, true), ?m(ok, wx_misc:bell()), diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl index b9c2fafe0e..076f16ba16 100644 --- a/lib/wx/test/wx_event_SUITE.erl +++ b/lib/wx/test/wx_event_SUITE.erl @@ -149,7 +149,7 @@ disconnect(Config) -> timer:sleep(1000), wx_test_lib:flush(), - ?m({'EXIT', {{badarg,_},_}}, wxEvtHandler:disconnect(Panel, non_existing_event_type)), + ?m(false, wxEvtHandler:disconnect(Panel, non_existing_event_type)), ?m(true, wxEvtHandler:disconnect(Panel, size)), ?m(ok, wxWindow:setSize(Panel, {200,102})), timer:sleep(1000), @@ -499,14 +499,14 @@ callback_clean(Config) -> end end), timer:sleep(500), %% Give it time to remove it - ?m({[{Pid,_,_}],[_],[_]}, white_box_check_event_handlers()), + ?m({[{Pid,_}],[_],[_]}, white_box_check_event_handlers()), Pid ! remove, timer:sleep(500), %% Give it time to remove it ?m({[],[],[]}, white_box_check_event_handlers()), SetupEventHandlers(), - ?m({[{_,_,_}],[_],[_]}, white_box_check_event_handlers()), + ?m({[{_,_}],[_],[_]}, white_box_check_event_handlers()), wxDialog:show(Dlg), wx_test_lib:wx_close(Dlg, Config), @@ -526,9 +526,9 @@ white_box_check_event_handlers() -> {status, _, _, [Env, _, _, _, Data]} = sys:get_status(Server), [_H, _data, {data, [{_, Record}]}] = Data, {state, _Port1, _Port2, Users, [], CBs, _Next} = Record, - {[{Pid, Evs, Listener} || - {Pid, {user, Evs, Listener}} <- gb_trees:to_list(Users), - (Evs =/= [] orelse Listener =/= undefined)], %% Ignore empty + {[{Pid, Evs} || + {Pid, {user, Evs}} <- gb_trees:to_list(Users), + Evs =/= []], %% Ignore empty gb_trees:to_list(CBs), [Funs || Funs = {Id, {Fun,_}} <- Env, is_integer(Id), is_function(Fun)] }. |