aboutsummaryrefslogtreecommitdiffstats
path: root/lib/wx/api_gen/wx_gen_erl.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/wx/api_gen/wx_gen_erl.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/wx/api_gen/wx_gen_erl.erl')
-rw-r--r--lib/wx/api_gen/wx_gen_erl.erl1272
1 files changed, 1272 insertions, 0 deletions
diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl
new file mode 100644
index 0000000000..64c11baec1
--- /dev/null
+++ b/lib/wx/api_gen/wx_gen_erl.erl
@@ -0,0 +1,1272 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%%-------------------------------------------------------------------
+%%% File : wx_gen_erl.erl
+%%% Author : Dan Gudmundsson <[email protected]>
+%%% Description :
+%%%
+%%% Created : 25 Jan 2007 by Dan Gudmundsson <[email protected]>
+%%%-------------------------------------------------------------------
+
+-module(wx_gen_erl).
+
+-include("wx_gen.hrl").
+
+-compile(export_all).
+
+-import(lists, [foldl/3,foldr/3,reverse/1, keysearch/3, map/2, filter/2]).
+-import(gen_util, [lowercase/1, lowercase_all/1, uppercase/1, uppercase_all/1,
+ open_write/1, close/0, erl_copyright/0, w/2,
+ args/3, args/4, strip_name/2]).
+
+gen(Defs) ->
+ [put({class,N},C) || C=#class{name=N} <- Defs],
+ gen_unique_names(Defs),
+ gen_event_recs(),
+ gen_enums_ints(),
+ [gen_class(Class) || Class <- Defs],
+ gen_funcnames().
+
+gen_class(Class) ->
+ try
+ gen_class1(Class)
+ catch throw:skipped ->
+ Class
+ end.
+
+gen_class1(C=#class{name=Name,parent="static",methods=Ms,options=_Opts}) ->
+ open_write("../src/gen/wx_misc.erl"),
+ put(current_class, Name),
+ erl_copyright(),
+ w("", []),
+ w("%% This file is generated DO NOT EDIT~n~n", []),
+ w("%% @doc See external documentation: "
+ "<a href=\"http://www.wxwidgets.org/manuals/stable/wx_miscellany.html\">Misc</a>.\n\n",[]),
+
+ w("%% This module contains wxWidgets utility functions.~n~n", []),
+ w("-module(wx_misc).~n", []),
+ w("-include(\"wxe.hrl\").~n",[]),
+ %% w("-compile(export_all).~n~n", []), %% XXXX remove ???
+
+ Exp = fun(M) -> gen_export(C,M) end,
+ ExportList = lists:usort(lists:append(lists:map(Exp,reverse(Ms)))),
+ w("-export([~s]).~n~n", [args(fun(EF) -> EF end, ",", ExportList, 60)]),
+
+
+ Gen = fun(M) -> gen_method(Name,M) end,
+ NewMs = lists:map(Gen,reverse(Ms)),
+ close(),
+ erase(current_class),
+ C#class{methods=NewMs};
+
+gen_class1(C=#class{name=Name,parent=Parent,methods=Ms,options=Opts}) ->
+ case Opts of
+ ["ignore"] -> throw(skipped);
+ _ -> ok
+ end,
+ open_write("../src/gen/"++Name++".erl"),
+ put(current_class, Name),
+ erl_copyright(),
+ w("", []),
+ w("%% This file is generated DO NOT EDIT~n~n", []),
+
+ case lists:member(taylormade, Opts) of
+ true ->
+ {ok, Bin} = file:read_file(filename:join([wx_extra, Name++".erl"])),
+ w("~s~n", [binary_to_list(Bin)]),
+ NewMs = Ms;
+ false ->
+ w("%% @doc See external documentation: "
+ "<a href=\"http://www.wxwidgets.org/manuals/stable/wx_~s.html\">~s</a>.\n",
+ [lowercase_all(Name), Name]),
+
+ case C#class.doc of
+ undefined -> ignore;
+ Str -> w("%%~n%% ~s~n~n%%~n", [Str])
+ end,
+
+ case C#class.event of
+ false -> ignore;
+ Evs ->
+ EvTypes = [event_type_name(Ev) || Ev <- Evs],
+ EvStr = args(fun(Ev) -> "<em>"++Ev++"</em>" end, ", ", EvTypes),
+
+ w("%% <dl><dt>Use {@link wxEvtHandler:connect/3.} with EventType:</dt>~n",[]),
+ w("%% <dd>~s</dd></dl>~n", [EvStr]),
+ w("%% See also the message variant {@link wxEvtHandler:~s(). #~s{}} event record type.~n",
+ [event_rec_name(Name),event_rec_name(Name)]),
+ w("%%~n",[]),
+ ok
+ end,
+
+ Parents = parents(Parent),
+ case [P || P <- Parents, P =/= root, P =/= object] of
+ [] -> ignore;
+ Ps ->
+ w("%% <p>This class is derived (and can use functions) from: ~n", []),
+ [w("%% <br />{@link ~s}~n", [P]) || P <- Ps],
+ w("%% </p>~n",[])
+ end,
+ w("%% @type ~s(). An object reference, The representation is internal~n",[Name]),
+ w("%% and can be changed without notice. It can't be used for comparsion~n", []),
+ w("%% stored on disc or distributed for use on other nodes.~n~n", []),
+ w("-module(~s).~n", [Name]),
+ w("-include(\"wxe.hrl\").~n",[]),
+ %% w("-compile(export_all).~n~n", []), %% XXXX remove ???
+ %% w("-compile(nowarn_unused_vars).~n~n", []), %% XXXX remove ???
+ Exp = fun(M) -> gen_export(C,M) end,
+ ExportList = lists:usort(lists:append(lists:map(Exp,reverse(Ms)))),
+ w("-export([~s]).~n~n", [args(fun(EF) -> EF end, ",", ExportList, 60)]),
+ 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]),
+ 60)]),
+
+ w("%% @hidden~n", []),
+ parents_check(Parents),
+
+ Gen = fun(M) -> gen_method(Name,M) end,
+ NewMs = lists:map(Gen,reverse(Ms)),
+ gen_dest(C, Ms),
+
+ gen_inherited(Parents, Done, true)
+ end,
+
+ close(),
+ erase(current_class),
+ C#class{methods=NewMs}.
+
+
+parents("root") -> [root];
+parents("object") -> [object];
+parents(Parent) ->
+ case get({class,Parent}) of
+ #class{parent=GrandParent} ->
+ [Parent|parents(GrandParent)];
+ undefined ->
+ ?warning("unknown parent of ~p~n",[Parent]),
+ [Parent]
+ end.
+
+parents_check([object]) ->
+ w("parent_class(_Class) -> erlang:error({badtype, ?MODULE}).~n~n",[]);
+parents_check([root]) ->
+ w("parent_class(_Class) -> erlang:error({badtype, ?MODULE}).~n~n",[]);
+parents_check([Parent|Ps]) ->
+ w("parent_class(~s) -> true;~n",[Parent]),
+ parents_check(Ps).
+
+check_class(#type{base={class,"wx"}}) -> ok;
+check_class(#type{base={class,Name},xml=Xml}) ->
+ case get({class,Name}) of
+ undefined ->
+ case get({enum, Name}) of
+ undefined ->
+ case Xml of
+ "class" ++ _ ->
+ ?warning("~s:~s: Class ~p used but not defined~n",
+ [get(current_class),get(current_func),Name]);
+ _ ->
+ ?warning("~s:~s: Class ~p used but not defined~n (see ~p)~n",
+ [get(current_class),get(current_func),Name, Xml])
+ end;
+ _ ->
+ ?warning("~s:~s: Class ~p used is enum~n",
+ [get(current_class),get(current_func),Name])
+ end;
+ _ -> ok
+ end.
+
+gen_export(#class{name=Class,abstract=Abs},Ms0) ->
+ RemoveC = fun(#method{where=merged_c}) -> false;(_Other) -> true end,
+ Res = filter(RemoveC, Ms0),
+ case Res of
+ [] -> [];
+ [M=#method{where=taylormade}|_] ->
+ [taylormade_export(Class, M)];
+ Ms ->
+ GetF = fun(#method{method_type=constructor,where=W,params=Ps}) ->
+ {Args,Opts} = split_optional(Ps),
+ OptLen = case Opts of
+ [] -> 0;
+ _ when W =:= erl_no_opt -> 0;
+ _ -> 1
+ end,
+ "new/" ++ integer_to_list(length(Args)+OptLen);
+ (#method{method_type=destructor}) ->
+ case Abs of
+ true -> [];
+ _ -> "destroy/1"
+ end;
+ (#method{name=N,alias=A,where=W, params=Ps}) ->
+ {Args,Opts} = split_optional(Ps),
+ OptLen = case Opts of
+ [] -> 0;
+ _ when W =:= erl_no_opt -> 0;
+ _ -> 1
+ end,
+ erl_func_name(N,A) ++ "/" ++ integer_to_list(length(Args) + OptLen)
+ end,
+ lists:map(GetF, Ms)
+ end.
+
+
+gen_method(Class,Ms0) ->
+ RemoveC = fun(#method{where=merged_c}) -> false;(_Other) -> true end,
+ Res = filter(RemoveC, Ms0),
+ case Res of
+ [] -> Ms0;
+ [M=#method{where=taylormade}|_] ->
+ taylormade_func(Class, M),
+ Ms0;
+ Ms ->
+ gen_doc(Class,Ms),
+ gen_method1(Ms),
+ Ms0
+ end.
+
+gen_method1([M=#method{method_type=destructor}]) ->
+ %% Skip now do destructors later
+ M;
+gen_method1([M0]) ->
+ gen_method2(M0),
+ w(".~n~n",[]);
+gen_method1([M0|Ms]) ->
+ gen_method2(M0),
+ w(";~n",[]),
+ gen_method1(Ms).
+
+gen_method2(M=#method{name=N,alias=A,params=Ps0,where=erl_no_opt,method_type=MT}) ->
+ put(current_func, N),
+ Ps = [patch_param(P,classes) || P <- Ps0],
+ w("~n", []),
+ gen_function_clause(erl_func_name(N,A),MT,Ps,[],[name_type]),
+ w(" ", []),
+ gen_function_clause(erl_func_name(N,A),MT,Ps,empty_list,[no_guards,name_only]),
+ M;
+gen_method2(M=#method{name=N,alias=A,params=Ps,type=T,method_type=MT,id=MethodId}) ->
+ put(current_func, N),
+ {Args, Optional} = split_optional(Ps),
+ gen_function_clause(erl_func_name(N,A),MT, Args, Optional, []),
+ MId = arg_type_tests(Args, "?" ++ get_unique_name(MethodId)),
+ {MArgs,Align} = marshal_args(Args),
+ MOpts = marshal_opts(Optional, Align, Args),
+ case have_return_vals(T, Ps) of
+ _ when MT =:= constructor ->
+ w(" wxe_util:construct(~s,~n <<~s~s>>)", [MId, MArgs,MOpts]);
+ true ->
+ w(" wxe_util:call(~s,~n <<~s~s>>)", [MId, MArgs,MOpts]);
+ false ->
+ w(" wxe_util:cast(~s,~n <<~s~s>>)", [MId, MArgs,MOpts])
+ end,
+ erase(current_func),
+ M.
+
+gen_dest(#class{name=CName,abstract=Abs}, Ms) ->
+ case Abs of
+ true ->
+ ignore;
+ false ->
+ case lists:keysearch(destructor,#method.method_type, lists:append(Ms)) of
+ {value, #method{method_type=destructor, id=Id}} ->
+ case hd(reverse(parents(CName))) of
+ object ->
+ gen_dest2(CName, object);
+ root ->
+ gen_dest2(CName, Id)
+ end;
+ false ->
+ erlang:error({no_destructor_found, CName})
+ end
+ end.
+
+gen_dest2(Class, Id) ->
+ w("%% @spec (This::~s()) -> ok~n", [Class]),
+ w("%% @doc Destroys this object, do not use object again~n", []),
+ w("destroy(Obj=#wx_ref{type=Type}) -> ~n", []),
+ w(" ?CLASS(Type,~s),~n",[Class]),
+ case Id of
+ object ->
+ w(" wxe_util:destroy(?DESTROY_OBJECT,Obj),~n ok.~n", []);
+ _ ->
+ w(" wxe_util:destroy(?~s,Obj),~n ok.~n", [get_unique_name(Id)])
+ end,
+ ok.
+
+gen_inherited([root], Done, Exported) -> {Done, Exported};
+gen_inherited([object], Done, Exported) -> {Done, Exported};
+gen_inherited([Parent|Ps], Done0, Exported0) ->
+ #class{name=Class, methods=Ms} = get({class,Parent}),
+ case is_list(Exported0) of
+ false -> w(" %% From ~s ~n", [Class]);
+ true -> ignore
+ end,
+ {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],
+ Class,Skip,Done, Exported)
+ when W =/= merged_c ->
+ case gb_sets:is_member(Name,Skip) of
+ false when MT =:= member, Exported =:= true ->
+ Ps = [patch_param(P,all) || P <- Ps0],
+ Opts = if W =:= erl_no_opt -> [];
+ true ->
+ [Opt || Opt = #param{def=Def,in=In, where=Where} <- Ps,
+ Def =/= none, In =/= false, Where =/= c]
+ end,
+ w("%% @hidden~n", []),
+ gen_function_clause(erl_func_name(Name,A),MT,Ps,Opts,[no_guards,name_only]),
+ w(" -> ~s:", [Class]),
+ gen_function_clause(erl_func_name(Name,A),MT,Ps,Opts,[no_guards,name_only]),
+ w(".~n", []),
+ gen_inherited_ms(R,Class, Skip, gb_sets:add(Name,Done), Exported);
+ false when MT =:= member, is_list(Exported) ->
+ {Args,Opts} = split_optional(Ps0),
+ OptLen = case Opts of
+ [] -> 0;
+ _ 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]);
+ _ ->
+ gen_inherited_ms(R,Class, Skip, Done, Exported)
+ end;
+gen_inherited_ms([[_|Check]|R],Class,Skip, Done0,Exp) ->
+ gen_inherited_ms([Check|R],Class,Skip, Done0,Exp);
+gen_inherited_ms([[]|R],Class,Skip,Done0,Exp) ->
+ gen_inherited_ms(R,Class,Skip,Done0,Exp);
+gen_inherited_ms([], _, _Skip, Done,Exp) -> {Done,Exp}.
+
+
+%%%%%%%%%%%%%%%
+
+taylormade_func(Class, #method{name=Name, id=Id}) ->
+ {ok, Bin} = file:read_file(filename:join([wx_extra, Class ++".erl"])),
+ Str0 = binary_to_list(Bin),
+ {match, [Str1]} = re:run(Str0, "<<"++Name++"(.*)"++Name++">>",
+ [dotall, {capture, all_but_first, list}]),
+
+ w(Str1, ["?" ++ get_unique_name(Id)]),
+ ok.
+
+taylormade_export(Class, #method{name=Name}) ->
+ {ok, Bin} = file:read_file(filename:join([wx_extra, Class ++".erl"])),
+ Str0 = binary_to_list(Bin),
+ {match, [Str1]} = re:run(Str0, "<<EXPORT:"++Name++"(.*)"++Name++":EXPORT>>",
+ [dotall, {capture, all_but_first, list}]),
+ Str1.
+
+%%%%%%%%%%%%%%%
+
+arg_type_tests([P|Ps], Mid0) ->
+ case arg_type_test(P,"\n",Mid0) of
+ Mid0 ->
+ arg_type_tests(Ps, Mid0);
+ Mid -> %% Already checked the other args
+ Mid
+ end;
+arg_type_tests([],Mid) -> Mid.
+
+arg_type_test(#param{where=c}, _, Acc) ->
+ Acc;
+arg_type_test(#param{name=Name0,in=In,type=#type{base={class,T},single=true},def=none},
+ EOS,Acc) when In =/= false ->
+ Name = erl_arg_name(Name0),
+ w(" ?CLASS(~sT,~s),~s", [Name,T,EOS]),
+ Acc;
+arg_type_test(#param{name=Name0,in=In,type=#type{base={class,T}}, def=none},EOS,Acc)
+ when In =/= false ->
+ Name = erl_arg_name(Name0),
+ w(" [?CLASS(~sT,~s) || #wx_ref{type=~sT} <- ~s],~s", [Name,T,Name,Name,EOS]),
+ Acc;
+arg_type_test(#param{name=Name0,def=none,in=In,
+ type={merged,
+ M1, #type{base={class,T1},single=true},Ps1,
+ M2, #type{base={class,T2},single=true},Ps2}}, EOS, _Acc)
+ when In =/= false ->
+ Name = erl_arg_name(Name0),
+ Opname = Name++"OP",
+ w(" ~s = case ?CLASS_T(~sT,~s) of~n true ->\n ", [Opname,Name,T1]),
+ lists:foreach(fun(Param) -> arg_type_test(Param,"\n ", ignore) end,
+ element(1,split_optional(Ps1))),
+ w("?~s;~n",[get_unique_name(M1)]),
+ w(" _ -> ?CLASS(~sT,~s),\n ",[Name,T2]),
+ {Ps21,_} = split_optional(patchArgName(Ps2,Ps1)),
+ lists:foreach(fun(Param) -> arg_type_test(Param,"\n ", ignore) end,
+ Ps21),
+ w("?~s\n end,~s",[get_unique_name(M2),EOS]),
+ Opname;
+arg_type_test(#param{name=Name0, type=#type{base=eventType}}, EOS, Acc) ->
+ Name = erl_arg_name(Name0),
+ w(" ~sBin = list_to_binary([atom_to_list(~s)|[0]]),~s", [Name,Name,EOS]),
+ w(" ThisTypeBin = list_to_binary([atom_to_list(ThisT)|[0]]),~s", [EOS]),
+ Acc;
+arg_type_test(#param{name=Name0,def=none,type=#type{base={term,_}}}, EOS, Acc) ->
+ Name = erl_arg_name(Name0),
+ w(" wxe_util:send_bin(term_to_binary(~s)),~s", [Name,EOS]),
+ Acc;
+arg_type_test(#param{name=Name0,type=#type{base=binary}},EOS,Acc) ->
+ Name = erl_arg_name(Name0),
+ w(" wxe_util:send_bin(~s),~s", [Name,EOS]),
+ Acc;
+arg_type_test(#param{name=Name0,type=#type{name=Type,base=Base,single=Single}},EOS,Acc) ->
+ if
+ Type =:= "wxArtClient", Single =:= true ->
+ Name = erl_arg_name(Name0),
+ w(" ~s_UC = unicode:characters_to_binary([~s, $_, $C,0]),~s",
+ [Name,Name, EOS]);
+ Base =:= string orelse (Type =:= "wxChar" andalso Single =/= true) ->
+ Name = erl_arg_name(Name0),
+ w(" ~s_UC = unicode:characters_to_binary([~s,0]),~s", [Name,Name,EOS]);
+ Type =:= "wxArrayString" ->
+ Name = erl_arg_name(Name0),
+ w(" ~s_UCA = [unicode:characters_to_binary([~sTemp,0]) || ~s",
+ [Name,Name, EOS]),
+ w(" ~sTemp <- ~s],~s", [Name,Name,EOS]);
+ true -> %% Not a string
+ ignore
+ end,
+ Acc;
+arg_type_test(_,_,Acc) -> Acc.
+
+patchArgName([Param|R1], [#param{name=Name}|R2]) ->
+ [Param#param{name=Name}|patchArgName(R1,R2)];
+patchArgName([],[]) -> [].
+
+have_return_vals(void, Ps) ->
+ lists:any(fun(#param{in=In}) -> In =/= true end, Ps);
+have_return_vals(#type{}, _) -> true.
+
+gen_function_clause(Name0,MT,Ps,Optional,Variant) ->
+ PArg = fun(Arg) ->
+ case lists:member(name_only, Variant) of
+ true -> func_arg_name(Arg);
+ false ->
+ case lists:member(name_type, Variant) of
+ true ->
+ Name = func_arg_name(Arg),
+ case func_arg(Arg) of
+ Name -> Name;
+ Typed -> Name ++ "=" ++ Typed
+ end;
+ false ->
+ func_arg(Arg)
+ end
+ end
+ end,
+ Args = args(PArg, ",", Ps),
+ Name = case MT of constructor -> "new"; _ -> Name0 end,
+ w("~s(~s",[Name,Args]),
+ Opts = case Optional of
+ [] -> "";
+ empty_list when Args =:= [] -> "[]";
+ empty_list -> ", []";
+ _ when Args =:= [] -> "Options";
+ _ -> ", Options"
+ end,
+ w("~s)", [Opts]),
+ case lists:member(no_guards, Variant) of
+ true -> ok;
+ false ->
+ Guards = args(fun guard_test/1, ",", Ps),
+ if
+ Guards =:= [], Opts =:= "" -> w(" ->~n", []);
+ Guards =:= [] -> w("~n when is_list(Options) ->~n", []);
+ Opts =:= "" -> w("~n when ~s ->~n", [Guards]);
+ true -> w("~n when ~s,is_list(Options) ->~n", [Guards])
+ end
+ end.
+
+split_optional(Ps) ->
+ split_optional(Ps, [], []).
+split_optional([P=#param{def=Def,in=In, where=Where}|Ps], Standard, Opts)
+ when Def =/= none, In =/= false, Where =/= c ->
+ split_optional(Ps, Standard, [P|Opts]);
+split_optional([P=#param{def=Def,in=In, where=Where}|Ps], Standard, Opts)
+ when Def =:= none, In =/= false, Where =/= c ->
+ split_optional(Ps, [P|Standard], Opts);
+split_optional([_|Ps], Standard, Opts) ->
+ split_optional(Ps, Standard, Opts);
+split_optional([], Standard, Opts) ->
+ {reverse(Standard), reverse(Opts)}.
+
+patch_param(P=#param{type=#type{base=Tuple}}, all) when is_tuple(Tuple) ->
+ P#param{type={class,ignore}};
+patch_param(P=#param{type={merged,_,_,_,_,_,_}}, _) ->
+ P#param{type={class,ignore}};
+patch_param(P=#param{type=#type{base={class,_}}},_) ->
+ P#param{type={class,ignore}};
+patch_param(P=#param{type=#type{base={ref,_}}},_) ->
+ P#param{type={class,ignore}};
+patch_param(P,_) -> P.
+
+func_arg_name(#param{def=Def}) when Def =/= none -> skip;
+func_arg_name(#param{in=false}) -> skip;
+func_arg_name(#param{where=c}) -> skip;
+func_arg_name(#param{name=Name}) ->
+ erl_arg_name(Name).
+
+func_arg(#param{def=Def}) when Def =/= none -> skip;
+func_arg(#param{in=false}) -> skip;
+func_arg(#param{where=c}) -> skip;
+func_arg(#param{name=Name,type=#type{base=string}}) ->
+ erl_arg_name(Name);
+func_arg(#param{name=Name,type=#type{name="wxArrayString"}}) ->
+ erl_arg_name(Name);
+func_arg(#param{name=Name0,type=#type{base={class,_CN}, single=true}}) ->
+ Name = erl_arg_name(Name0),
+ "#wx_ref{type=" ++ Name ++ "T,ref=" ++ Name++"Ref}";
+func_arg(#param{name=Name0,type=#type{base={ref,CN}, single=true}}) ->
+ Name = erl_arg_name(Name0),
+ "#wx_ref{type=" ++ CN ++ ",ref=" ++ Name++"Ref}";
+func_arg(#param{name=Name0,type={merged,_,#type{base={class,_},single=true},_,
+ _, #type{base={class,_},single=true},_}}) ->
+ Name = erl_arg_name(Name0),
+ "#wx_ref{type=" ++ Name ++ "T,ref=" ++ Name++"Ref}";
+func_arg(#param{name=Name,type=#type{base={enum,_}}}) ->
+ erl_arg_name(Name);
+func_arg(#param{name=Name,type=#type{base={comp,"wxColour",_Tup}, single=true}}) ->
+ erl_arg_name(Name);
+func_arg(#param{name=Name,type=#type{base={comp,"wxDateTime",_Tup}, single=true}}) ->
+ erl_arg_name(Name);
+func_arg(#param{name=Name,type=#type{name="wxArtClient", single=true}}) ->
+ erl_arg_name(Name);
+func_arg(#param{name=Name,type=#type{base={comp,_,Tup}, single=true}}) ->
+ N = erl_arg_name(Name),
+ Doc = fun({_,V}) -> erl_arg_name(N)++V end,
+ "{" ++ args(Doc, ",", Tup) ++ "}";
+func_arg(#param{name=Name}) ->
+ erl_arg_name(Name).
+
+
+guard_test(#param{type=#type{base={class,_},single=true}}) -> skip;
+guard_test(#param{def=Def}) when Def =/= none -> skip;
+guard_test(#param{where=c}) -> skip;
+guard_test(#param{in=In}) when In == false -> skip;
+guard_test(#param{name=N, type=#type{base=string}}) ->
+ "is_list(" ++ erl_arg_name(N) ++")";
+guard_test(#param{name=N, type=#type{name="wxArtClient"}}) ->
+ "is_list(" ++ erl_arg_name(N) ++")";
+guard_test(#param{name=N, type=#type{name="wxArrayString"}}) ->
+ "is_list(" ++ erl_arg_name(N) ++")";
+guard_test(#param{name=Name,type=#type{single=Single}})
+ when Single =/= true->
+ "is_list(" ++ erl_arg_name(Name) ++ ")";
+guard_test(#param{name=N,type=#type{base=int}}) ->
+ "is_integer(" ++ erl_arg_name(N) ++ ")";
+guard_test(#param{name=N,type=#type{base=long}}) ->
+ "is_integer(" ++ erl_arg_name(N) ++ ")";
+guard_test(#param{name=N,type=#type{base=float}}) ->
+ "is_float(" ++ erl_arg_name(N) ++ ")";
+guard_test(#param{name=N,type=#type{base=double}}) ->
+ "is_float(" ++ erl_arg_name(N) ++ ")";
+guard_test(#param{name=N,type=#type{base=bool}}) ->
+ "is_boolean(" ++ erl_arg_name(N) ++ ")";
+guard_test(#param{name=N,type=#type{name="wxDateTime"}}) ->
+ "tuple_size(" ++ erl_arg_name(N) ++ ") =:= 2";
+guard_test(#param{name=N,type=#type{base=binary}}) ->
+ "is_binary(" ++ erl_arg_name(N) ++ ")";
+guard_test(#param{name=Name,type=#type{base={enum,_}}}) ->
+ "is_integer(" ++ erl_arg_name(Name) ++ ")";
+guard_test(#param{name=Name,type=#type{base=eventType}}) ->
+ "is_atom(" ++ erl_arg_name(Name) ++ ")";
+guard_test(#param{name=_N,type=#type{base={term,_}}}) ->
+ skip;
+guard_test(#param{name=_N,type=#type{base={ref,_}}}) ->
+ skip;
+guard_test(#param{name=_N,type=#type{base={class,_}}}) ->
+ skip;
+guard_test(#param{name=_N,type={merged,_,#type{base={class,_}},_,_,#type{},_}}) ->
+ skip;
+guard_test(#param{name=N,type=#type{base={comp,"wxColour",_Tup}}}) ->
+ "tuple_size(" ++ erl_arg_name(N) ++ ") =:= 3; tuple_size(" ++ erl_arg_name(N) ++ ") =:= 4";
+guard_test(#param{name=N,type=#type{base={comp,_,Tup}}}) ->
+ Doc = fun({int,V}) -> "is_integer("++erl_arg_name(N)++V ++")";
+ ({double,V}) -> "is_number("++erl_arg_name(N)++V ++")"
+ end,
+ args(Doc, ",", Tup);
+guard_test(#param{name=N,type={class,ignore}}) ->
+ "is_record(" ++ erl_arg_name(N)++ ", wx_ref)";
+guard_test(T) -> ?error({unknown_type,T}).
+
+gen_doc(_Class, [#method{method_type=destructor}]) -> skip;
+gen_doc(_Class,[#method{name=N,alias=A,params=Ps,type=T,where=erl_no_opt,method_type=MT}])->
+ w("%% @spec (~s~s) -> ~s~n",[doc_arg_types(Ps),"",doc_return_types(T,Ps)]),
+ w("%% @equiv ", []),
+ gen_function_clause(erl_func_name(N,A),MT,Ps,empty_list,[no_guards,name_only]);
+gen_doc(Class,[#method{name=N,params=Ps,type=T}])->
+ {_, Optional} = split_optional(Ps),
+ NonDef = [Arg || Arg = #param{def=Def,in=In, where=Where} <- Ps,
+ Def =:= none, In =/= false, Where =/= c],
+ OptsType = case Optional of
+ [] -> "";
+ _ when NonDef =:= [] -> "[Option]";
+ _ -> ", [Option]"
+ end,
+ w("%% @spec (~s~s) -> ~s~n",
+ [doc_arg_types(Ps),OptsType,doc_return_types(T,Ps)]),
+ doc_optional(Optional, normal),
+ DocEnum = doc_enum(T,Ps, normal),
+ case Class of
+ "utils" ->
+ w("%% @doc See <a href=\"http://www.wxwidgets.org/manuals/stable/wx_miscellany.html#~s\">"
+ "external documentation</a>.~n",
+ [lowercase_all(N)]);
+ _ ->
+ w("%% @doc See <a href=\"http://www.wxwidgets.org/manuals/stable/wx_~s.html#~s~s\">"
+ "external documentation</a>.~n",
+ [lowercase_all(Class),lowercase_all(Class),lowercase_all(N)])
+ end,
+ doc_enum_desc(DocEnum);
+gen_doc(Class, Cs = [#method{name=N, alias=A,method_type=MT}|_]) ->
+ GetRet = fun(#method{params=Ps,type=T}) ->
+ doc_return_types(T,Ps)
+ end,
+ GetArgs = fun(#method{params=Ps, where=Where}) ->
+ Opt = case Where of
+ erl_no_opt -> [];
+ _ ->
+ case split_optional(Ps) of
+ {_, []} -> [];
+ _ -> ["[Option]"]
+ end
+ end,
+ [doc_arg_type(P) ||
+ P=#param{in=In,def=none,where=W} <- Ps,
+ In =/= false, W =/= c] ++ Opt
+ end,
+ Args = zip(lists:map(GetArgs, Cs)),
+ Ret = lists:map(GetRet, Cs),
+ w("%% @spec (~s) -> ~s~n",[args(fun doc_arg/1,",",Args),doc_ret(Ret)]),
+ case Class of
+ "utils" ->
+ w("%% @doc See <a href=\"http://www.wxwidgets.org/manuals/stable/wx_miscellany.html#~s\">"
+ "external documentation</a>.~n",
+ [lowercase_all(N)]);
+ _ ->
+ w("%% @doc See <a href=\"http://www.wxwidgets.org/manuals/stable/wx_~s.html#~s~s\">"
+ "external documentation</a>.~n",
+ [lowercase_all(Class),lowercase_all(Class),lowercase_all(N)])
+ end,
+ Name = case MT of constructor -> "new"; _ -> erl_func_name(N,A) end,
+ w("%% <br /> Alternatives: ~n",[]),
+ [gen_doc2(Name, Clause) || Clause <- Cs],
+ ok.
+
+gen_doc2(Name,#method{params=Ps,where=erl_no_opt,method_type=MT}) ->
+ w("%% <p><c>~n",[]),
+ w("%% ~s(~s) -> ", [Name,doc_arg_types(Ps)]),
+ gen_function_clause(Name,MT,Ps,empty_list,[no_guards,name_only]),
+ w(" </c></p>~n",[]);
+gen_doc2(Name,#method{params=Ps,type=T}) ->
+ {NonDef, Optional} = split_optional(Ps),
+ OptsType = case Optional of
+ [] -> "";
+ _ when NonDef =:= [] -> "[Option]";
+ _ -> ", [Option]"
+ end,
+ w("%% <p><c>~n",[]),
+ w("%% ~s(~s~s) -> ~s </c>~n",
+ [Name,doc_arg_types(Ps),OptsType,doc_return_types(T,Ps)]),
+ doc_optional(Optional, xhtml),
+ DocEnum = doc_enum(T,Ps, xhtml),
+ doc_enum_desc(DocEnum),
+ w("%% </p>~n",[]).
+
+doc_arg(ArgList) ->
+ case all_eq(ArgList) of
+ true -> hd(ArgList);
+ false ->
+ Get = fun(Str) ->
+ [_Name|Types] = string:tokens(Str, ":"),
+ case Types of
+ [Type] -> Type;
+ _ ->
+ "term()"
+ end
+ end,
+ Args0 = lists:map(Get, ArgList),
+ Args = unique(Args0, []),
+ "X::" ++ args(fun(A) -> A end, "|", Args)
+ end.
+
+doc_ret(ArgList) ->
+ case all_eq(ArgList) of
+ true -> hd(ArgList);
+ false ->
+ args(fun(A) -> A end, "|", ArgList)
+ end.
+
+unique([], U) -> reverse(U);
+unique([H|R], U) ->
+ case lists:member(H,U) of
+ false -> unique(R,[H|U]);
+ true -> unique(R,U)
+ end.
+
+all_eq([H|R]) -> all_eq(R,H).
+
+all_eq([H|R],H) -> all_eq(R,H);
+all_eq([],_) -> true;
+all_eq(_,_) -> false.
+
+zip(List) ->
+ zip(List, [], [], []).
+
+zip([[F|L1]|List], Rest, AccL, Acc) ->
+ zip(List, [L1|Rest], [F|AccL], Acc);
+zip(Empty, Rest, AccL, Acc) ->
+ true = empty(Empty),
+ case empty(Rest) andalso empty(AccL) of
+ true -> reverse(Acc);
+ false ->
+ zip(reverse(Rest), [], [], [reverse(AccL)|Acc])
+ end.
+
+empty([[]|R]) -> empty(R);
+empty([]) -> true;
+empty(_) -> false.
+
+doc_arg_types(Ps0) ->
+ Ps = [P || P=#param{in=In, where=Where} <- Ps0,In =/= false, Where =/= c],
+ args(fun doc_arg_type/1, ", ", Ps).
+doc_arg_type(#param{name=Name,def=none,type=T}) ->
+ erl_arg_name(Name) ++ "::" ++ doc_arg_type2(T);
+doc_arg_type(#param{name=Name,in=false,type=T}) ->
+ erl_arg_name(Name) ++ "::" ++ doc_arg_type2(T);
+doc_arg_type(_) -> skip.
+
+doc_arg_type2(T=#type{single=Single}) when Single =:= array; Single =:= list ->
+ "[" ++ doc_arg_type3(T) ++ "]";
+doc_arg_type2(T) ->
+ doc_arg_type3(T).
+
+doc_arg_type3(#type{base=string}) -> "string()";
+doc_arg_type3(#type{name="wxChar", single=S}) when S =/= true -> "string()";
+doc_arg_type3(#type{name="wxArrayString"}) -> "[string()]";
+doc_arg_type3(#type{name="wxDateTime"}) -> "wx:datetime()";
+doc_arg_type3(#type{name="wxArtClient"}) -> "string()";
+doc_arg_type3(#type{base=int}) -> "integer()";
+doc_arg_type3(#type{base=long}) -> "integer()";
+doc_arg_type3(#type{base=bool}) -> "bool()";
+doc_arg_type3(#type{base=float}) -> "float()";
+doc_arg_type3(#type{base=double}) -> "float()";
+doc_arg_type3(#type{base=binary}) -> "binary()";
+doc_arg_type3(#type{base={binary,_}}) -> "binary()";
+doc_arg_type3(#type{base=eventType}) -> "atom()";
+doc_arg_type3(#type{base={ref,N}}) -> N++"()";
+doc_arg_type3(#type{base={term,_N}}) -> "term()";
+doc_arg_type3(T=#type{base={class,N}}) ->
+ check_class(T),
+ case get(current_class) of
+ N -> N ++ "()";
+ _ -> N++":" ++ N++"()"
+ end;
+doc_arg_type3({merged,_,T1=#type{base={class,N1}},_,_,T2=#type{base={class,N2}},_}) ->
+ check_class(T1),
+ check_class(T2),
+ Curr = get(current_class),
+ if
+ N1 =:= Curr, N2 =:= Curr -> N1++"() | "++ N2++"()";
+ N1 =:= Curr -> N1++"() | "++ N2++":" ++ N2++"()";
+ N2 =:= Curr -> N1++":" ++ N1++"() | "++ N2++"()";
+ true ->
+ N1++":" ++ N1++"() | "++ N2++":" ++ N2++"()"
+ end;
+doc_arg_type3(#type{base={enum,{_,N}}}) -> uppercase(N);
+doc_arg_type3(#type{base={enum,N}}) -> uppercase(N);
+doc_arg_type3(#type{base={comp,"wxColour",_Tup}}) ->
+ "wx:colour()";
+doc_arg_type3(#type{base={comp,_,{record,Name}}}) ->
+ "wx:" ++ atom_to_list(Name) ++ "()";
+doc_arg_type3(#type{base={comp,_,Tup}}) ->
+ Doc = fun({int,V}) -> V ++ "::integer()";
+ ({double,V}) -> V ++ "::float()"
+ end,
+ "{" ++ args(Doc, ",", Tup) ++ "}";
+doc_arg_type3(T) -> ?error({unknown_type,T}).
+
+doc_return_types(T, Ps) ->
+ doc_return_types2(T, [P || P=#param{in=In} <- Ps,In =/= true]).
+doc_return_types2(void, []) -> "ok";
+doc_return_types2(void, [#param{type=T}]) -> doc_arg_type2(T);
+doc_return_types2(T, []) -> doc_arg_type2(T);
+doc_return_types2(void, Ps) ->
+ "{" ++ args(fun doc_arg_type/1,",",Ps) ++ "}";
+doc_return_types2(T, Ps) ->
+ "{" ++ doc_arg_type2(T) ++ "," ++ args(fun doc_arg_type/1,",",Ps) ++ "}".
+
+break(xhtml) -> "<br />";
+break(_) -> "".
+
+doc_optional([],_) -> ok;
+doc_optional(Opts,Type) ->
+ w("%%~s Option = ~s~n", [break(Type),args(fun doc_optional2/1, " | ", Opts)]).
+
+doc_optional2(#param{name=Name, def=_Def, type=T}) ->
+ "{" ++ erl_option_name(Name) ++ ", " ++ doc_arg_type2(T) ++ "}".
+
+doc_enum(#type{base={enum,Enum}},Ps,Break) ->
+ [doc_enum_type(Enum,Break) |
+ [doc_enum_type(Type,Break) || #param{type=#type{base={enum,Type}}} <- Ps]];
+doc_enum(_,Ps,Break) ->
+ [doc_enum_type(Type,Break) || #param{type=#type{base={enum,Type}}} <- Ps].
+
+doc_enum_type(Type,Break) ->
+ {Enum0, #enum{vals=Vals}} = wx_gen:get_enum(Type),
+ case Enum0 of {_, Enum} -> Enum; Enum -> Enum end,
+ Consts = get(consts),
+ Format = fun({Name,_What}) ->
+ #const{name=Name} = gb_trees:get(Name, Consts),
+ "?" ++ enum_name(Name)
+ end,
+ Vs = args(Format, " | ", Vals),
+ w("%%~s ~s = integer()~n", [break(Break),uppercase(Enum)]),
+ {uppercase(Enum),Vs}.
+
+doc_enum_desc([]) -> ok;
+doc_enum_desc([{Enum,Vs}|R]) ->
+ w("%%<br /> ~s is one of ~s~n", [Enum,Vs]),
+ doc_enum_desc(R).
+
+%% Misc functions prefixed with wx
+erl_func_name("wx" ++ Name, undefined) -> check_name(lowercase(Name));
+erl_func_name(Name, undefined) -> check_name(lowercase(Name));
+erl_func_name(_, Alias) -> check_name(lowercase(Alias)).
+
+erl_option_name(Name) -> lowercase(Name).
+erl_arg_name(Name) -> uppercase(Name).
+
+check_name("destroy") -> "'Destroy'";
+check_name("xor") -> "'Xor'";
+check_name("~" ++ _Name) -> "destroy";
+check_name(Name) -> Name.
+
+marshal_opts([], _,_) -> ""; %% No opts skip this!
+marshal_opts(Opts, Align, Args) ->
+ w(" MOpts = fun", []),
+ marshal_opts1(Opts,1),
+ w(";~n (BadOpt, _) -> erlang:error({badoption, BadOpt}) end,~n", []),
+ w(" BinOpt = list_to_binary(lists:foldl(MOpts, [<<0:32>>], Options)),~n", []),
+ {Str, _} = align(64, Align, "BinOpt/binary"),
+ case Args of
+ [] -> Str; % All Args are optional
+ _ -> ", " ++ Str
+ end.
+
+marshal_opts1([P],N) ->
+ marshal_opt(P,N);
+marshal_opts1([P|R],N) ->
+ marshal_opt(P,N),
+ w(";~n ", []),
+ marshal_opts1(R,N+1).
+
+marshal_opt(P0=#param{name=Name,type=Type},N) ->
+ P = P0#param{def=none},
+ {Arg,Align} = marshal_arg(Type,erl_arg_name(Name),1),
+ AStr = if Align =:= 0 -> "";
+ Align =:= 1 -> ",0:32"
+ end,
+ w("({~s, ~s}, Acc) -> ", [erl_option_name(Name), func_arg(P)]),
+ arg_type_test(P,"",[]),
+ case Arg of
+ skip ->
+ w("[<<~p:32/?UI~s>>|Acc]", [N, AStr]);
+ _ ->
+ w("[<<~p:32/?UI,~s~s>>|Acc]", [N, Arg,AStr])
+ end.
+marshal_args(Ps) ->
+ marshal_args(Ps, [], 0).
+
+marshal_args([#param{where=erl}|Ps], Margs, Align) ->
+ marshal_args(Ps, Margs, Align);
+marshal_args([#param{name=_N,where=c}|Ps], Margs, Align) ->
+ %% io:format("~p:~p: skip ~p~n",[get(current_class),get(current_func),_N]),
+ marshal_args(Ps, Margs, Align);
+marshal_args([#param{in=false}|Ps], Margs, Align) ->
+ marshal_args(Ps, Margs, Align);
+marshal_args([#param{def=Def}|Ps], Margs, Align) when Def =/= none ->
+ marshal_args(Ps, Margs, Align);
+marshal_args([#param{name=Name, type=Type}|Ps], Margs, Align0) ->
+ {Arg,Align} = marshal_arg(Type,erl_arg_name(Name),Align0),
+ marshal_args(Ps, [Arg|Margs], Align);
+marshal_args([],Margs, Align) ->
+ {args(fun(Str) -> Str end, ",", reverse(Margs)), Align}.
+
+marshal_arg(#type{base={class,_}, single=true}, Name, Align) ->
+ align(32, Align, Name ++ "Ref:32/?UI");
+marshal_arg({merged,_,#type{base={class,_},single=true},_,_,_,_},Name,Align) ->
+ align(32, Align, Name ++ "Ref:32/?UI");
+marshal_arg(#type{base={ref,_}, single=true}, Name, Align) ->
+ align(32, Align, Name ++ "Ref:32/?UI");
+marshal_arg(#type{single=true,base=long}, Name, Align) ->
+ align(64, Align, Name ++ ":64/?UI");
+marshal_arg(#type{single=true,base=float}, Name, Align) ->
+ align(32, Align, Name ++ ":32/?F");
+marshal_arg(#type{single=true,base=double}, Name, Align) ->
+ align(64, Align, Name ++ ":64/?F");
+marshal_arg(#type{single=true,base=int}, Name, Align) ->
+ align(32, Align, Name ++ ":32/?UI");
+marshal_arg(#type{single=true,base={enum,_Enum}}, Name, Align) ->
+ align(32, Align, Name ++ ":32/?UI");
+
+marshal_arg(#type{single=true,base=bool}, Name, Align) ->
+ align(32, Align, "(wxe_util:from_bool(" ++ Name ++ ")):32/?UI");
+marshal_arg(#type{name="wxChar", single=Single}, Name, Align0)
+ when Single =/= true ->
+ {Str,Align} =
+ align(32,Align0, "(byte_size("++Name++"_UC)):32/?UI,(" ++ Name ++ "_UC)/binary"),
+ MsgSize = "(" ++ integer_to_list(Align*4)++"+byte_size("++Name++"_UC))",
+ {Str++", 0:(((8- (" ++ MsgSize ++" band 16#7)) band 16#7))/unit:8",0};
+marshal_arg(#type{base=string}, Name, Align0) ->
+ {Str,Align} =
+ align(32,Align0, "(byte_size("++Name++"_UC)):32/?UI,(" ++ Name ++ "_UC)/binary"),
+ MsgSize = "(" ++ integer_to_list(Align*4)++"+byte_size("++Name++"_UC))",
+ {Str++", 0:(((8- (" ++ MsgSize ++" band 16#7)) band 16#7))/unit:8",0};
+marshal_arg(#type{name="wxArrayString"}, Name, Align0) ->
+ InnerBin = "<<(byte_size(UC_Str)):32/?UI, UC_Str/binary>>",
+ Outer = "(<< " ++ InnerBin ++ "|| UC_Str <- "++ Name ++"_UCA>>)/binary",
+ Str0 = "(length("++Name++"_UCA)):32/?UI, " ++ Outer,
+ {Str,Align} = align(32,Align0,Str0),
+ MsgSize = "("++integer_to_list(Align*4) ++
+ " + lists:sum([byte_size(S)+4||S<-" ++ Name ++"_UCA]))",
+ AStr = ", 0:(((8- (" ++ MsgSize ++" band 16#7)) band 16#7))/unit:8",
+ {Str ++ AStr, 0};
+marshal_arg(#type{single=true,base={comp,"wxColour",_Comp}}, Name, Align0) ->
+ Str = "(wxe_util:colour_bin(" ++ Name ++ ")):16/binary",
+ {Str,Align0};
+marshal_arg(#type{single=true,base={comp,"wxDateTime",_Comp}}, Name, Align) ->
+ {"(wxe_util:datetime_bin(" ++ Name ++ ")):24/binary", Align};
+marshal_arg(#type{single=true,base={comp,_,Comp}}, Name, Align0) ->
+ case hd(Comp) of
+ {int,_} ->
+ A = [Name++Spec++":32/?UI" || {int,Spec} <- Comp],
+ Str = args(fun(Str) -> Str end, ",", A),
+ {Str,(Align0 + length(Comp)) rem 2};
+ {double,_} ->
+ A = [Name++Spec++":64/float" || {double,Spec} <- Comp],
+ Str = args(fun(Str) -> Str end, ",", A),
+ align(64,Align0,Str)
+ end;
+marshal_arg(#type{base={term,_}}, _Name, Align0) ->
+ {skip,Align0};
+marshal_arg(#type{base=binary}, _Name, Align0) ->
+ {skip,Align0};
+marshal_arg(#type{base=Base, single=Single}, Name, Align0)
+ when Single =/= true ->
+ case Base of
+ int ->
+ Str0 = "(length("++Name++")):32/?UI,\n"
+ " (<< <<C:32/?I>> || C <- "++Name++">>)/binary",
+ {Str,Align} = align(32,Align0, Str0),
+ {Str ++ ", 0:((("++integer_to_list(Align)++"+length("++Name++ ")) rem 2)*32)", 0};
+ {ObjRef,_} when ObjRef =:= class; ObjRef =:= ref ->
+ Str0 = "(length("++Name++")):32/?UI,",
+ Str1 = "\n (<< <<(C#wx_ref.ref):32/?UI>> || C <- "++Name++">>)/binary",
+ {Str2,Align} = align(32, Align0, Str1),
+ AlignStr = ", 0:((("++integer_to_list(Align)++"+length("++Name++ ")) rem 2)*32)",
+ {Str0 ++ Str2 ++ AlignStr, 0};
+ {comp, "wxPoint", _} ->
+ Str0 = "(length("++Name++")):32/?UI,\n"
+ " (<< <<X:32/?I,Y:32/?I>> || {X,Y} <- "++Name++">>)/binary",
+ align(32,Align0, Str0);
+ double ->
+ Str0 = "(length("++Name++")):32/?UI,\n",
+ Str1 = " (<< <<C:64/float>> || C <- "++Name++">>)/binary",
+ {Str,_Align} = align(64,Align0+1, Str1),
+ {Str0 ++ Str, 0};
+ _ ->
+ ?error({unhandled_array_type, Base})
+ end;
+marshal_arg(T=#type{name=_wxString}, Name, _Align) ->
+ ?error({unhandled_type, {Name,T}}).
+
+
+align(32, 0, Str) -> {Str, 1};
+align(32, 1, Str) -> {Str, 0};
+align(64, 0, Str) -> {Str, 0};
+align(64, 1, Str) -> {"0:32," ++ Str,0};
+align(Sz, W, Str) -> align(Sz, W rem 2, Str).
+
+enum_name(Name) ->
+ case string:tokens(Name, ":") of
+ [Name] -> Name;
+ [C,N] -> C ++ "_" ++ N
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+gen_enums_ints() ->
+ %% open_write("../include/wx.hrl"), opened in gen_event_recs
+ w("~n%% Hardcoded Records ~n", []),
+ w("-record(wxMouseState, {x, y, %% integer() ~n"
+ " leftDown, middleDown, rightDown, %% bool() ~n"
+ " controlDown, shiftDown, altDown, metaDown, cmdDown %% bool()~n"
+ " }).~n", []),
+ w("-record(wxHtmlLinkInfo, { ~n"
+ " href, target %% string() ~n"
+ " }).~n", []),
+ w("~n%% Hardcoded Defines ~n", []),
+ Enums = [E || E = {{enum,_},#enum{as_atom=false}} <- get()],
+ w("-define(wxDefaultSize, {-1,-1}).~n", []),
+ w("-define(wxDefaultPosition, {-1,-1}).~n", []),
+ w("~n%% Global Variables ~n", []),
+ [w("-define(~s, wxe_util:get_const(~s)).~n", [Gvar, Gvar]) ||
+ {Gvar,_,_Id} <- get(gvars)],
+ w("~n%% Enum and defines ~n", []),
+ foldl(fun({{enum,Type},Enum= #enum{as_atom=false}}, Done) ->
+ build_enum_ints(Type,Enum,Done);
+ (_,Done) -> Done
+ end, gb_sets:empty(), lists:sort(Enums)),
+ close().
+
+build_enum_ints(Type,#enum{vals=Vals},Done) ->
+ case Type of
+ [$@|_] -> ok; % anonymous
+ {Class,[$@|_]} when Vals =/= [] -> w("% From class ~s ~n", [Class]);
+ {Class,Enum} when Vals =/= [] -> w("% From ~s::~s ~n", [Class,Enum]);
+ _ when Vals =/= [] -> w("% Type ~s ~n", [Type]);
+ _ -> ok
+ end,
+
+ Format = fun(#const{name=Name,val=Value,is_const=true}) when is_integer(Value) ->
+ w("-define(~s, ~p).~n", [enum_name(Name),Value]);
+ (#const{name=Name,val=Value,is_const=false}) when is_integer(Value) ->
+ w("-define(~s, wxe_util:get_const(~s)).~n", [enum_name(Name),enum_name(Name)]);
+ (#const{name=Name,val={Str,0}}) ->
+ case string:tokens(Str, " |()") of
+ [Token] ->
+ w("-define(~s, ?~s).~n", [enum_name(Name),Token]);
+ Tokens ->
+ Def = args(fun(T) -> [$?|T] end, " bor ", Tokens),
+ w("-define(~s, (~s)).~n", [enum_name(Name),Def])
+ end;
+ (#const{name=Name,val={Str,N}}) ->
+ case string:tokens(Str, " |()") of
+ [Token] ->
+ w("-define(~s, (?~s+~p)).~n", [enum_name(Name),Token,N])
+ end
+ end,
+ Consts = get(consts),
+ Write = fun({Name,_What}, Skip) ->
+ case gb_sets:is_member(Name,Skip) of
+ true ->
+ Skip;
+ false ->
+ case gb_trees:lookup(Name, Consts) of
+ {value, Const} ->
+ Format(Const),
+ gb_sets:add(Name,Skip);
+ none -> Skip
+ end
+ end
+ end,
+ lists:foldl(Write, Done, Vals).
+
+gen_event_recs() ->
+ open_write("../include/wx.hrl"),
+ erl_copyright(),
+ w("", []),
+ w("%% This file is generated DO NOT EDIT~n~n", []),
+ w("%% All event messages are encapsulated in a wx record ~n"
+ "%% they contain the widget id and a specialized event record.~n"
+ "%% Each event record may be sent for one or more event types.~n"
+ "%% The mapping to wxWidgets is one record per class.~n~n",[]),
+ w("%% @type wx() = #wx{id=integer(), obj=wx:wxObject(), userData=term(), event=Rec}. Rec is a event record.~n",[]),
+ w("-record(wx, {id, %% Integer Identity of object.~n"
+ " obj, %% Object reference that was used in the connect call.~n"
+ " userData, %% User data specified in the connect call.~n"
+ " event}).%% The event record ~n~n",[]),
+ w("%% Here comes the definitions of all event records.~n"
+ "%% they contain the event type and possible some extra information.~n~n",[]),
+ Types = [build_event_rec(C) || {_,C=#class{event=Evs}} <- get(), Evs =/= false],
+ w("%% @type wxEventType() = ~s.~n",
+ [args(fun(Ev) -> Ev end, " | ", lists:sort(lists:append(Types)))]),
+ %% close(), closed in gen_enums_ints
+ ok.
+
+find_inherited_attr(Param = {PName,_}, Name) ->
+ #class{parent=Parent, attributes=Attrs} = get({class, Name}),
+ case lists:keysearch(atom_to_list(PName), #param.name, Attrs) of
+ {value, P=#param{}} ->
+ P;
+ _ ->
+ find_inherited_attr(Param, Parent)
+ end.
+
+filter_attrs(#class{name=Name, parent=Parent,attributes=Attrs}) ->
+ Attr1 = lists:foldl(fun(#param{acc=skip},Acc) -> Acc;
+ (P=#param{prot=public},Acc) -> [P|Acc];
+ (#param{acc=undefined},Acc) -> Acc;
+ ({inherited, PName},Acc) ->
+ case find_inherited_attr(PName, Parent) of
+ undefined ->
+ io:format("~p:~p: Missing Event Attr ~p in ~p~n",
+ [?MODULE,?LINE, PName, Name]),
+ Acc;
+ P ->
+ [P|Acc]
+ end;
+ (P, Acc) -> [P|Acc]
+ end, [], Attrs),
+ lists:reverse(Attr1).
+
+build_event_rec(Class=#class{name=Name, event=Evs}) ->
+ EvTypes = [event_type_name(Ev) || Ev <- Evs],
+ Str = args(fun(Ev) -> "<em>"++Ev++"</em>" end, ", ", EvTypes),
+ Attr = filter_attrs(Class),
+ Rec = event_rec_name(Name),
+ GetName = fun(#param{name=N}) ->event_attr_name(N) end,
+ GetType = fun(#param{name=N,type=T}) ->
+ event_attr_name(N) ++ "=" ++ doc_arg_type2(T)
+ end,
+ case Attr =:= [] of
+ true ->
+ w("%% @type ~s() = #~s{type=wxEventType()}.~n", [Rec,Rec]),
+ w("%% <dl><dt>EventType:</dt> <dd>~s</dd></dl>~n",[Str]),
+%% case is_command_event(Name) of
+%% true -> w("%% This event skips other event handlers.~n",[]);
+%% false -> w("%% This event will be handled by other handlers~n",[])
+%% end,
+ w("%% Callback event: {@link ~s}~n", [Name]),
+ w("-record(~s, {type}). ~n~n", [Rec]);
+ false ->
+ w("%% @type ~s() = #~s{type=wxEventType(),~s}.~n",
+ [Rec,Rec,args(GetType,",",Attr)]),
+ w("%% <dl><dt>EventType:</dt> <dd>~s</dd></dl>~n",[Str]),
+%% case is_command_event(Name) of
+%% true -> w("%% This event skips other event handlers.~n",[]);
+%% false -> w("%% This event will be handled by other handlers~n",[])
+%% end,
+ w("%% Callback event: {@link ~s}~n", [Name]),
+ w("-record(~s,{type, ~s}). ~n~n", [Rec,args(GetName,",",Attr)])
+ end,
+ EvTypes.
+
+is_command_event(Name) ->
+ case lists:member("wxCommandEvent", parents(Name)) of
+ true -> true;
+ false -> false
+ end.
+
+event_rec_name(Name0 = "wx" ++ _) ->
+ "tnevE" ++ Name1 = reverse(Name0),
+ reverse(Name1).
+
+event_type_name({EvN,_,_}) -> event_type_name(EvN);
+event_type_name({EvN,_}) -> event_type_name(EvN);
+event_type_name(EvN) ->
+ "wxEVT_" ++ Ev = atom_to_list(EvN),
+ lowercase_all(Ev).
+
+event_attr_name("m_" ++ Attr) ->
+ lowercase(Attr);
+event_attr_name(Attr) ->
+ lowercase(Attr).
+
+
+gen_funcnames() ->
+ open_write("../src/gen/wxe_debug.hrl"),
+ erl_copyright(),
+ w("%% This file is generated DO NOT EDIT~n~n", []),
+ w("wxdebug_table() -> ~n[~n", []),
+ w(" {0, {wx, internal_batch_start, 0}},~n", []),
+ w(" {1, {wx, internal_batch_end, 0}},~n", []),
+ w(" {4, {wxObject, internal_destroy, 1}},~n", []),
+ Ns = get_unique_names(),
+ [w(" {~p, {~s, ~s, ~p}},~n", [Id,Class,erl_func_name(Name,undefined),A]) || {Class,Name,A,Id} <- Ns],
+ w(" {-1, {mod, func, -1}}~n",[]),
+ w("].~n~n", []),
+ close(),
+ open_write("../src/gen/wxe_funcs.hrl"),
+ erl_copyright(),
+ w("%% This file is generated DO NOT EDIT~n~n", []),
+ w("%% We define each id so we don't get huge diffs when adding new funcs/classes~n~n",[]),
+ [w("-define(~s_~s, ~p).~n", [Class,Name,Id]) || {Class,Name,_,Id} <- Ns],
+ close().
+
+get_unique_name(ID) when is_integer(ID) ->
+ Tree = get(unique_names),
+ {Class,Name, _,_} = gb_trees:get(ID, Tree),
+ Class ++ "_" ++ Name.
+
+get_unique_names() ->
+ Tree = get(unique_names),
+ gb_trees:values(Tree).
+
+gen_unique_names(Defs) ->
+ Names = [ unique_names(Ms, Class) || #class{name=Class, methods=Ms} <- Defs],
+ Data = [{Id, Struct} || Struct = {_,_,_,Id} <- lists:append(Names)],
+ Tree = gb_trees:from_orddict(lists:sort(Data)),
+ put(unique_names, Tree).
+
+unique_names(Ms0, Class) ->
+ Ms1 = [M || M = #method{where = W} <- lists:append(Ms0),
+ W =/= erl_no_opt],
+ Ms2 = lists:keysort(#method.name, Ms1),
+ Ms = split_list(fun(#method{name=N}, M) -> {N =:= M, N} end, undefined, Ms2),
+ unique_names2(Ms,Class).
+%% by Names
+unique_names2([[#method{id=Id, name=Method,alias=Alias, max_arity=A}]|Ms], Class) ->
+ [{Class,uname(alias(Method,Alias),Class),A,Id} | unique_names2(Ms,Class)];
+unique_names2([Ms0|RMs], Class) ->
+ Split = fun(#method{max_arity=A}, P) -> {A =:= P, A} end,
+ Ms = split_list(Split, 0, Ms0),
+ unique_names3(Ms, Class) ++ unique_names2(RMs, Class);
+unique_names2([], _Class) -> [].
+%% by Arity
+unique_names3([[#method{id=Id, name=Method,alias=Alias, max_arity=A}]|Ms], Class) ->
+ [{Class,uname(alias(Method,Alias),Class) ++ "_" ++ integer_to_list(A),A,Id} | unique_names3(Ms,Class)];
+unique_names3([Ms0|RMs], Class) ->
+ unique_names4(Ms0, 0, Class) ++ unique_names3(RMs, Class);
+unique_names3([], _Class) -> [].
+
+unique_names4([#method{id=Id, name=Method,alias=Alias, max_arity=A}|Ms], C, Class) ->
+ [{Class,uname(alias(Method,Alias),Class) ++ "_" ++ integer_to_list(A) ++ "_" ++ integer_to_list(C),A,Id}
+ | unique_names4(Ms,C+1,Class)];
+unique_names4([], _, _Class) -> [].
+
+alias(Method, undefined) -> Method;
+alias(_, Alias) -> Alias.
+
+uname(Class,Class) -> "new";
+uname([$~ | _], _ ) -> "destruct";
+uname(Name, _) -> Name.
+
+split_list(F, Keep, List) ->
+ split_list(F, Keep, List, []).
+
+split_list(F, Keep, [M|Ms], Acc) ->
+ case F(M,Keep) of
+ {true, Test} ->
+ split_list(F, Test, Ms, [M|Acc]);
+ {false, Test} when Acc =:= [] ->
+ split_list(F, Test, Ms, [M]);
+ {false, Test} ->
+ [lists:reverse(Acc)|split_list(F, Test, Ms, [M])]
+ end;
+split_list(_, _, [], []) -> [];
+split_list(_, _, [], Acc) -> [lists:reverse(Acc)].
+
+