175
175
{arity, integer_to_list(A)}],
178
%% <!ELEMENT function (args, typespec?, throws?, equiv?, description?,
179
%% since?, deprecated?, see*, todo?)>
178
%% <!ELEMENT function (args, typespec?, returns?, throws?, equiv?,
179
%% description?, since?, deprecated?, see*, todo?)>
180
180
%% <!ATTLIST function
181
181
%% name CDATA #REQUIRED
182
182
%% arity CDATA #REQUIRED
183
183
%% exported NMTOKEN(yes | no) #REQUIRED
184
184
%% label CDATA #IMPLIED>
185
185
%% <!ELEMENT args (arg*)>
186
%% <!ELEMENT arg description?>
187
%% <!ATTLIST arg name CDATA #REQUIRED>
188
%% <!ELEMENT equiv (expr, see?)>
186
%% <!ELEMENT arg (argName, description?)>
187
%% <!ELEMENT argName (#PCDATA)>
188
%% <!ELEMENT returns (description)>
189
%% <!ELEMENT throws (type, localdef*)>
189
190
%% <!ELEMENT equiv (expr, see?)>
190
191
%% <!ELEMENT expr (#PCDATA)>
192
193
function({N, A}, As, Export, Ts, Env, Opts) ->
193
{As1, Spec} = signature(Ts, As, Env),
194
{Args, Ret, Spec} = signature(Ts, As, Env),
194
195
{function, [{name, atom_to_list(N)},
195
196
{arity, integer_to_list(A)},
196
197
{exported, case Export of
376
382
case get_tags(spec, Ts) of
378
384
Spec = T#tag.data,
385
R = merge_returns(Spec, Ts),
379
386
As0 = edoc_types:arg_names(Spec),
380
As1 = merge_argnames(As0, As), % choose spec before code
381
Spec1 = edoc_types:set_arg_names(Spec, As1),
382
{As1, [edoc_types:to_xml(Spec1, Env)]};
387
Ds0 = edoc_types:arg_descs(Spec),
388
%% choose names in spec before names in code
389
P = dict:from_list(params(Ts)),
390
As1 = merge_args(As0, As, Ds0, P),
391
%% check_params(As1, P),
392
Spec1 = edoc_types:set_arg_names(Spec, [A || {A,_} <- As1]),
393
{As1, R, [edoc_types:to_xml(Spec1, Env)]};
385
{fix_argnames(As, S, 1), []}
388
%% Names are chosen from the first list if possible.
390
merge_argnames(As, As1) ->
391
merge_argnames(As, As1, sets:new(), 1).
393
merge_argnames(['_' | As], ['_' | As1], S, N) ->
395
[A | merge_argnames(As, As1, sets:add_element(A, S), N + 1)];
396
merge_argnames(['_' | As], [A | As1], S, N) ->
397
[A | merge_argnames(As, As1, sets:add_element(A, S), N + 1)];
398
merge_argnames([A | As], [_ | As1], S, N) ->
399
[A | merge_argnames(As, As1, sets:add_element(A, S), N + 1)];
400
merge_argnames([], [], _S, _N) ->
396
{fix_argnames(As, S, 1), [], []}
400
[T#tag.data || T <- get_tags(param, Ts)].
402
%% check_params(As, P) ->
403
%% case dict:keys(P) -- [N || {N,_} <- As] of
405
%% Ps -> error %% TODO: report @param declarations with no match
408
merge_returns(Spec, Ts) ->
409
case get_tags(return, Ts) of
411
case edoc_types:range_desc(Spec) of
418
%% Names are chosen from the first list (the specification) if possible.
419
%% Descriptions specified with @param (in P dict) override descriptions
420
%% from the spec (in Ds).
422
merge_args(As, As1, Ds, P) ->
423
merge_args(As, As1, Ds, [], P, sets:new(), 1).
425
merge_args(['_' | As], ['_' | As1], [D | Ds], Rs, P, S, N) ->
426
merge_args(As, As1, Ds, Rs, P, S, N, make_name(N, S), D);
427
merge_args(['_' | As], [A | As1], [D | Ds], Rs, P, S, N) ->
428
merge_args(As, As1, Ds, Rs, P, S, N, A, D);
429
merge_args([A | As], [_ | As1], [D | Ds], Rs, P, S, N) ->
430
merge_args(As, As1, Ds, Rs, P, S, N, A, D);
431
merge_args([], [], [], Rs, _P, _S, _N) ->
434
merge_args(As, As1, Ds, Rs, P, S, N, A, D0) ->
435
D = case dict:find(A, P) of
437
error when D0 == [] -> []; % no description
438
error -> [D0] % a simple-xml text element
440
merge_args(As, As1, Ds, [{A, D} | Rs], P,
441
sets:add_element(A, S), N + 1).
403
443
fix_argnames(['_' | As], S, N) ->
404
444
A = make_name(N, S),