1%% =====================================================================
2%% Licensed under the Apache License, Version 2.0 (the "License"); you may
3%% not use this file except in compliance with the License. You may obtain
4%% a copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>
5%%
6%% Unless required by applicable law or agreed to in writing, software
7%% distributed under the License is distributed on an "AS IS" BASIS,
8%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9%% See the License for the specific language governing permissions and
10%% limitations under the License.
11%%
12%% Alternatively, you may use this file under the terms of the GNU Lesser
13%% General Public License (the "LGPL") as published by the Free Software
14%% Foundation; either version 2.1, or (at your option) any later version.
15%% If you wish to allow use of your version of this file only under the
16%% terms of the LGPL, you should delete the provisions above and replace
17%% them with the notice and other provisions required by the LGPL; see
18%% <http://www.gnu.org/licenses/>. If you do not delete the provisions
19%% above, a recipient may use your version of this file under the terms of
20%% either the Apache License or the LGPL.
21%%
22%% @private
23%% @copyright 2001-2005 Richard Carlsson
24%% @author Richard Carlsson <carlsson.richard@gmail.com>
25%% @see edoc
26%% @end
27%% =====================================================================
28
29%% @doc EDoc macro expansion
30
31-module(edoc_macros).
32
33-export([expand_tags/3, std_macros/1, check_defs/1]).
34
35-include("edoc.hrl").
36-include("edoc_types.hrl").
37
38-define(DEFAULT_XML_EXPORT, xmerl_html).
39
40
41std_macros(Env) ->
42    (if Env#env.module =:= [] -> [];
43	true -> [{module, atom_to_list(Env#env.module)}]
44     end
45     ++
46     [{date, fun date_macro/3},
47      {docRoot, Env#env.root},
48      {link, fun link_macro/3},
49      {section, fun section_macro/3},
50      {time, fun time_macro/3},
51      {type, fun type_macro/3},
52      {version, fun version_macro/3}]).
53
54
55%% Check well-formedness of user-specified list of macro definitions.
56
57check_defs([{K, D} | Ds]) when is_atom(K), is_list(D) ->
58    check_defs(Ds);
59check_defs([{K, D} | Ds]) when is_atom(K), is_function(D, 3) ->
60    check_defs(Ds);
61check_defs([X | _Ds]) ->
62    edoc_report:report("bad macro definition: ~P.", [X, 10]),
63    exit(error);
64check_defs([]) ->
65    ok.
66
67%% Code for special macros should throw {error, Line, Reason} for error
68%% reporting, where Reason and Line are passed to edoc_report:error(...)
69%% together with the file name etc. The expanded text must be flat!
70
71date_macro(_S, _Line, _Env) ->
72    edoc_lib:datestr(date()).
73
74time_macro(_S, _Line, _Env) ->
75    edoc_lib:timestr(time()).
76
77version_macro(S, Line, Env) ->
78    date_macro(S, Line, Env)
79	++ " " ++ time_macro(S, Line, Env).
80
81link_macro(S, Line, Env) ->
82    {S1, S2} = edoc_lib:split_at_stop(S),
83    Ref = edoc_parser:parse_ref(S1, Line),
84    {DocgenRel, DocgenURI} = edoc_refs:get_docgen_link(Ref),
85    URI = edoc_refs:get_uri(Ref, Env),
86    Txt = if S2 =:= [] -> "<code>" ++ S1 ++ "</code>";
87	     true -> S2
88	  end,
89    Target = case edoc_refs:is_top(Ref, Env) of
90		 true -> " target=\"_top\""; % note the initial space
91		 false -> ""
92	     end,
93    lists:flatten(io_lib:fwrite("<a docgen-rel=\"~ts\" docgen-href=\"~ts\" href=\"~ts\"~ts>~ts</a>",
94				[DocgenRel, DocgenURI, URI, Target, Txt])).
95
96section_macro(S, _Line, _Env) ->
97    S1 = lists:reverse(edoc_lib:strip_space(
98			 lists:reverse(edoc_lib:strip_space(S)))),
99    lists:flatten(io_lib:format("<a href=\"#~ts\">~ts</a>",
100				[edoc_lib:to_label(S1), S1])).
101
102type_macro(S, Line, Env) ->
103    S1 = "t()=" ++ S,
104    Def = edoc_parser:parse_typedef(S1, Line),
105    {#t_typedef{type = T}, _} = Def,
106    Txt = edoc_layout:type(edoc_data:type(T, Env)),
107    lists:flatten(io_lib:fwrite("<code>~ts</code>", [Txt])).
108
109
110%% Expand inline macros in tag content.
111
112expand_tags(Ts, Env, Where) ->
113    Defs = dict:from_list(lists:reverse(Env#env.macros)),
114    expand_tags(Ts, Defs, Env, Where).
115
116expand_tags([#tag{data = Cs, line = L} = T | Ts], Defs, Env, Where) ->
117    [T#tag{data = expand_tag(Cs, L, Defs, Env, Where)}
118     | expand_tags(Ts, Defs, Env, Where)];
119expand_tags([T | Ts], Defs, Env, Where) ->
120    [T | expand_tags(Ts, Defs, Env, Where)];
121expand_tags([], _, _, _) ->
122    [].
123
124expand_tag(Cs, L, Defs, Env, Where) ->
125    case catch {ok, expand_text(Cs, L, Defs, Env, Where)} of
126 	{ok, Cs1} ->
127	    lists:reverse(Cs1);
128 	{'EXIT', R} ->
129	    exit(R);
130	{error, L1, Error} ->
131	    edoc_report:error(L1, Where, Error),
132	    exit(error);
133	Other ->
134	    throw(Other)
135    end.
136
137%% Expand macros in arbitrary lines of text.
138%% The result is in reverse order.
139
140-record(state, {where, env, seen}).
141
142expand_text(Cs, L, Defs, Env, Where) ->
143    St = #state{where = Where,
144		env = Env,
145		seen = sets:new()},
146    expand(Cs, L, Defs, St, []).
147
148%% Inline macro syntax: "{@name content}"
149%%   where 'content' is optional, and separated from 'name' by one or
150%%   more whitespace characters. The content is bound to the '{@?}'
151%%   parameter variable, and the macro definition is expanded and
152%%   substituted for the call. Recursion is detected and reported as an
153%%   error, since there are (currently) no control flow operators.
154%% Escape sequences:
155%%   "@{" -> "{"
156%%   "@}" -> "}"
157%%   "@@" -> "@"
158
159expand([$@, $@ | Cs], L, Defs, St, As) ->
160    expand(Cs, L, Defs, St, [$@ | As]);
161expand([$@, ${ | Cs], L, Defs, St, As) ->
162    expand(Cs, L, Defs, St, [${ | As]);
163expand([$@, $} | Cs], L, Defs, St, As) ->
164    expand(Cs, L, Defs, St, [$} | As]);
165expand([${, $@ | Cs], L, Defs, St, As) ->
166    expand_macro(Cs, L, Defs, St, As);
167expand([$\n = C | Cs], L, Defs, St, As) ->
168    expand(Cs, L + 1, Defs, St, [C | As]);
169expand([C | Cs], L, Defs, St, As) ->
170    expand(Cs, L, Defs, St, [C | As]);
171expand([], _, _, _, As) ->
172    As.
173
174expand_macro(Cs, L, Defs, St, As) ->
175    {M, Cs1, L1} = macro_name(Cs, L),
176    {Arg, Cs2, L2} = macro_content(Cs1, L1),
177    As1 = expand_macro_def(M, Arg, L, Defs, St, As),
178    expand(Cs2, L2, Defs, St, As1).
179
180%% The macro argument (the "content") is expanded in the environment of
181%% the call, and the result is bound to the '{@?}' parameter. The result
182%% of the macro expansion is then expanded again. This allows macro
183%% definitions to contain calls to other macros, avoids name capture of
184%% '{@?}', and makes it easier to write handler functions for special
185%% macros such as '{@link ...}', since the argument is already expanded.
186
187expand_macro_def(M, Arg, L, Defs, St, As) ->
188    Seen = St#state.seen,
189    case sets:is_element(M, Seen) of
190	true ->
191	    throw_error(L, {"recursive macro expansion of {@~s}.",
192			    [M]});
193	false ->
194	    Arg1 = lists:reverse(expand(Arg, L, Defs, St, [])),
195	    Defs1 = dict:store('?', Arg1, Defs),
196	    St1 = St#state{seen = sets:add_element(M, Seen)},
197	    case dict:find(M, Defs) of
198		{ok, Def} ->
199		    Txt = if is_function(Def) ->
200				  Def(Arg1, L, St1#state.env);
201			     is_list(Def) ->
202				  Def
203			  end,
204		    expand(Txt, L, Defs1, St1, As);
205		error ->
206		    edoc_report:warning(L, St1#state.where,
207					"undefined macro {@~s}.", [M]),
208		    "??"
209	    end
210    end.
211
212%% The macro name ends at the first whitespace or '}' character.  The
213%% content, if any, starts at the next non-whitespace character.
214
215%% See edoc_tags:scan_tag/is_name/1 for details on what is a valid
216%% name. In macro names we also allow '?' as the initial character.
217
218macro_name(Cs, L) ->
219    macro_name(Cs, [], L).
220
221macro_name([C | Cs], As, L) when C >= $a, C =< $z ->
222    macro_name_1(Cs, [C | As], L);
223macro_name([C | Cs], As, L) when C >= $A, C =< $Z ->
224    macro_name_1(Cs, [C | As], L);
225macro_name([C | Cs], As, L) when C >= $\300, C =< $\377,
226				 C =/= $\327, C =/= $\367 ->
227    macro_name_1(Cs, [C | As], L);
228macro_name([$_ | Cs], As, L) ->
229    macro_name_1(Cs, [$_ | As], L);
230macro_name([$? | Cs], As, L) ->
231    macro_name_1(Cs, [$? | As], L);
232macro_name([$\s | _Cs], _As, L) ->
233    throw_error(L, macro_name);
234macro_name([$\t | _Cs], _As, L) ->
235    throw_error(L, macro_name);
236macro_name([$\n | _Cs], _As, L) ->
237    throw_error(L, macro_name);
238macro_name([C | _Cs], As, L) ->
239    throw_error(L, {macro_name, [C | As]});
240macro_name([], _As, L) ->
241    throw_error(L, macro_name).
242
243macro_name_1([C | Cs], As, L) when C >= $a, C =< $z ->
244    macro_name_1(Cs, [C | As], L);
245macro_name_1([C | Cs], As, L) when C >= $A, C =< $Z ->
246    macro_name_1(Cs, [C | As], L);
247macro_name_1([C | Cs], As, L) when C >= $0, C =< $9 ->
248    macro_name_1(Cs, [C | As], L);
249macro_name_1([C | Cs], As, L) when C >= $\300, C =< $\377,
250				   C =/= $\327, C =/= $\367 ->
251    macro_name_1(Cs, [C | As], L);
252macro_name_1([$_ | Cs], As, L) ->
253    macro_name_1(Cs, [$_ | As], L);
254macro_name_1([$\s | Cs], As, L) ->
255    macro_name_2(Cs, As, L);
256macro_name_1([$\t | Cs], As, L) ->
257    macro_name_2(Cs, As, L);
258macro_name_1([$\n | Cs], As, L) ->
259    macro_name_2(Cs, As, L + 1);
260macro_name_1([$} | _] = Cs, As, L) ->
261    macro_name_3(Cs, As, L);
262macro_name_1([C | _Cs], As, L) ->
263    throw_error(L, {macro_name, [C | As]});
264macro_name_1([], _As, L) ->
265    throw_error(L, unterminated_macro).
266
267macro_name_2([$\s | Cs], As, L) ->
268    macro_name_2(Cs, As, L);
269macro_name_2([$\t | Cs], As, L) ->
270    macro_name_2(Cs, As, L);
271macro_name_2([$\n | Cs], As, L) ->
272    macro_name_2(Cs, As, L + 1);
273macro_name_2([_ | _] = Cs, As, L) ->
274    macro_name_3(Cs, As, L);
275macro_name_2([], _As, L) ->
276    throw_error(L, unterminated_macro).
277
278macro_name_3(Cs, As, L) ->
279    {list_to_atom(lists:reverse(As)), Cs, L}.
280
281
282%% The macro content ends at the first non-escaped '}' character that is
283%% not balanced by a corresponding non-escaped '{@' sequence.
284%% Escape sequences are those defined above.
285
286macro_content(Cs, L) ->
287    %% If there is an error, we report the start line, not the end line.
288    case catch {ok, macro_content(Cs, [], L, 0)} of
289	{ok, X} ->
290	    X;
291	{'EXIT', R} ->
292	    exit(R);
293	'end' ->
294	    throw_error(L, unterminated_macro);
295	Other ->
296	    throw(Other)
297    end.
298
299%% @throws 'end'
300
301macro_content([$@, $@ | Cs], As, L, N) ->
302    macro_content(Cs, [$@, $@ | As], L, N);  % escaped '@'
303macro_content([$@, $} | Cs], As, L, N) ->
304    macro_content(Cs, [$}, $@ | As], L, N);  % escaped '}'
305macro_content([$@, ${ | Cs], As, L, N) ->
306    macro_content(Cs, [${, $@ | As], L, N);  % escaped '{'
307macro_content([${, $@ | Cs], As, L, N) ->
308    macro_content(Cs, [$@, ${ | As], L, N + 1);
309macro_content([$} | Cs], As, L, 0) ->
310    {lists:reverse(As), Cs, L};
311macro_content([$} | Cs], As, L, N) ->
312    macro_content(Cs, [$} | As], L, N - 1);
313macro_content([$\n = C | Cs], As, L, N) ->
314    macro_content(Cs, [C | As], L + 1, N);
315macro_content([C | Cs], As, L, N) ->
316    macro_content(Cs, [C | As], L, N);
317macro_content([], _As, _L, _N) ->
318    throw('end').
319
320-type line() :: erl_anno:line().
321-type err()  :: 'unterminated_macro'
322	      | 'macro_name'
323	      | {'macro_name', string()}
324	      | {string(), [string()]}.
325
326-spec throw_error(line(), err()) -> no_return().
327
328throw_error(L, unterminated_macro) ->
329    throw_error(L, {"unexpected end of macro.", []});
330throw_error(L, macro_name) ->
331    throw_error(L, {"missing macro name.", []});
332throw_error(L, {macro_name, S}) ->
333    throw_error(L, {"bad macro name: '@~s...'.", [lists:reverse(S)]});
334throw_error(L, D) ->
335    throw({error, L, D}).
336