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