diff options
Diffstat (limited to 'lib/erl_docgen')
-rw-r--r-- | lib/erl_docgen/Makefile | 19 | ||||
-rw-r--r-- | lib/erl_docgen/ebin/.gitignore | 0 | ||||
-rw-r--r-- | lib/erl_docgen/priv/bin/specs_gen.escript | 129 | ||||
-rwxr-xr-x | lib/erl_docgen/priv/bin/xref_mod_app.escript | 107 | ||||
-rw-r--r-- | lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd | 7 | ||||
-rw-r--r-- | lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd | 2 | ||||
-rw-r--r-- | lib/erl_docgen/priv/xsl/db_html.xsl | 626 | ||||
-rw-r--r-- | lib/erl_docgen/priv/xsl/db_man.xsl | 338 | ||||
-rw-r--r-- | lib/erl_docgen/priv/xsl/db_pdf.xsl | 486 | ||||
-rw-r--r-- | lib/erl_docgen/src/Makefile | 96 | ||||
-rw-r--r-- | lib/erl_docgen/src/erl_docgen.app.src | 12 | ||||
-rw-r--r-- | lib/erl_docgen/src/erl_docgen.appup.src | 1 | ||||
-rw-r--r-- | lib/erl_docgen/src/otp_specs.erl | 701 |
13 files changed, 2269 insertions, 255 deletions
diff --git a/lib/erl_docgen/Makefile b/lib/erl_docgen/Makefile index c5bed632a5..93a6353cac 100644 --- a/lib/erl_docgen/Makefile +++ b/lib/erl_docgen/Makefile @@ -1,19 +1,20 @@ -# ``The contents of this file are subject to the Erlang Public License, +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2010. 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 via the world wide web at http://www.erlang.org/. +# 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. # -# The Initial Developer of the Original Code is Ericsson Utvecklings AB. -# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ +# %CopyrightEnd% # include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk @@ -22,9 +23,11 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Macros # -SUB_DIRECTORIES = priv +SUB_DIRECTORIES = src priv #doc/src +include vsn.mk +VSN = $(ERL_DOCGEN_VSN) SPECIAL_TARGETS = diff --git a/lib/erl_docgen/ebin/.gitignore b/lib/erl_docgen/ebin/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/erl_docgen/ebin/.gitignore diff --git a/lib/erl_docgen/priv/bin/specs_gen.escript b/lib/erl_docgen/priv/bin/specs_gen.escript new file mode 100644 index 0000000000..840fed6dd5 --- /dev/null +++ b/lib/erl_docgen/priv/bin/specs_gen.escript @@ -0,0 +1,129 @@ +#!/usr/bin/env escript +%% -*- erlang -*- +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. 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% + +%%% <script> [-I<dir>]... [-o<dir>] [-module Module] [File] +%%% +%%% Use EDoc and the layout module 'otp_specs' to create an XML file +%%% containing Dialyzer types and specifications (-type, -spec). +%%% +%%% Options: +%%% +%%% "-o<dir>" The output directory for the created file. +%%% Default is ".". +%%% "-I<dir>" Directory to be searched when including a file. +%%% "-module Module" +%%% Module name to use when there is no File argument. +%%% A temporary file will be created. +%%% Exactly one of -module Module and File must be given. +%%% +%%% The name of the generated file is "specs_<module>.xml". Its exact +%%% format is not further described here. + +main(Args) -> + case catch parse(Args, [], ".", no_module) of + {ok, FileSpec, InclFs, Dir} -> + call_edoc(FileSpec, InclFs, Dir); + {error, Msg} -> + io:format("~s\n", [Msg]), + usage() + end. + +parse(["-o"++Dir | Opts], InclFs, _, Module) -> + parse(Opts, InclFs, Dir, Module); +parse(["-I"++I | Opts], InclFs, Dir, Module) -> + parse(Opts, [I | InclFs], Dir, Module); +parse(["-module", Module | Opts], InclFs, Dir, _) -> + parse(Opts, InclFs, Dir, Module); +parse([File], InclFs, Dir, no_module) -> + {ok, {file, File}, lists:reverse(InclFs), Dir}; +parse([_], _, _, _) -> + {error, io_lib:format("Cannot have both -module option and file", [])}; +parse([], _, _, no_module) -> + {error, io_lib:format("Missing -module option or file", [])}; +parse([], InclFs, Dir, Module) -> + {ok, {module, Module}, lists:reverse(InclFs), Dir}; +parse(Args, _, _, _) -> + {error, io_lib:format("Bad arguments: ~p", [Args])}. + +usage() -> + io:format("usage: ~s [-I<include_dir>]... [-o<out_dir>] " + "[-module <module>] [file]\n", [escript:script_name()]), + halt(1). + +call_edoc(FileSpec, InclFs, Dir) -> + Incl = [{includes, InclFs}], + Pre = [{preprocess, true}], + Choice = [{dialyzer_specs, all}], + DirOpt = [{dir, Dir}], + Pretty = [{pretty_print, erl_pp}], + Layout = [{layout, otp_specs}, + {file_suffix, ".specs"}, + {stylesheet, ""}], + Warn = [{report_missing_type, false}, + {report_type_mismatch, false}], + OptionList = (DirOpt ++ Choice ++ Pre ++ Warn ++ Pretty ++ Layout ++ Incl), + {File, TmpFile} = case FileSpec of + {file, File0} -> + {File0, false}; + {module, Module} -> + {create_tmp_file(Dir, Module), true} + end, + try edoc:files([File], OptionList) of + ok -> + clean_up(Dir, File, TmpFile), + rename(Dir, File) + catch + _:_ -> + io:format("EDoc could not process file '~s'\n", [File]), + clean_up(Dir, File, TmpFile), + halt(3) + end. + +rename(Dir, F) -> + Mod = filename:basename(F, ".erl"), + Old = filename:join(Dir, Mod ++ ".specs"), + New = filename:join(Dir, "specs_" ++ Mod ++ ".xml"), + case file:rename(Old, New) of + ok -> + ok; + {error, R} -> + R1 = file:format_error(R), + io:format("could not rename file '~s': ~s\n", [New, R1]), + halt(2) + end. + +clean_up(Dir, File, TmpFile) -> + [file:delete(File) || TmpFile], + _ = [file:delete(filename:join(Dir, F)) || + F <- ["packages-frame.html", + "overview-summary.html", + "modules-frame.html", + "index.html", "erlang.png", "edoc-info"]], + ok. + +create_tmp_file(Dir, Module) -> + TmpFile = filename:join(Dir, Module++".erl"), + case file:write_file(TmpFile, "-module(" ++ Module ++ ").\n") of + ok -> + TmpFile; + {error, R} -> + R1 = file:format_error(R), + io:format("could not write file '~s': ~s\n", [TmpFile, R1]), + halt(2) + end. diff --git a/lib/erl_docgen/priv/bin/xref_mod_app.escript b/lib/erl_docgen/priv/bin/xref_mod_app.escript new file mode 100755 index 0000000000..fcc3a96ada --- /dev/null +++ b/lib/erl_docgen/priv/bin/xref_mod_app.escript @@ -0,0 +1,107 @@ +#!/usr/bin/env escript +%% -*- erlang -*- +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. 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% + +%%% Find all applications and all modules given a root directory. +%%% Output an XML file that can be used for finding which application +%%% a given module belongs to. +%%% +%%% Options: +%%% +%%% "-topdir <D>" Applications are found under D/lib/. +%%% The default value is $ERL_TOP. +%%% +%%% "-outfile <F>" Output is written onto F. +%%% The default value is "mod2app.xml". +%%% +%%% The output file has the following format: +%%% +%%% <?xml version="1.0"?> +%%% <mod2app> +%%% <module name="ModName1">AppName1</module> +%%% ... +%%% <mod2app> +%%% +%%% meaning that module ModName1 resides in application AppName1. + +main(Args) -> + case catch parse(Args, os:getenv("ERL_TOP"), "mod2app.xml") of + {ok, TopDir, OutFile} -> + case modapp(TopDir) of + [] -> + io:format("no applications found\n"), + halt(3); + MA -> + Layout = layout(MA), + XML = xmerl:export_simple(Layout, xmerl_xml), + write_file(XML, OutFile) + end; + {error, Msg} -> + io:format("~s\n", [Msg]), + usage() + end. + +parse(["-topdir", TopDir | Opts], _, OutFile) -> + parse(Opts, TopDir, OutFile); +parse(["-outfile", OutFile | Opts], TopDir, _) -> + parse(Opts, TopDir, OutFile); +parse([], TopDir, OutFile) -> + {ok, TopDir, OutFile}; +parse([Opt | _], _, _) -> + {error, io_lib:format("Bad option: ~p", [Opt])}. + +usage() -> + io:format("usage: ~s [-topdir <dir>] [-outfile <file>]\n", + [escript:script_name()]), + halt(1). + +modapp(TopDir) -> + AppDirs = filelib:wildcard(filename:join([TopDir,"lib","*"])), + AM = [appmods(D) || D <- AppDirs], + lists:keysort(1, [{M,A} || {A,Ms} <- AM, M <- Ms]). + +%% It's OK if too much data is generated as long as all applications +%% and all modules are mentioned. +appmods(D) -> + ErlFiles = filelib:wildcard(filename:join([D,"src","*.erl"])), + AppV = filename:basename(D), + App = case string:rstr(AppV, "-") of + 0 -> AppV; + P -> string:sub_string(AppV, 1, P-1) + end, + {App, [filename:basename(EF, ".erl") || EF <- ErlFiles]}. + +-include_lib("xmerl/include/xmerl.hrl"). + +-define(IND(N), lists:duplicate(N, $\s)). +-define(NL, "\n"). + +layout(MAL) -> + ML = lists:append([[?IND(2),{module,[{name,M}],[A]},?NL] || {M,A} <- MAL]), + [?NL,{mod2app,[?NL|ML]},?NL]. + +write_file(Text, File) -> + case file:open(File, [write]) of + {ok, FD} -> + io:put_chars(FD, Text), + ok = file:close(FD); + {error, R} -> + R1 = file:format_error(R), + io:format("could not write file '~s': ~s\n", [File, R1]), + halt(2) + end. diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd b/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd index 7b9974fbda..c1237766e1 100644 --- a/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd +++ b/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd @@ -26,15 +26,18 @@ <!ELEMENT description (%block;|quote|br|marker|warning|note)* > <!ELEMENT funcs (func)+ > -<!ELEMENT func (name+,fsummary,type?,desc?) > +<!ELEMENT func (name+,type_desc+,fsummary,type?,desc?) > <!-- ELEMENT name is defined in each ref dtd --> <!ELEMENT fsummary (#PCDATA|c|em)* > <!ELEMENT type (v,d?)+ > <!ELEMENT v (#PCDATA) > <!ELEMENT d (#PCDATA|c|em)* > -<!ELEMENT desc (%block;|quote|br|marker|warning|note)* > +<!ELEMENT desc (%block;|quote|br|marker|warning|note|anno)* > <!ELEMENT authors (aname,email)+ > <!ELEMENT aname (#PCDATA) > <!ELEMENT email (#PCDATA) > <!ELEMENT section (marker*,title,(%block;|quote|br|marker| warning|note)*) > +<!ELEMENT datatypes (datatype)+ > +<!ELEMENT datatype (name+,desc?) > +<!ELEMENT type_desc (#PCDATA) > diff --git a/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd b/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd index 21656a1446..9905086ff4 100644 --- a/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd +++ b/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd @@ -22,7 +22,7 @@ %common.refs; <!ELEMENT erlref (header,module,modulesummary,description, - (section|funcs)*,authors?) > + (section|funcs|datatypes)*,authors?) > <!ELEMENT module (#PCDATA) > <!ELEMENT modulesummary (#PCDATA) > diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl index bba0f97645..732560e303 100644 --- a/lib/erl_docgen/priv/xsl/db_html.xsl +++ b/lib/erl_docgen/priv/xsl/db_html.xsl @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- +<!-- # # %CopyrightBegin% # @@ -17,15 +17,315 @@ # under the License. # # %CopyrightEnd% - + --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" - xmlns:fn="http://www.w3.org/2005/02/xpath-functions"> + xmlns:fn="http://www.w3.org/2005/02/xpath-functions"> <xsl:include href="db_html_params.xsl"/> + <!-- Start of Dialyzer type/spec tags. + See also the template matching "name" and the template "menu.funcs" + --> + + <xsl:param name="specs_file" select="''"/> + <xsl:variable name="i" select="document($specs_file)"></xsl:variable> + + <xsl:param name="mod2app_file" select="''"/> + <xsl:variable name="m2a" select="document($mod2app_file)"></xsl:variable> + <xsl:key name="mod2app" match="module" use="@name"/> + + <xsl:template name="err"> + <xsl:param name="m"/> + <xsl:param name="n"/> + <xsl:param name="a"/> + <xsl:param name="s"/> + <xsl:message terminate="yes"> + Error <xsl:if test="$m != ''"><xsl:value-of select ="$m"/>:</xsl:if> + <xsl:value-of + select="$n"/>/<xsl:value-of + select="$a"/>: <xsl:value-of select="$s"/> + </xsl:message> + </xsl:template> + + <xsl:template name="spec_name"> + <xsl:variable name="curModule" select="ancestor::erlref/module"/> + <xsl:variable name="mod" select="@mod"/> + <xsl:variable name="name" select="@name"/> + <xsl:variable name="arity" select="@arity"/> + <xsl:variable name="clause" select="@clause"/> + <xsl:variable name="spec0" select= + "$i/specs/module[@name=$curModule]/spec + [name=$name and arity=$arity + and (string-length($mod) = 0 or module = $mod)]"/> + <xsl:variable name="spec" select="$spec0[string-length($clause) = 0 + or position() = $clause]"/> + <xsl:if test="count($spec) = 0"> + <xsl:call-template name="err"> + <xsl:with-param name="m" select="$mod"/> + <xsl:with-param name="n" select="$name"/> + <xsl:with-param name="a" select="$arity"/> + <xsl:with-param name="s">unknown spec</xsl:with-param> + </xsl:call-template> + </xsl:if> + + <xsl:variable name="arity_clause"> + <xsl:choose> + <xsl:when test="string-length(@clause) > 0"> + <xsl:value-of select="@arity"/>/<xsl:value-of select="@clause"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@arity"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:choose> + <xsl:when test="ancestor::cref"> + <xsl:message terminate="yes"> + Error: did not expect a 'name' tag with name/arity attributes here! + </xsl:message> + </xsl:when> + <xsl:when test="ancestor::erlref"> + <a name="{$name}-{$arity_clause}"></a> + <xsl:choose> + <xsl:when test="string(@with_guards) = 'no'"> + <xsl:apply-templates select="$spec/contract/clause/head"/> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="contract"> + <xsl:with-param name="contract" select="$spec/contract"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + </xsl:choose> + </xsl:template> + + <xsl:template name="contract"> + <xsl:param name="contract"/> + <xsl:call-template name="clause"> + <xsl:with-param name="clause" select="$contract/clause"/> + </xsl:call-template> + </xsl:template> + + <xsl:template name="clause"> + <xsl:param name="clause"/> + <xsl:variable name="type_desc" select="../type_desc"/> + <xsl:for-each select="$clause"> + <xsl:apply-templates select="head"/> + <xsl:if test="count(guard) > 0"> + <xsl:call-template name="guard"> + <xsl:with-param name="guard" select="guard"/> + <xsl:with-param name="type_desc" select="$type_desc"/> + </xsl:call-template> + </xsl:if> + </xsl:for-each> + </xsl:template> + + <xsl:template match="head"> + <span class="bold_code"> + <xsl:apply-templates/> + </span> + <br/> + </xsl:template> + + <xsl:template name="guard"> + <xsl:param name="guard"/> + <xsl:param name="type_desc"/> + <div class="REFBODY"><p>Types:</p> + <xsl:call-template name="subtype"> + <xsl:with-param name="subtype" select="$guard/subtype"/> + <xsl:with-param name="type_desc" select="$type_desc"/> + </xsl:call-template> + </div> + </xsl:template> + + <xsl:template name="subtype"> + <xsl:param name="subtype"/> + <xsl:param name="type_desc"/> + <xsl:for-each select="$subtype"> + <xsl:variable name="tname" select="typename"/> + <xsl:variable name="tdesc" select="$type_desc[@name = $tname]"/> + <div class="REFTYPES"> + <span class="bold_code"> + <xsl:apply-templates select="string"/> + </span> + </div> + <xsl:apply-templates select="$type_desc[@name = $tname]"/> + </xsl:for-each> + </xsl:template> + + <!-- Note: <type_desc> has not been implemented for data types. --> + + <!-- Similar to <d> --> + <xsl:template match="type_desc"> + <div class="REFBODY"> + <xsl:apply-templates/> + </div> + </xsl:template> + + <!-- This is for debugging. All modules! --> + <xsl:template match="all_etypes"> + <xsl:for-each select= "$i//type"> + <pre> + <span class="bold_code"> + <xsl:apply-templates select="typedecl"/> + </span><xsl:text> +</xsl:text> + </pre> + </xsl:for-each> + </xsl:template> + + <!-- Datatypes --> + <xsl:template match="datatypes"> + <h3> + <xsl:text>DATA TYPES</xsl:text> + </h3> + <xsl:apply-templates/> + </xsl:template> + + <!-- Datatype --> + <xsl:template match="datatype"> + <p><xsl:apply-templates select="name"/></p> + <xsl:apply-templates select="desc"/> + </xsl:template> + + <xsl:template match="typehead"> + <span class="bold_code"> + <xsl:apply-templates/> + </span><br/> + </xsl:template> + + <!-- local_defs --> + <xsl:template match="local_defs"> + <div class="REFBODY"> + <xsl:apply-templates> + </xsl:apply-templates> + </div> + </xsl:template> + + <xsl:template match="local_def"> + <div class="REFTYPES"> + <span class="bold_code"> + <xsl:apply-templates/> + </span> + </div> + </xsl:template> + + <xsl:template name="type_name"> + <xsl:variable name="curModule" select="ancestor::erlref/module"/> + <xsl:variable name="mod" select="@mod"/> + <xsl:variable name="name" select="@name"/> + <xsl:variable name="n_vars"> + <xsl:choose> + <xsl:when test="string-length(@n_vars) > 0"> + <xsl:value-of select="@n_vars"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="0"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:choose> + <xsl:when test="string-length($name) > 0"> + <xsl:variable name="type" select= + "$i/specs/module[@name=$curModule]/type + [name=$name and n_vars=$n_vars + and (string-length($mod) = 0 or module = $mod)]"/> + + <xsl:if test="count($type) != 1"> + <xsl:call-template name="err"> + <xsl:with-param name="m" select="$mod"/> + <xsl:with-param name="n" select="$name"/> + <xsl:with-param name="a" select="$n_vars"/> + <xsl:with-param name="s">unknown type</xsl:with-param> + </xsl:call-template> + </xsl:if> + <xsl:apply-templates select="$type/typedecl"/> + </xsl:when> + <xsl:otherwise> + <span class="bold_code"> + <xsl:value-of select="."/> + </span> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Used both in <datatype> and in <func>! --> + <xsl:template match="anno"> + <xsl:variable name="curModule" select="ancestor::erlref/module"/> + <xsl:variable name="anno" select="normalize-space(text())"/> + <xsl:variable name="namespec" + select="ancestor::desc/preceding-sibling::name"/> + <xsl:if test="count($namespec) = 0 and string-length($specs_file) > 0"> + <xsl:call-template name="err"> + <xsl:with-param name="s">cannot find 'name' (<xsl:value-of select="$anno"/>) + </xsl:with-param> + </xsl:call-template> + </xsl:if> + + <xsl:variable name="mod" select="$namespec/@mod"/> + <xsl:variable name="name" select="$namespec/@name"/> + <xsl:variable name="arity" select="$namespec/@arity"/> + <xsl:variable name="clause" select="$namespec/@clause"/> + <xsl:variable name="tmp_n_vars" select="$namespec/@n_vars"/> + <xsl:variable name="n_vars"> + <xsl:choose> + <xsl:when test="string-length($tmp_n_vars) > 0"> + <xsl:value-of select="$tmp_n_vars"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="0"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="spec0" select= + "$i/specs/module[@name=$curModule]/spec + [name=$name and arity=$arity + and (string-length($mod) = 0 or module = $mod)]"/> + <xsl:variable name="spec_annos" select= + "$spec0[string-length($clause) = 0 + or position() = $clause]/anno[.=$anno]"/> + <xsl:variable name="type_annos" select= + "$i/specs/module[@name=$curModule]/type + [name=$name and n_vars=$n_vars + and (string-length($mod) = 0 or module = $mod)]/anno[.=$anno]"/> + + <xsl:if test="count($spec_annos) = 0 + and count($type_annos) = 0 + and string-length($specs_file) > 0"> + <xsl:variable name="n"> + <xsl:choose> + <xsl:when test="string-length($arity) = 0"> + <xsl:value-of select="$n_vars"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$arity"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:call-template name="err"> + <xsl:with-param name="m" select="$mod"/> + <xsl:with-param name="n" select="$name"/> + <xsl:with-param name="a" select="$n"/> + <xsl:with-param name="s">unknown annotation <xsl:value-of select="$anno"/> + </xsl:with-param> + </xsl:call-template> + </xsl:if> + <xsl:value-of select="$anno"/> + </xsl:template> + + <!-- Used for indentation of formatted types and specs --> + <xsl:template match="nbsp"> + <xsl:text> </xsl:text> + </xsl:template> + + <!-- End of Dialyzer type/spec tags --> + <!-- Page layout --> <xsl:template name="pagelayout"> <xsl:param name="chapnum"/> @@ -36,19 +336,19 @@ <title>Erlang -- <xsl:value-of select="header/title"/></title> </head> <body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000"> - + <div id="container"> <script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/> <script id="js2" type="text/javascript" src="{$topdocdir}/js/erlresolvelinks.js"></script> <script language="JavaScript" type="text/javascript"> <xsl:text disable-output-escaping="yes"><![CDATA[ - <!-- + <!-- function getWinHeight() { var myHeight = 0; if( typeof( window.innerHeight ) == 'number' ) { //Non-IE myHeight = window.innerHeight; - } else if( document.documentElement && ( document.documentElement.clientWidth || + } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) { //IE 6+ in 'standards compliant mode' myHeight = document.documentElement.clientHeight; @@ -56,7 +356,7 @@ //IE 4 compatible myHeight = document.body.clientHeight; } - return myHeight; + return myHeight; } function setscrollpos() { @@ -64,16 +364,16 @@ document.getElementById("leftnav").scrollTop = objf.offsetTop - getWinHeight()/2; } - function addEvent(obj, evType, fn){ - if (obj.addEventListener){ - obj.addEventListener(evType, fn, true); - return true; - } else if (obj.attachEvent){ - var r = obj.attachEvent("on"+evType, fn); - return r; - } else { - return false; - } + function addEvent(obj, evType, fn){ + if (obj.addEventListener){ + obj.addEventListener(evType, fn, true); + return true; + } else if (obj.attachEvent){ + var r = obj.attachEvent("on"+evType, fn); + return r; + } else { + return false; + } } addEvent(window, 'load', setscrollpos); @@ -85,7 +385,7 @@ <xsl:with-param name="chapnum" select="$chapnum"/> <xsl:with-param name="curModule" select="$curModule"/> </xsl:call-template> - + <div id="content"> <div class="innertube"> @@ -124,17 +424,17 @@ <xsl:if test="$lname = 'releasenotes'"> <!-- .../part --> <xsl:call-template name="releasenotes.content" /> - </xsl:if> + </xsl:if> <xsl:if test="$lname = 'part'"> <!-- .../part --> <xsl:call-template name="part.content" /> - </xsl:if> + </xsl:if> <xsl:if test="$lname = 'chapter'"> <!-- .../part/chapter --> <xsl:call-template name="chapter.content"> <xsl:with-param name="chapnum" select="$chapnum"/> </xsl:call-template> - </xsl:if> + </xsl:if> <xsl:if test="$lname = 'application'"> <!-- .../application --> <xsl:call-template name="app.content" /> @@ -178,37 +478,37 @@ <small> <xsl:if test="boolean(/book/parts/part)"> <a href="users_guide.html">User's Guide</a><br/> - </xsl:if> + </xsl:if> <xsl:if test="boolean(/book/applications)"> <a href="index.html">Reference Manual</a><br/> - </xsl:if> + </xsl:if> <xsl:if test="boolean(/book/releasenotes)"> <a href="release_notes.html">Release Notes</a><br/> - </xsl:if> + </xsl:if> <a href="{$pdfdir}/{$appname}-{$appver}.pdf">PDF</a><br/> <a href="{$topdocdir}/index.html">Top</a> </small> </xsl:template> - + <xsl:template name="menu_middle"> <!-- small> <xsl:choose> <xsl:when test="ancestor::parts"> <a href="users_guide_bibliography.html">Bibliography</a><br/> <a href="users_guide_glossary.html">Glossary</a><br/> - </xsl:when> - <xsl:when test="ancestor::applications"> + </xsl:when> + <xsl:when test="ancestor::applications"> <a href="ref_man_bibliography.html">Bibliography</a><br/> <a href="ref_man_glossary.html">Glossary</a><br/> - </xsl:when> + </xsl:when> </xsl:choose> </small --> <br/> <a href="javascript:openAllFlips()">Expand All</a><br/> <a href="javascript:closeAllFlips()">Contract All</a> - </xsl:template> - + </xsl:template> + <!-- Book --> <xsl:template match="/book"> @@ -243,7 +543,7 @@ <!-- Chapter/Section --> <xsl:template match="chapter/section"> - <xsl:param name="chapnum"/> + <xsl:param name="chapnum"/> <h3> <a name="{generate-id(title)}"> <xsl:value-of select="$chapnum"/>.<xsl:number/>  @@ -302,7 +602,7 @@ <!-- Lists --> - + <xsl:template match="list"> <xsl:param name="chapnum"/> <ul> @@ -330,7 +630,7 @@ </xsl:apply-templates> </dl> </xsl:template> - + <xsl:template match="taglist/tag"> <xsl:param name="chapnum"/> <dt> @@ -377,7 +677,7 @@ </xsl:apply-templates> </p> </div> - </div> + </div> </xsl:template> <!-- Paragraph --> @@ -402,7 +702,7 @@ </xsl:template> <xsl:template match="em"> - <strong><xsl:apply-templates/></strong> + <strong><xsl:apply-templates/></strong> </xsl:template> <!-- Code --> @@ -507,7 +807,7 @@ <!-- Part --> <xsl:template match="part"> <!-- Generate Glossary for Users Guide --> - <!--xsl:call-template name="glossary"> + <!--xsl:call-template name="glossary"> <xsl:with-param name="type">users_guide</xsl:with-param> </xsl:call-template--> @@ -530,9 +830,9 @@ <center><h4>Version <xsl:value-of select="$appver"/></h4></center> <center><h4><xsl:value-of select="$gendate"/></h4></center> - + <xsl:apply-templates select="chapter"/> - + </xsl:template> <!-- Menu.ug --> @@ -565,10 +865,10 @@ </xsl:call-template> </ul> </div> - </div> + </div> </xsl:template> - - + + <xsl:template name="menu.chapter"> <xsl:param name="entries"/> <xsl:param name="chapnum"/> @@ -596,7 +896,7 @@ <a href="{$chapter_file}.html"> Top of chapter </a> - </li> + </li> <xsl:call-template name="menu.section"> <xsl:with-param name="entries" select="section[title]"/> @@ -623,7 +923,7 @@ <!-- Chapter (if top tag)--> <xsl:template match="/chapter"> - <xsl:document href="{substring-before(header/file, '.xml')}.html" method="html" encoding="UTF-8" indent="yes" + <xsl:document href="{substring-before(header/file, '.xml')}.html" method="html" encoding="UTF-8" indent="yes" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"> <xsl:call-template name="pagelayout"> @@ -635,7 +935,7 @@ <!-- Chapter --> <xsl:template match="chapter"> - <xsl:document href="{substring-before(header/file, '.xml')}.html" method="html" encoding="UTF-8" indent="yes" + <xsl:document href="{substring-before(header/file, '.xml')}.html" method="html" encoding="UTF-8" indent="yes" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"> <xsl:call-template name="pagelayout"> @@ -670,7 +970,7 @@ <xsl:template match="application"> <!-- Generate Glossary for Ref. Manual --> - <!--xsl:call-template name="glossary"> + <!--xsl:call-template name="glossary"> <xsl:with-param name="type">ref_man</xsl:with-param> </xsl:call-template--> @@ -678,7 +978,7 @@ <!--xsl:call-template name="bibliography"> <xsl:with-param name="type">ref_man</xsl:with-param> </xsl:call-template--> - + <xsl:document href="{$outdir}/index.html" method="html" encoding="UTF-8" indent="yes" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"> @@ -695,9 +995,9 @@ <center><h4>Version <xsl:value-of select="$appver"/></h4></center> <center><h4><xsl:value-of select="$gendate"/></h4></center> - + <xsl:apply-templates select="erlref|cref|comref|fileref|appref"/> - + </xsl:template> <!-- Menu.ref --> @@ -730,16 +1030,16 @@ </xsl:call-template> </ul> </div> - </div> + </div> </xsl:template> - - + + <xsl:template name="menu.ref2"> <xsl:param name="entries"/> <!--xsl:param name="genFuncMenu"/--> <xsl:param name="curModule"/> <xsl:for-each select="$entries"> - + <xsl:variable name="cval"> <xsl:choose> <xsl:when test="local-name() = 'erlref'"> @@ -767,9 +1067,9 @@ <xsl:when test="local-name() = 'fileref'">false</xsl:when> <xsl:when test="descendant::funcs">true</xsl:when> <xsl:otherwise>false</xsl:otherwise> - </xsl:choose> + </xsl:choose> </xsl:variable> - + <xsl:variable name="expanded"> <xsl:choose> <xsl:when test="$curModule = $cval">true</xsl:when> @@ -796,7 +1096,7 @@ <a href="{$link_cval}.html"> Top of manual page </a> - </li> + </li> <xsl:call-template name="menu.funcs"> <xsl:with-param name="entries" select="funcs/func/name"/> @@ -823,7 +1123,7 @@ </xsl:otherwise> </xsl:choose> </xsl:otherwise> - </xsl:choose> + </xsl:choose> </xsl:for-each> </xsl:template> @@ -831,7 +1131,7 @@ <xsl:template name="menu.funcs"> <xsl:param name="entries"/> <xsl:param name="basename"/> - + <xsl:for-each select="$entries"> <xsl:choose> @@ -840,74 +1140,97 @@ <xsl:choose> <xsl:when test="string-length($fname) > 0"> <li title="{$fname}"> - <a href="{$basename}.html#{$fname}"> + <a href="{$basename}.html#{$fname}"> <xsl:value-of select="$fname"/>() </a> - </li> + </li> </xsl:when> <xsl:otherwise> <li title="{name/nametext}"> - <a href="{$basename}.html#{name/nametext}"> + <a href="{$basename}.html#{name/nametext}"> <xsl:value-of select="nametext"/>() - </a> - </li> + </a> + </li> </xsl:otherwise> - </xsl:choose> + </xsl:choose> </xsl:when> - + <xsl:when test="ancestor::erlref"> - + <xsl:variable name="tmpstring"> <xsl:value-of select="substring-before(substring-after(., '('), '->')"/> - </xsl:variable> - + </xsl:variable> + <xsl:variable name="ustring"> <xsl:choose> <xsl:when test="string-length($tmpstring) > 0"> <xsl:call-template name="remove-paren"> <xsl:with-param name="string" select="$tmpstring"/> - </xsl:call-template> + </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:call-template name="remove-paren"> <xsl:with-param name="string" select="substring-after(., '(')"/> - </xsl:call-template> + </xsl:call-template> </xsl:otherwise> </xsl:choose> - </xsl:variable> - + </xsl:variable> + <xsl:variable name="arity"> - <xsl:call-template name="calc-arity"> - <xsl:with-param name="string" select="substring-before($ustring, ')')"/> - <xsl:with-param name="no-of-pars" select="0"/> - </xsl:call-template> - </xsl:variable> - + <xsl:choose> + <xsl:when test="string-length(@arity) > 0"> + <!-- Dialyzer spec --> + <xsl:choose> + <xsl:when test="string-length(@clause) > 0"> + <xsl:value-of select="@arity"/>/<xsl:value-of select="@clause"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@arity"/> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="calc-arity"> + <xsl:with-param name="string" select="substring-before($ustring, ')')"/> + <xsl:with-param name="no-of-pars" select="0"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="fname"> - <xsl:variable name="fname1"> - <xsl:value-of select="substring-before(., '(')"/> - </xsl:variable> - <xsl:variable name="fname2"> - <xsl:value-of select="substring-after($fname1, 'erlang:')"/> - </xsl:variable> <xsl:choose> - <xsl:when test="string-length($fname2) > 0"> - <xsl:value-of select="$fname2"/> + <xsl:when test="string-length(@name) > 0"> + <!-- Dialyzer spec --> + <xsl:value-of select="@name"/> </xsl:when> <xsl:otherwise> - <xsl:value-of select="$fname1"/> + <xsl:variable name="fname1"> + <xsl:value-of select="substring-before(., '(')"/> + </xsl:variable> + <xsl:variable name="fname2"> + <xsl:value-of select="substring-after($fname1, 'erlang:')"/> + </xsl:variable> + <xsl:choose> + <xsl:when test="string-length($fname2) > 0"> + <xsl:value-of select="$fname2"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$fname1"/> + </xsl:otherwise> + </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:variable> - + <li title="{$fname}-{$arity}"> - <a href="{$basename}.html#{$fname}-{$arity}"> + <a href="{$basename}.html#{$fname}-{$arity}"> <xsl:value-of select="$fname"/>/<xsl:value-of select="$arity"/> </a> - </li> + </li> </xsl:when> </xsl:choose> - + </xsl:for-each> </xsl:template> @@ -1148,7 +1471,7 @@ <!-- Func --> <xsl:template match="func"> <xsl:param name="partnum"/> - + <p><xsl:apply-templates select="name"/></p> <xsl:apply-templates select="fsummary|type|desc"> @@ -1159,33 +1482,48 @@ <xsl:template match="name"> + <xsl:choose> + <!-- @arity is mandatory when referring to a specification --> + <xsl:when test="string-length(@arity) > 0"> + <xsl:call-template name="spec_name"/> + </xsl:when> + <xsl:when test="ancestor::datatype"> + <xsl:call-template name="type_name"/> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="name"> <xsl:variable name="tmpstring"> <xsl:value-of select="substring-before(substring-after(., '('), '->')"/> - </xsl:variable> + </xsl:variable> <xsl:variable name="ustring"> <xsl:choose> <xsl:when test="string-length($tmpstring) > 0"> <xsl:call-template name="remove-paren"> <xsl:with-param name="string" select="$tmpstring"/> - </xsl:call-template> + </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:call-template name="remove-paren"> <xsl:with-param name="string" select="substring-after(., '(')"/> - </xsl:call-template> + </xsl:call-template> </xsl:otherwise> </xsl:choose> - </xsl:variable> - + </xsl:variable> + <xsl:variable name="arity"> <xsl:call-template name="calc-arity"> <xsl:with-param name="string" select="substring-before($ustring, ')')"/> - <xsl:with-param name="no-of-pars" select="0"/> + <xsl:with-param name="no-of-pars" select="0"/> </xsl:call-template> - </xsl:variable> - + </xsl:variable> + <xsl:choose> <xsl:when test="ancestor::cref"> <a name="{substring-before(nametext, '(')}"><span class="bold_code"><xsl:value-of select="ret"/><xsl:text> </xsl:text><xsl:value-of select="nametext"/></span></a><br/> @@ -1199,7 +1537,7 @@ <xsl:value-of select="substring-after($fname1, 'erlang:')"/> </xsl:variable> <xsl:choose> - <xsl:when test="string-length($fname2) > 0"> + <xsl:when test="string-length($fname2) > 0"> <xsl:value-of select="$fname2"/> </xsl:when> <xsl:otherwise> @@ -1213,21 +1551,20 @@ <span class="bold_code"><xsl:value-of select="."/></span> </xsl:otherwise> </xsl:choose> - - </xsl:template> + </xsl:template> <!-- Type --> <xsl:template match="type"> <xsl:param name="partnum"/> - <div class="REFBODY"><p>Types:</p> + <div class="REFBODY"><p>Types:</p> <xsl:apply-templates> <xsl:with-param name="partnum" select="$partnum"/> </xsl:apply-templates> </div> - + </xsl:template> @@ -1286,16 +1623,37 @@ <xsl:variable name="modulepart"><xsl:value-of select="substring-before($filepart, ':')"/></xsl:variable> <xsl:choose> <xsl:when test="string-length($modulepart) > 0"> - <xsl:variable name="filepart1"><xsl:value-of select="substring-after($filepart, ':')"/></xsl:variable> + <xsl:variable name="filepart1"><xsl:value-of select="substring-after($filepart, ':')"/></xsl:variable> <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$modulepart}','{$filepart1}.html#{$linkpart}');"><xsl:apply-templates/></a></span> </xsl:when> <xsl:otherwise> <xsl:choose> + <!-- Dialyzer seealso (the application is unknown) --> + <xsl:when test="string-length($specs_file) > 0 + and count($i/specs/module[@name=$filepart]) = 0"> + <!-- Deemed to slow; use key() instead + <xsl:variable name="app" + select="$m2a/mod2app/module[@name=$filepart]"/> + --> + <xsl:variable name="reftext" select="text()"/> + <xsl:for-each select="$m2a"> + <xsl:variable name="app" select="key('mod2app', $filepart)"/> + <xsl:choose> + <xsl:when test="string-length($app) > 0"> + <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app}','{$filepart}.html');"><xsl:value-of select="$reftext"/></a></span> + </xsl:when> + <xsl:otherwise> + <!-- Unknown application; no link --> + <xsl:value-of select="$reftext"/> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + </xsl:when> <xsl:when test="string-length($linkpart) > 0"> <span class="bold_code"><a href="{$filepart}.html#{$linkpart}"><xsl:apply-templates/></a></span> </xsl:when> - <xsl:otherwise> - <span class="bold_code"><a href="{$filepart}.html"><xsl:apply-templates/></a></span> + <xsl:otherwise> + <span class="bold_code"><a href="{$filepart}.html"><xsl:apply-templates/></a></span> </xsl:otherwise> </xsl:choose> </xsl:otherwise> @@ -1308,16 +1666,16 @@ </xsl:when> <xsl:otherwise> <xsl:variable name="modulepart"><xsl:value-of select="substring-before(@marker, ':')"/></xsl:variable> - + <xsl:choose> <xsl:when test="string-length($modulepart) > 0"> - <xsl:variable name="filepart1"><xsl:value-of select="substring-after(@marker, ':')"/></xsl:variable> + <xsl:variable name="filepart1"><xsl:value-of select="substring-after(@marker, ':')"/></xsl:variable> <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$modulepart}','{$filepart1}.html');"><xsl:apply-templates/></a></span> </xsl:when> <xsl:otherwise> - <span class="bold_code"><a href="{@marker}.html"><xsl:apply-templates/></a></span> + <span class="bold_code"><a href="{@marker}.html"><xsl:apply-templates/></a></span> </xsl:otherwise> - </xsl:choose> + </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:otherwise> @@ -1342,16 +1700,16 @@ <xsl:choose> <xsl:when test="ancestor::parts"> <a href="users_guide_glossary.html#{@id}"><xsl:value-of select="@id"/></a> - </xsl:when> - <xsl:when test="ancestor::applications"> + </xsl:when> + <xsl:when test="ancestor::applications"> <a href="ref_man_glossary.html#{@id}"><xsl:value-of select="@id"/></a> - </xsl:when> + </xsl:when> </xsl:choose> </xsl:when> <xsl:otherwise> <a href="{$topdocdir}/glossary.html#{@id}"><xsl:value-of select="@id"/></a> </xsl:otherwise> - </xsl:choose --> + </xsl:choose --> </xsl:template> <xsl:template match="cite"> @@ -1375,9 +1733,9 @@ <center><h4>Version <xsl:value-of select="$appver"/></h4></center> <center><h4><xsl:value-of select="$gendate"/></h4></center> - + <xsl:apply-templates select="chapter"/> - + </xsl:template> <!-- Menu.rn --> @@ -1410,7 +1768,7 @@ </xsl:call-template> </ul> </div> - </div> + </div> </xsl:template> <!-- Glossary --> @@ -1423,14 +1781,14 @@ <title>Erlang Documentation -- <xsl:value-of select="header/title"/></title> </head> <body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000"> - + <div id="container"> <script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/> <script id="js2" type="text/javascript" src="{$topdocdir}/js/erlresolvelinks.js"></script> <!-- Generate menu --> <xsl:call-template name="menu"/> - + <div id="content"> <div class="innertube"> <h1>Glossary</h1> @@ -1478,14 +1836,14 @@ <title>Erlang Documentation -- <xsl:value-of select="header/title"/></title> </head> <body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000"> - + <div id="container"> <script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/> <script id="js2" type="text/javascript" src="{$topdocdir}/js/erlresolvelinks.js"></script> <!-- Generate menu --> <xsl:call-template name="menu"/> - + <div id="content"> <div class="innertube"> <h1>Bibliography</h1> @@ -1498,8 +1856,8 @@ <tr> <td><xsl:value-of select="@id"/></td> <td><xsl:value-of select="citedef"/></td> - </tr> - </xsl:if> + </tr> + </xsl:if> </xsl:for-each> </table> @@ -1529,7 +1887,7 @@ <xsl:template name="calc-arity"> <xsl:param name="string"/> <xsl:param name="no-of-pars"/> - + <xsl:variable name="length"> <xsl:value-of select="string-length($string)"/> </xsl:variable> @@ -1538,8 +1896,8 @@ <xsl:when test="$length > 0"> <xsl:call-template name="calc-arity"> <xsl:with-param name="string" select="substring-after($string, ',')"/> - <xsl:with-param name="no-of-pars" select="$no-of-pars+1"/> - </xsl:call-template> + <xsl:with-param name="no-of-pars" select="$no-of-pars+1"/> + </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$no-of-pars"/> @@ -1554,9 +1912,9 @@ <xsl:variable name="str1"> <xsl:call-template name="remove-paren-1"> <xsl:with-param name="string" select="$string"/> - <xsl:with-param name="start">(</xsl:with-param> - <xsl:with-param name="end">)</xsl:with-param> - </xsl:call-template> + <xsl:with-param name="start">(</xsl:with-param> + <xsl:with-param name="end">)</xsl:with-param> + </xsl:call-template> </xsl:variable> <xsl:variable name="str2"> @@ -1564,7 +1922,7 @@ <xsl:with-param name="string" select="$str1"/> <xsl:with-param name="start">{</xsl:with-param> <xsl:with-param name="end">}</xsl:with-param> - </xsl:call-template> + </xsl:call-template> </xsl:variable> <xsl:variable name="str3"> @@ -1572,7 +1930,7 @@ <xsl:with-param name="string" select="$str2"/> <xsl:with-param name="start">[</xsl:with-param> <xsl:with-param name="end">]</xsl:with-param> - </xsl:call-template> + </xsl:call-template> </xsl:variable> <xsl:value-of select="$str3"/> @@ -1584,7 +1942,7 @@ <xsl:param name="string"/> <xsl:param name="start"/> <xsl:param name="end"/> - + <xsl:variable name="tmp1"> <xsl:value-of select="substring-before($string, $start)"/> </xsl:variable> @@ -1597,7 +1955,7 @@ <xsl:variable name="retstring"> <xsl:call-template name="remove-paren"> <xsl:with-param name="string" select="$tmp2"/> - </xsl:call-template> + </xsl:call-template> </xsl:variable> <xsl:value-of select="concat(concat($tmp1, 'x'), $retstring)"/> </xsl:when> diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl index 71c4a66707..2ed0d95c6d 100644 --- a/lib/erl_docgen/priv/xsl/db_man.xsl +++ b/lib/erl_docgen/priv/xsl/db_man.xsl @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- +<!-- # # %CopyrightBegin% # @@ -17,24 +17,294 @@ # under the License. # # %CopyrightEnd% - + --> <xsl:stylesheet version="1.0" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:preserve-space elements="code pre"/> <xsl:strip-space elements="*"/> <xsl:output method="text" encoding="UTF-8" indent="no"/> + <!-- Start of Dialyzer type/spec tags. See also the template matching "name" + --> + + <!-- Note: specs data for *one* module (as opposed to html and pdf) --> + <xsl:param name="specs_file" select="''"/> + <xsl:variable name="i" select="document($specs_file)"></xsl:variable> + + <xsl:template name="err"> + <xsl:param name="m"/> + <xsl:param name="n"/> + <xsl:param name="a"/> + <xsl:param name="s"/> + <xsl:message terminate="yes"> + Error <xsl:if test="$m != ''"><xsl:value-of select ="$m"/>:</xsl:if> + <xsl:value-of + select="$n"/>/<xsl:value-of + select="$a"/>: <xsl:value-of select="$s"/> + </xsl:message> + </xsl:template> + + <xsl:template name="spec_name"> + <xsl:variable name="curModule" select="ancestor::erlref/module"/> + <xsl:variable name="mod" select="@mod"/> + <xsl:variable name="name" select="@name"/> + <xsl:variable name="arity" select="@arity"/> + <xsl:variable name="clause" select="@clause"/> + <xsl:variable name="spec0" select= + "$i/module[@name=$curModule]/spec + [name=$name and arity=$arity + and (string-length($mod) = 0 or module = $mod)]"/> + <xsl:variable name="spec" select="$spec0[string-length($clause) = 0 + or position() = $clause]"/> + <xsl:if test="count($spec) = 0"> + <xsl:call-template name="err"> + <xsl:with-param name="m" select="$mod"/> + <xsl:with-param name="n" select="$name"/> + <xsl:with-param name="a" select="$arity"/> + <xsl:with-param name="s">unknown spec</xsl:with-param> + </xsl:call-template> + </xsl:if> + + <xsl:choose> + <xsl:when test="ancestor::cref"> + <xsl:message terminate="yes"> + Error: did not expect a 'name' tag with name/arity attributes here! + </xsl:message> + </xsl:when> + <xsl:when test="ancestor::erlref"> + <xsl:choose> + <xsl:when test="string(@with_guards) = 'no'"> + <xsl:apply-templates select="$spec/contract/clause/head"/> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="contract"> + <xsl:with-param name="contract" select="$spec/contract"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + <xsl:text> .br</xsl:text> + </xsl:when> + </xsl:choose> + </xsl:template> + + <xsl:template name="contract"> + <xsl:param name="contract"/> + <xsl:call-template name="clause"> + <xsl:with-param name="clause" select="$contract/clause"/> + </xsl:call-template> + </xsl:template> + + <xsl:template name="clause"> + <xsl:param name="clause"/> + <xsl:variable name="type_desc" select="../type_desc"/> + <xsl:for-each select="$clause"> + <xsl:apply-templates select="head"/> + <xsl:if test="count(guard) > 0"> + <xsl:call-template name="guard"> + <xsl:with-param name="guard" select="guard"/> + <xsl:with-param name="type_desc" select="$type_desc"/> + </xsl:call-template> + </xsl:if> + </xsl:for-each> + </xsl:template> + + <xsl:template match="head"> + <xsl:text> .nf </xsl:text> + <xsl:text> .B </xsl:text> + <xsl:apply-templates/> + <xsl:text> .br</xsl:text> + <xsl:text> .fi</xsl:text> + </xsl:template> + + <xsl:template name="guard"> + <xsl:param name="guard"/> + <xsl:param name="type_desc"/> + <xsl:text> .RS</xsl:text> + <xsl:text> .TP</xsl:text> + <xsl:text> Types</xsl:text> + <xsl:call-template name="subtype"> + <xsl:with-param name="subtype" select="$guard/subtype"/> + <xsl:with-param name="type_desc" select="$type_desc"/> + </xsl:call-template> + <xsl:text> .RE</xsl:text> + </xsl:template> + + <xsl:template name="subtype"> + <xsl:param name="subtype"/> + <xsl:param name="type_desc"/> + <xsl:for-each select="$subtype"> + <xsl:variable name="tname" select="typename"/> + <xsl:variable name="tdesc" select="$type_desc[@name = $tname]"/> + <xsl:text> </xsl:text> + <xsl:apply-templates select="string"/> + <xsl:text> .br</xsl:text> + <xsl:apply-templates select="$type_desc[@name = $tname]"/> + </xsl:for-each> + </xsl:template> + + <!-- Note: <type_desc> has not been implemented for data types. --> + + <!-- Similar to <d> --> + <xsl:template match="type_desc"> + <xsl:text> </xsl:text><xsl:apply-templates/> + <xsl:text> .br</xsl:text> + </xsl:template> + + <!-- Datatypes --> + <xsl:template match="datatypes"> + <xsl:text> .SH DATA TYPES</xsl:text> + <xsl:apply-templates/> + </xsl:template> + + <!-- Datatype --> + <xsl:template match="datatype"> + <xsl:apply-templates/> + </xsl:template> + + <xsl:template match="typehead"> + <xsl:text> .nf </xsl:text> + <xsl:text> .B </xsl:text> + <xsl:apply-templates/> + <xsl:text> .br</xsl:text> + <xsl:text> .fi</xsl:text> + </xsl:template> + + <xsl:template match="local_defs"> + <xsl:text> .RS</xsl:text> + <xsl:apply-templates/> + <xsl:text> .RE</xsl:text> + </xsl:template> + + <xsl:template match="local_def"> + <xsl:text> </xsl:text> + <xsl:apply-templates/> + <xsl:text> .br</xsl:text> + </xsl:template> + + <xsl:template name="type_name"> + <xsl:variable name="curModule" select="ancestor::erlref/module"/> + <xsl:variable name="mod" select="@mod"/> + <xsl:variable name="name" select="@name"/> + <xsl:variable name="n_vars"> + <xsl:choose> + <xsl:when test="string-length(@n_vars) > 0"> + <xsl:value-of select="@n_vars"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="0"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:choose> + <xsl:when test="string-length($name) > 0"> + <xsl:variable name="type" select= + "$i/module[@name=$curModule]/type + [name=$name and n_vars=$n_vars + and (string-length($mod) = 0 or module = $mod)]"/> + + <xsl:if test="count($type) != 1"> + <xsl:call-template name="err"> + <xsl:with-param name="m" select="$mod"/> + <xsl:with-param name="n" select="$name"/> + <xsl:with-param name="a" select="$n_vars"/> + <xsl:with-param name="s">unknown type</xsl:with-param> + </xsl:call-template> + </xsl:if> + <xsl:apply-templates select="$type/typedecl"/> + </xsl:when> + <xsl:otherwise> + <xsl:text> .nf </xsl:text> + <xsl:text> .B </xsl:text> + <xsl:apply-templates/> + <xsl:text> .br</xsl:text> + <xsl:text> .fi</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Used both in <datatype> and in <func>! --> + <xsl:template match="anno"> + <xsl:variable name="curModule" select="ancestor::erlref/module"/> + <xsl:variable name="anno" select="normalize-space(text())"/> + <xsl:variable name="namespec" + select="ancestor::desc/preceding-sibling::name"/> + <xsl:if test="count($namespec) = 0 and string-length($specs_file) > 0"> + <xsl:call-template name="err"> + <xsl:with-param name="s">cannot find 'name' (<xsl:value-of select="$anno"/>) + </xsl:with-param> + </xsl:call-template> + </xsl:if> + + <xsl:variable name="mod" select="$namespec/@mod"/> + <xsl:variable name="name" select="$namespec/@name"/> + <xsl:variable name="arity" select="$namespec/@arity"/> + <xsl:variable name="clause" select="$namespec/@clause"/> + <xsl:variable name="tmp_n_vars" select="$namespec/@n_vars"/> + <xsl:variable name="n_vars"> + <xsl:choose> + <xsl:when test="string-length($tmp_n_vars) > 0"> + <xsl:value-of select="$tmp_n_vars"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="0"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="spec0" select= + "$i/module[@name=$curModule]/spec + [name=$name and arity=$arity + and (string-length($mod) = 0 or module = $mod)]"/> + <xsl:variable name="spec_annos" select= + "$spec0[string-length($clause) = 0 + or position() = $clause]/anno[.=$anno]"/> + <xsl:variable name="type_annos" select= + "$i/module[@name=$curModule]/type + [name=$name and n_vars=$n_vars + and (string-length($mod) = 0 or module = $mod)]/anno[.=$anno]"/> + + <xsl:if test="count($spec_annos) = 0 + and count($type_annos) = 0 + and string-length($specs_file) > 0"> + <xsl:variable name="n"> + <xsl:choose> + <xsl:when test="string-length($arity) = 0"> + <xsl:value-of select="$n_vars"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$arity"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:call-template name="err"> + <xsl:with-param name="m" select="$mod"/> + <xsl:with-param name="n" select="$name"/> + <xsl:with-param name="a" select="$n"/> + <xsl:with-param name="s">unknown annotation <xsl:value-of select="$anno"/> + </xsl:with-param> + </xsl:call-template> + </xsl:if> + <xsl:value-of select="$anno"/> + </xsl:template> + + <!-- Used for indentation of formatted types and specs --> + <xsl:template match="nbsp"> + <xsl:text> </xsl:text> + </xsl:template> + + <!-- End of Dialyzer type/spec tags --> + <!-- Header --> <xsl:template match="header"> </xsl:template> - + <!-- Section/Title --> <xsl:template match="section/title"> </xsl:template> - + <!-- *ref/Section --> <xsl:template match="erlref/section|comref/section|cref/section|fileref/section|appref/section"> <xsl:text> .SH "</xsl:text><xsl:value-of select="translate(title, 'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/><xsl:text>" </xsl:text> @@ -49,7 +319,7 @@ <!-- Lists --> - + <xsl:template match="list"> <xsl:text> .RS 2</xsl:text> <xsl:apply-templates/> @@ -68,7 +338,7 @@ <xsl:apply-templates select="tag|item"/> <xsl:text> .RE</xsl:text> </xsl:template> - + <xsl:template match="taglist/tag"> <xsl:text> .TP 2 </xsl:text> <xsl:text>.B </xsl:text> @@ -76,7 +346,7 @@ </xsl:template> <xsl:template match="taglist/item"> - <xsl:apply-templates/> + <xsl:apply-templates/> </xsl:template> <xsl:template match="item/p"> @@ -88,10 +358,10 @@ <xsl:value-of select="$content"/> </xsl:when> <xsl:otherwise> - <xsl:text> .RS 2</xsl:text> - <xsl:text> .LP .LP </xsl:text> + <xsl:text> .RS 2</xsl:text> + <xsl:text> .LP .LP </xsl:text> <xsl:value-of select="$content"/> - <xsl:text> .RE</xsl:text> + <xsl:text> .RE</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:template> @@ -171,7 +441,7 @@ <xsl:template match="application"> <xsl:apply-templates/> </xsl:template> - + <!-- Erlref --> <xsl:template match="/erlref"> <xsl:variable name="companyname"> @@ -184,7 +454,7 @@ <xsl:text>.TH </xsl:text><xsl:value-of select="module"/><xsl:text> 3 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "Erlang Module Definition" </xsl:text> <xsl:text>.SH NAME </xsl:text> - <xsl:value-of select="module"/><xsl:text> \- </xsl:text><xsl:value-of select="modulesummary"/><xsl:text> </xsl:text> + <xsl:value-of select="module"/><xsl:text> \- </xsl:text><xsl:value-of select="modulesummary"/><xsl:text> </xsl:text> <xsl:apply-templates/> </xsl:template> @@ -199,7 +469,7 @@ </xsl:variable> <xsl:text>.TH </xsl:text><xsl:value-of select="com"/><xsl:text> 1 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "User Commands" </xsl:text> <xsl:text>.SH NAME </xsl:text> - <xsl:value-of select="com"/><xsl:text> \- </xsl:text><xsl:value-of select="comsummary"/><xsl:text> </xsl:text> + <xsl:value-of select="com"/><xsl:text> \- </xsl:text><xsl:value-of select="comsummary"/><xsl:text> </xsl:text> <xsl:apply-templates/> </xsl:template> @@ -214,7 +484,7 @@ </xsl:variable> <xsl:text>.TH </xsl:text><xsl:value-of select="lib"/><xsl:text> 3 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "C Library Functions" </xsl:text> <xsl:text>.SH NAME </xsl:text> - <xsl:value-of select="lib"/><xsl:text> \- </xsl:text><xsl:value-of select="libsummary"/><xsl:text> </xsl:text> + <xsl:value-of select="lib"/><xsl:text> \- </xsl:text><xsl:value-of select="libsummary"/><xsl:text> </xsl:text> <xsl:apply-templates/> </xsl:template> @@ -229,7 +499,7 @@ </xsl:variable> <xsl:text>.TH </xsl:text><xsl:value-of select="file"/><xsl:text> 5 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "Files" </xsl:text> <xsl:text>.SH NAME </xsl:text> - <xsl:value-of select="file"/><xsl:text> \- </xsl:text><xsl:value-of select="filesummary"/><xsl:text> </xsl:text> + <xsl:value-of select="file"/><xsl:text> \- </xsl:text><xsl:value-of select="filesummary"/><xsl:text> </xsl:text> <xsl:apply-templates/> </xsl:template> @@ -244,7 +514,7 @@ </xsl:variable> <xsl:text>.TH </xsl:text><xsl:value-of select="app"/><xsl:text> 7 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "Erlang Application Definition" </xsl:text> <xsl:text>.SH NAME </xsl:text> - <xsl:value-of select="app"/><xsl:text> \- </xsl:text><xsl:value-of select="appsummary"/><xsl:text> </xsl:text> + <xsl:value-of select="app"/><xsl:text> \- </xsl:text><xsl:value-of select="appsummary"/><xsl:text> </xsl:text> <xsl:apply-templates/> </xsl:template> @@ -271,10 +541,26 @@ <!-- Func --> <xsl:template match="func"> <xsl:text> .LP</xsl:text> - <xsl:apply-templates/> + <xsl:apply-templates select="name"/> + <xsl:apply-templates select="fsummary|type|desc"/> </xsl:template> <xsl:template match="name"> + <xsl:choose> + <!-- @arity is mandatory when referring to a specification --> + <xsl:when test="string-length(@arity) > 0"> + <xsl:call-template name="spec_name"/> + </xsl:when> + <xsl:when test="ancestor::datatype"> + <xsl:call-template name="type_name"/> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="name"> <xsl:text> .B </xsl:text> <xsl:apply-templates/> <xsl:text> .br</xsl:text> @@ -296,7 +582,7 @@ <xsl:text> </xsl:text><xsl:value-of select="normalize-space(text())"/> <xsl:text> .br</xsl:text> </xsl:template> - + <!-- D --> <xsl:template match="d"> <xsl:text> </xsl:text><xsl:apply-templates/> @@ -316,7 +602,7 @@ <!-- This tag is skipped for now. --> </xsl:template> - + <!-- Authors --> <xsl:template match="authors"> <xsl:text> .SH AUTHORS</xsl:text> @@ -336,21 +622,11 @@ <xsl:text>></xsl:text> </xsl:template> - <!-- Do not noramlize any text within pre and code tags. --> - <xsl:template match="pre/text()"> - <xsl:value-of select="."/> - </xsl:template> - - <xsl:template match="code/text()"> - <xsl:value-of select="."/> - </xsl:template> - - <!-- Replace ' by \&' ans . by \&. --> <xsl:template match="text()"> <xsl:variable name="startstring"> <xsl:value-of select="normalize-space()"/><xsl:text> </xsl:text> - </xsl:variable> + </xsl:variable> <xsl:variable name="rep1"> <xsl:call-template name="replace-string"> <xsl:with-param name="text" select="$startstring" /> diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl index e12b4d219a..1e80c360b8 100644 --- a/lib/erl_docgen/priv/xsl/db_pdf.xsl +++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- +<!-- # # %CopyrightBegin% # @@ -17,7 +17,7 @@ # under the License. # # %CopyrightEnd% - + --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" @@ -27,16 +27,310 @@ <xsl:include href="db_pdf_params.xsl"/> + <!-- Start of Dialyzer type/spec tags. + See also the template matching "name" and the template "bookmarks6" + --> + + <xsl:param name="specs_file" select="''"/> + <xsl:variable name="i" select="document($specs_file)"></xsl:variable> + + <xsl:template name="err"> + <xsl:param name="m"/> + <xsl:param name="n"/> + <xsl:param name="a"/> + <xsl:param name="s"/> + <xsl:message terminate="yes"> + Error <xsl:if test="$m != ''"><xsl:value-of select ="$m"/>:</xsl:if> + <xsl:value-of + select="$n"/>/<xsl:value-of + select="$a"/>: <xsl:value-of select="$s"/> + </xsl:message> + </xsl:template> + + <xsl:template name="spec_name"> + <xsl:variable name="curModule" select="ancestor::erlref/module"/> + <xsl:variable name="mod" select="@mod"/> + <xsl:variable name="name" select="@name"/> + <xsl:variable name="arity" select="@arity"/> + <xsl:variable name="clause" select="@clause"/> + <xsl:variable name="spec0" select= + "$i/specs/module[@name=$curModule]/spec + [name=$name and arity=$arity + and (string-length($mod) = 0 or module = $mod)]"/> + <xsl:variable name="spec" select="$spec0[string-length($clause) = 0 + or position() = $clause]"/> + <xsl:if test="count($spec) = 0"> + <xsl:call-template name="err"> + <xsl:with-param name="m" select="$mod"/> + <xsl:with-param name="n" select="$name"/> + <xsl:with-param name="a" select="$arity"/> + <xsl:with-param name="s">unknown spec</xsl:with-param> + </xsl:call-template> + </xsl:if> + + <xsl:choose> + <xsl:when test="ancestor::cref"> + <xsl:message terminate="yes"> + Error: did not expect a 'name' tag with name/arity attributes here! + </xsl:message> + </xsl:when> + <xsl:when test="ancestor::erlref"> + <fo:block id="{generate-id()}"> + <xsl:choose> + <xsl:when test="string(@with_guards) = 'no'"> + <xsl:apply-templates select="$spec/contract/clause/head"/> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="contract"> + <xsl:with-param name="contract" select="$spec/contract"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </fo:block> + </xsl:when> + </xsl:choose> + </xsl:template> + + <xsl:template name="contract"> + <xsl:param name="contract"/> + <xsl:call-template name="clause"> + <xsl:with-param name="clause" select="$contract/clause"/> + </xsl:call-template> + </xsl:template> + + <xsl:template name="clause"> + <xsl:param name="clause"/> + <xsl:variable name="type_desc" select="../type_desc"/> + <xsl:for-each select="$clause"> + <xsl:apply-templates select="head"/> + <xsl:if test="count(guard) > 0"> + <xsl:call-template name="guard"> + <xsl:with-param name="guard" select="guard"/> + <xsl:with-param name="type_desc" select="$type_desc"/> + </xsl:call-template> + </xsl:if> + </xsl:for-each> + </xsl:template> + + <xsl:template match="head"> + <fo:block xsl:use-attribute-sets="function-name"> + <xsl:apply-templates/> + </fo:block> + </xsl:template> + + <xsl:template name="guard"> + <fo:block> + <xsl:text>Types:</xsl:text> + </fo:block> + <fo:list-block xsl:use-attribute-sets="type-listblock"> + <xsl:call-template name="subtype"> + <xsl:with-param name="subtype" select="$guard/subtype"/> + <xsl:with-param name="type_desc" select="$type_desc"/> + </xsl:call-template> + </fo:list-block> + </xsl:template> + + <xsl:template name="subtype"> + <xsl:param name="subtype"/> + <xsl:param name="type_desc"/> + <xsl:for-each select="$subtype"> + <xsl:variable name="tname" select="typename"/> + <xsl:variable name="tdesc" select="$type_desc[@name = $tname]"/> + <fo:list-item xsl:use-attribute-sets="type-listitem"> + <fo:list-item-label end-indent="label-end()"> + <fo:block> + </fo:block> + </fo:list-item-label> + <fo:list-item-body start-indent="body-start()" format="justify"> + <fo:block font-weight="bold"> + <xsl:apply-templates select="string"/> + </fo:block> + </fo:list-item-body> + </fo:list-item> + <xsl:apply-templates select="$type_desc[@name = $tname]"/> + </xsl:for-each> + </xsl:template> + + <!-- Note: <type_desc> has not been implemented for data types. --> + + <!-- Similar to <d> --> + <xsl:template match="type_desc"> + <fo:list-item xsl:use-attribute-sets="type-listitem"> + <fo:list-item-label end-indent="label-end()"><fo:block></fo:block> + </fo:list-item-label> + <fo:list-item-body start-indent="body-start()" format="justify"> + <fo:block> + <xsl:apply-templates/> + </fo:block> + </fo:list-item-body> + </fo:list-item> + </xsl:template> + + <!-- Datatypes --> + <xsl:template match="datatypes"> + <fo:block xsl:use-attribute-sets="h3"> + <xsl:text>Data Types</xsl:text> + </fo:block> + <xsl:apply-templates/> + </xsl:template> + + <!-- Datatype --> + <xsl:template match="datatype"> + <fo:block xsl:use-attribute-sets="function-name"> + <xsl:apply-templates select="name"/> + </fo:block> + <xsl:apply-templates select="desc"/> + </xsl:template> + + <!-- Like <head>... --> + <xsl:template match="typehead"> + <fo:block xsl:use-attribute-sets="function-name"> + <xsl:apply-templates/> + </fo:block> + </xsl:template> + + <!-- Like <guard>, except "Types:"... --> + <xsl:template match="local_defs"> + <fo:list-block xsl:use-attribute-sets="type-listblock"> + <xsl:apply-templates/> + </fo:list-block> + </xsl:template> + + <!-- Like <subtype>... --> + <xsl:template match="local_def"> + <fo:list-item xsl:use-attribute-sets="type-listitem"> + <fo:list-item-label end-indent="label-end()"> + <fo:block> + </fo:block> + </fo:list-item-label> + <fo:list-item-body start-indent="body-start()" format="justify"> + <fo:block font-weight="bold"> + <xsl:apply-templates/> + </fo:block> + </fo:list-item-body> + </fo:list-item> + </xsl:template> + + <xsl:template name="type_name"> + <xsl:variable name="curModule" select="ancestor::erlref/module"/> + <xsl:variable name="mod" select="@mod"/> + <xsl:variable name="name" select="@name"/> + <xsl:variable name="n_vars"> + <xsl:choose> + <xsl:when test="string-length(@n_vars) > 0"> + <xsl:value-of select="@n_vars"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="0"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:choose> + <xsl:when test="string-length($name) > 0"> + <xsl:variable name="type" select= + "$i/specs/module[@name=$curModule]/type + [name=$name and n_vars=$n_vars + and (string-length($mod) = 0 or module = $mod)]"/> + + <xsl:if test="count($type) != 1"> + <xsl:call-template name="err"> + <xsl:with-param name="m" select="$mod"/> + <xsl:with-param name="n" select="$name"/> + <xsl:with-param name="a" select="$n_vars"/> + <xsl:with-param name="s">unknown type</xsl:with-param> + </xsl:call-template> + </xsl:if> + <xsl:apply-templates select="$type/typedecl"/> + </xsl:when> + <xsl:otherwise> + <fo:inline font-weight="bold" xsl:use-attribute-sets="type-listitem"> + <xsl:value-of select="."/> + </fo:inline> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Used both in <datatype> and in <func>! --> + <xsl:template match="anno"> + <xsl:variable name="curModule" select="ancestor::erlref/module"/> + <xsl:variable name="anno" select="normalize-space(text())"/> + <xsl:variable name="namespec" + select="ancestor::desc/preceding-sibling::name"/> + <xsl:if test="count($namespec) = 0 and string-length($specs_file) > 0"> + <xsl:call-template name="err"> + <xsl:with-param name="s">cannot find 'name' (<xsl:value-of select="$anno"/>) + </xsl:with-param> + </xsl:call-template> + </xsl:if> + + <xsl:variable name="mod" select="$namespec/@mod"/> + <xsl:variable name="name" select="$namespec/@name"/> + <xsl:variable name="arity" select="$namespec/@arity"/> + <xsl:variable name="clause" select="$namespec/@clause"/> + <xsl:variable name="tmp_n_vars" select="$namespec/@n_vars"/> + <xsl:variable name="n_vars"> + <xsl:choose> + <xsl:when test="string-length($tmp_n_vars) > 0"> + <xsl:value-of select="$tmp_n_vars"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="0"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="spec0" select= + "$i/specs/module[@name=$curModule]/spec + [name=$name and arity=$arity + and (string-length($mod) = 0 or module = $mod)]"/> + <xsl:variable name="spec_annos" select= + "$spec0[string-length($clause) = 0 + or position() = $clause]/anno[.=$anno]"/> + <xsl:variable name="type_annos" select= + "$i/specs/module[@name=$curModule]/type + [name=$name and n_vars=$n_vars + and (string-length($mod) = 0 or module = $mod)]/anno[.=$anno]"/> + + <xsl:if test="count($spec_annos) = 0 + and count($type_annos) = 0 + and string-length($specs_file) > 0"> + <xsl:variable name="n"> + <xsl:choose> + <xsl:when test="string-length($arity) = 0"> + <xsl:value-of select="$n_vars"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$arity"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:call-template name="err"> + <xsl:with-param name="m" select="$mod"/> + <xsl:with-param name="n" select="$name"/> + <xsl:with-param name="a" select="$n"/> + <xsl:with-param name="s">unknown annotation <xsl:value-of select="$anno"/> + </xsl:with-param> + </xsl:call-template> + </xsl:if> + <xsl:value-of select="$anno"/> + </xsl:template> + + <!-- Used for indentation of formatted types and specs --> + <xsl:template match="nbsp"> + <xsl:text> </xsl:text> + </xsl:template> + + <!-- End of Dialyzer type/spec tags --> <xsl:template match="/"> <xsl:apply-templates select="book"/> </xsl:template> - + <xsl:template match="book"> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> - <!-- Master pages --> + <!-- Master pages --> <fo:layout-master-set> <fo:simple-page-master master-name="cover" @@ -47,7 +341,7 @@ <xsl:attribute name="page-width"> <xsl:value-of select="$page-width"/> </xsl:attribute> - <fo:region-body + <fo:region-body margin="0mm"/> </fo:simple-page-master> @@ -63,7 +357,7 @@ <xsl:attribute name="page-width"> <xsl:value-of select="$page-width"/> </xsl:attribute> - <fo:region-body + <fo:region-body margin-top="15mm" margin-bottom="20mm"/> <fo:region-before @@ -100,10 +394,10 @@ <fo:page-sequence-master master-name="document"> <fo:repeatable-page-master-alternatives> - <fo:conditional-page-master-reference + <fo:conditional-page-master-reference master-reference="left-page" odd-or-even="even"/> - <fo:conditional-page-master-reference + <fo:conditional-page-master-reference master-reference="right-page" odd-or-even="odd"/> </fo:repeatable-page-master-alternatives> @@ -166,7 +460,7 @@ <fo:flow flow-name="xsl-region-body"> <fo:block> - + </fo:block> <xsl:apply-templates select="parts"/> @@ -189,7 +483,7 @@ <!-- Cover page --> <xsl:template match="header/title"> - <fo:page-sequence + <fo:page-sequence font-family="sans-serif" force-page-count="even" master-reference="cover"> @@ -242,7 +536,7 @@ the License for the specific language governing rights and limitations under the License. - The Initial Developer of the Original Code is + The Initial Developer of the Original Code is --> <xsl:value-of select="$companyname"/>. </fo:block> @@ -281,22 +575,22 @@ <xsl:template name="bookmarks1"> <xsl:param name="entries"/> <xsl:if test="$entries != ''"> - + <fo:bookmark internal-destination="{generate-id(/book/parts/part)}" starting-state="hide"> <fo:bookmark-title>User's Guide</fo:bookmark-title> - + <xsl:for-each select="$entries"> <xsl:call-template name="bookmarks2"> <xsl:with-param name="entries" select="chapter[header/title]"/> </xsl:call-template> </xsl:for-each> - + </fo:bookmark> </xsl:if> </xsl:template> - + <xsl:template name="bookmarks2"> <xsl:param name="entries"/> <xsl:for-each select="$entries"> @@ -341,7 +635,7 @@ starting-state="hide"> <fo:bookmark-title>Reference Manual</fo:bookmark-title> <xsl:for-each select="$entries"> - + <xsl:call-template name="bookmarks5"> <xsl:with-param name="entries" select="erlref[module]|comref[com]|cref[lib]|fileref[file]|appref[app]"/> @@ -387,7 +681,7 @@ <fo:bookmark internal-destination="{generate-id(nametext)}" starting-state="hide"> <xsl:variable name="fname"> <xsl:value-of select="substring-before(nametext, '(')"/> - </xsl:variable> + </xsl:variable> <fo:bookmark-title> <xsl:choose> <xsl:when test="string-length($fname) > 0"> @@ -396,7 +690,7 @@ <xsl:otherwise> <xsl:value-of select="nametext"/>() </xsl:otherwise> - </xsl:choose> + </xsl:choose> </fo:bookmark-title> </fo:bookmark> </xsl:when> @@ -404,60 +698,76 @@ <fo:bookmark internal-destination="{generate-id(.)}" starting-state="hide"> <xsl:variable name="tmpstring"> <xsl:value-of select="substring-before(substring-after(., '('), '->')"/> - </xsl:variable> + </xsl:variable> <xsl:variable name="ustring"> <xsl:choose> <xsl:when test="string-length($tmpstring) > 0"> <xsl:call-template name="remove-paren"> <xsl:with-param name="string" select="$tmpstring"/> - </xsl:call-template> + </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:call-template name="remove-paren"> <xsl:with-param name="string" select="substring-after(., '(')"/> - </xsl:call-template> + </xsl:call-template> </xsl:otherwise> </xsl:choose> - </xsl:variable> + </xsl:variable> <xsl:variable name="arity"> - <xsl:call-template name="calc-arity"> - <xsl:with-param name="string" select="substring-before($ustring, ')')"/> - <xsl:with-param name="no-of-pars" select="0"/> - </xsl:call-template> - </xsl:variable> - - <xsl:variable name="fname"> - <xsl:variable name="fname1"> - <xsl:value-of select="substring-before(., '(')"/> - </xsl:variable> - <xsl:variable name="fname2"> - <xsl:value-of select="substring-after($fname1, 'erlang:')"/> - </xsl:variable> - <xsl:choose> - <xsl:when test="string-length($fname2) > 0"> - <xsl:value-of select="$fname2"/> - </xsl:when> + <xsl:choose> + <xsl:when test="string-length(@arity) > 0"> + <!-- Dialyzer spec --> + <xsl:value-of select="@arity"/> + </xsl:when> <xsl:otherwise> - <xsl:value-of select="$fname1"/> + <xsl:call-template name="calc-arity"> + <xsl:with-param name="string" select="substring-before($ustring, ')')"/> + <xsl:with-param name="no-of-pars" select="0"/> + </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:variable> + <xsl:variable name="fname"> + <xsl:choose> + <xsl:when test="string-length(@name) > 0"> + <!-- Dialyzer spec --> + <xsl:value-of select="@name"/> + </xsl:when> + <xsl:otherwise> + <xsl:variable name="fname1"> + <xsl:value-of select="substring-before(., '(')"/> + </xsl:variable> + <xsl:variable name="fname2"> + <xsl:value-of select="substring-after($fname1, 'erlang:')"/> + </xsl:variable> + <xsl:choose> + <xsl:when test="string-length($fname2) > 0"> + <xsl:value-of select="$fname2"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$fname1"/> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <fo:bookmark-title> <xsl:value-of select="$fname"/>/<xsl:value-of select="$arity"/> </fo:bookmark-title> </fo:bookmark> </xsl:when> </xsl:choose> - + </xsl:for-each> </xsl:template> <!-- UG part --> - + <!-- Parts --> <xsl:template match="parts"> <xsl:apply-templates select="part"/> @@ -491,7 +801,7 @@ <xsl:value-of select="$partnum"/>.<xsl:number/>  <xsl:value-of select="header/title"/> </fo:marker> <xsl:value-of select="$partnum"/>.<xsl:number/>  <xsl:value-of select="header/title"/> - + </fo:block> <xsl:apply-templates select="section|quote|warning|note|br|image|marker|table|p|pre|code|list|taglist|codeinclude|erleval"> @@ -567,7 +877,7 @@ </xsl:template> <!-- Lists --> - + <xsl:template match="list"> <xsl:param name="partnum"/> <fo:list-block xsl:use-attribute-sets="listblock"> @@ -692,7 +1002,7 @@ </xsl:variable> <fo:block xsl:use-attribute-sets="code"> - <xsl:apply-templates select="text()"/> + <xsl:apply-templates select="text()"/> </fo:block> <xsl:if test="@caption"> @@ -711,7 +1021,7 @@ </xsl:variable> <fo:block xsl:use-attribute-sets="code"> - <xsl:apply-templates/> + <xsl:apply-templates/> </fo:block> <xsl:if test="@caption"> @@ -734,23 +1044,23 @@ <xsl:variable name="partnum"> <xsl:number level="any" from="book" count="part|application"/> </xsl:variable> - - <fo:block xsl:use-attribute-sets="h1" id="{generate-id()}"> + + <fo:block xsl:use-attribute-sets="h1" id="{generate-id()}"> <xsl:if test="/book/header/title"> <xsl:value-of select="$partnum"/>    <xsl:text>Reference Manual</xsl:text> - </xsl:if> + </xsl:if> </fo:block> - - + + <xsl:apply-templates select="description"> <xsl:with-param name="partnum" select="$partnum"/> </xsl:apply-templates> - + <xsl:apply-templates select="erlref|comref|cref|fileref|appref"> <xsl:with-param name="partnum" select="$partnum"/> </xsl:apply-templates> - + </xsl:template> <!-- Erlref --> @@ -763,7 +1073,7 @@ <fo:marker marker-class-name="chapter-title"> <xsl:value-of select="module"/> </fo:marker> - <xsl:value-of select="module"/> + <xsl:value-of select="module"/> </fo:block> <xsl:text>Erlang module</xsl:text> </fo:block> @@ -784,7 +1094,7 @@ <fo:marker marker-class-name="chapter-title"> <xsl:value-of select="com"/> </fo:marker> - <xsl:value-of select="com"/> + <xsl:value-of select="com"/> </fo:block> <xsl:text>Command</xsl:text> </fo:block> @@ -805,7 +1115,7 @@ <fo:marker marker-class-name="chapter-title"> <xsl:value-of select="lib"/> </fo:marker> - <xsl:value-of select="lib"/> + <xsl:value-of select="lib"/> </fo:block> <xsl:text>C Library</xsl:text> </fo:block> @@ -826,7 +1136,7 @@ <fo:marker marker-class-name="chapter-title"> <xsl:value-of select="file"/> </fo:marker> - <xsl:value-of select="file"/> + <xsl:value-of select="file"/> </fo:block> <xsl:text>Name</xsl:text> </fo:block> @@ -847,7 +1157,7 @@ <fo:marker marker-class-name="chapter-title"> <xsl:value-of select="app"/> </fo:marker> - <xsl:value-of select="app"/> + <xsl:value-of select="app"/> </fo:block> <xsl:text>Application</xsl:text> </fo:block> @@ -900,9 +1210,7 @@ <xsl:template match="func"> <xsl:param name="partnum"/> - <fo:block xsl:use-attribute-sets="function-name"> - <xsl:apply-templates select="name"/> - </fo:block> + <xsl:apply-templates select="name"/> <xsl:apply-templates select="fsummary|type|desc"> <xsl:with-param name="partnum" select="$partnum"/> @@ -914,15 +1222,35 @@ <xsl:template match="name"> <xsl:param name="partnum"/> <xsl:choose> + <!-- @arity is mandatory when referring to a specification --> + <xsl:when test="string-length(@arity) > 0"> + <xsl:call-template name="spec_name"/> + </xsl:when> + <xsl:when test="ancestor::datatype"> + <xsl:call-template name="type_name"/> + </xsl:when> + <xsl:otherwise> + <fo:block xsl:use-attribute-sets="function-name"> + <xsl:call-template name="name"> + <xsl:with-param name="partnum" select="$partnum"/> + </xsl:call-template> + </fo:block> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="name"> + <xsl:param name="partnum"/> + <xsl:choose> <xsl:when test="ancestor::cref"> <fo:block id="{generate-id(nametext)}"> - <xsl:value-of select="ret"/><xsl:text> </xsl:text><xsl:value-of select="nametext"/> - </fo:block> + <xsl:value-of select="ret"/><xsl:text> </xsl:text><xsl:value-of select="nametext"/> + </fo:block> </xsl:when> <xsl:otherwise> <fo:block id="{generate-id(.)}"> - <xsl:value-of select="."/> - </fo:block> + <xsl:value-of select="."/> + </fo:block> </xsl:otherwise> </xsl:choose> </xsl:template> @@ -931,9 +1259,9 @@ <!-- Type --> <xsl:template match="type"> <xsl:param name="partnum"/> - + <fo:block> - <xsl:text>Types:</xsl:text> + <xsl:text>Types:</xsl:text> </fo:block> <fo:list-block xsl:use-attribute-sets="type-listblock"> @@ -1001,9 +1329,9 @@ <xsl:param name="chapnum"/> <xsl:variable name="tabnum"> <xsl:number level="any" from="chapter" count="table"/> - </xsl:variable> + </xsl:variable> <fo:table xsl:use-attribute-sets="table"> - <fo:table-body> + <fo:table-body> <xsl:apply-templates select="row"> <xsl:with-param name="chapnum" select="$chapnum"/> <xsl:with-param name="tabnum" select="$tabnum"/> @@ -1107,7 +1435,7 @@ <xsl:template name="calc-arity"> <xsl:param name="string"/> <xsl:param name="no-of-pars"/> - + <xsl:variable name="length"> <xsl:value-of select="string-length($string)"/> </xsl:variable> @@ -1116,8 +1444,8 @@ <xsl:when test="$length > 0"> <xsl:call-template name="calc-arity"> <xsl:with-param name="string" select="substring-after($string, ',')"/> - <xsl:with-param name="no-of-pars" select="$no-of-pars+1"/> - </xsl:call-template> + <xsl:with-param name="no-of-pars" select="$no-of-pars+1"/> + </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$no-of-pars"/> @@ -1131,9 +1459,9 @@ <xsl:variable name="str1"> <xsl:call-template name="remove-paren-1"> <xsl:with-param name="string" select="$string"/> - <xsl:with-param name="start">(</xsl:with-param> - <xsl:with-param name="end">)</xsl:with-param> - </xsl:call-template> + <xsl:with-param name="start">(</xsl:with-param> + <xsl:with-param name="end">)</xsl:with-param> + </xsl:call-template> </xsl:variable> <xsl:variable name="str2"> @@ -1141,7 +1469,7 @@ <xsl:with-param name="string" select="$str1"/> <xsl:with-param name="start">{</xsl:with-param> <xsl:with-param name="end">}</xsl:with-param> - </xsl:call-template> + </xsl:call-template> </xsl:variable> <xsl:variable name="str3"> @@ -1149,7 +1477,7 @@ <xsl:with-param name="string" select="$str2"/> <xsl:with-param name="start">[</xsl:with-param> <xsl:with-param name="end">]</xsl:with-param> - </xsl:call-template> + </xsl:call-template> </xsl:variable> <xsl:value-of select="$str3"/> @@ -1161,7 +1489,7 @@ <xsl:param name="string"/> <xsl:param name="start"/> <xsl:param name="end"/> - + <xsl:variable name="tmp1"> <xsl:value-of select="substring-before($string, $start)"/> </xsl:variable> @@ -1174,7 +1502,7 @@ <xsl:variable name="retstring"> <xsl:call-template name="remove-paren"> <xsl:with-param name="string" select="$tmp2"/> - </xsl:call-template> + </xsl:call-template> </xsl:variable> <xsl:value-of select="concat(concat($tmp1, 'x'), $retstring)"/> </xsl:when> diff --git a/lib/erl_docgen/src/Makefile b/lib/erl_docgen/src/Makefile new file mode 100644 index 0000000000..8e81bccd59 --- /dev/null +++ b/lib/erl_docgen/src/Makefile @@ -0,0 +1,96 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2010. 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% +# + +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(ERL_DOCGEN_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/erl_docgen-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +MODULES = \ + otp_specs + +HRL_FILES = + +ERL_FILES = $(MODULES:%=%.erl) + +TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) + +APP_FILE = erl_docgen.app + +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +APPUP_FILE = erl_docgen.appup + +APPUP_SRC= $(APPUP_FILE).src +APPUP_TARGET= $(EBIN)/$(APPUP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += -I../../xmerl/include + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f core + +docs: + + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + +$(APP_TARGET): $(APP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + +release_docs_spec: + diff --git a/lib/erl_docgen/src/erl_docgen.app.src b/lib/erl_docgen/src/erl_docgen.app.src new file mode 100644 index 0000000000..1720464b6d --- /dev/null +++ b/lib/erl_docgen/src/erl_docgen.app.src @@ -0,0 +1,12 @@ +{application, erl_docgen, + [{description, "Misc tools for building documentation"}, + {vsn, "%VSN%"}, + {modules, [otp_specs + ] + }, + {registered,[]}, + {applications, [kernel,stdlib]}, + {env, [] + } + ] +}. diff --git a/lib/erl_docgen/src/erl_docgen.appup.src b/lib/erl_docgen/src/erl_docgen.appup.src new file mode 100644 index 0000000000..54a63833e6 --- /dev/null +++ b/lib/erl_docgen/src/erl_docgen.appup.src @@ -0,0 +1 @@ +{"%VSN%",[],[]}. diff --git a/lib/erl_docgen/src/otp_specs.erl b/lib/erl_docgen/src/otp_specs.erl new file mode 100644 index 0000000000..728ddb2e6e --- /dev/null +++ b/lib/erl_docgen/src/otp_specs.erl @@ -0,0 +1,701 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2010. 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% +%% + +-module(otp_specs). + +-export([module/2, package/2, overview/2, type/1]). + +-include("xmerl.hrl"). + +-define(XML_EXPORT, xmerl_xml). +-define(DEFAULT_XML_EXPORT, ?XML_EXPORT). +-define(DEFAULT_PP, erl_pp). +-define(IND(N), #xmlText{value="\n" ++ lists:duplicate(N, $\s)}). +-define(NL, "\n"). + +module(Element, Options) -> + XML = layout_module(Element, init_opts(Options)), + Export = proplists:get_value(xml_export, Options, + ?DEFAULT_XML_EXPORT), + xmerl:export_simple(XML, Export, [#xmlAttribute{name=prolog, + value=""}]). + +-record(opts, {pretty_print, file_suffix}). + +init_opts(Options) -> + #opts{pretty_print = proplists:get_value(pretty_print, + Options, ?DEFAULT_PP), + %% It *is* depending on edoc.hrl! + file_suffix = proplists:get_value(file_suffix, Options, ".html")}. + +layout_module(#xmlElement{name = module, content = Es}=E, Opts) -> + Name = get_attrval(name, E), + Functions = [{function_name(Elem), Elem} || + Elem <- get_content(functions, Es)], + Types = [{type_name(Elem), Elem} || Elem <- get_content(typedecls, Es)], + Body = [{module, + [{name,[Name]}], + ([?NL] ++ types(lists:sort(Types), Opts) + ++ functions(lists:sort(Functions), Opts) + ++ timestamp())}], + Body. + +timestamp() -> + [{timestamp, [io_lib:fwrite("Generated by EDoc, ~s, ~s.", + [edoc_lib:datestr(date()), + edoc_lib:timestr(time())])]},?NL]. + +functions(Fs, Opts) -> + lists:flatmap(fun ({Name, E}) -> function(Name, E, Opts) end, Fs). + +function(Name, #xmlElement{content = Es}, Opts) -> + TS = get_content(typespec, Es), + Spec = typespec(TS, Opts), + [{spec,(Name + ++ [?IND(2),{contract,Spec}] + ++ typespec_annos(TS))}, + ?NL]. + +function_name(E) -> + [] = get_attrval(module, E), + [?IND(2),{name,[atom(get_attrval(name, E))]}, + ?IND(2),{arity,[get_attrval(arity, E)]}]. + +label_anchor(Content, E) -> + case get_attrval(label, E) of + "" -> Content; + Ref -> [{marker, [{id, Ref}], Content}] + end. + +typespec([], _Opts) -> []; +typespec(Es, Opts) -> + {Head, LDefs} = collect_clause(Es, Opts), + clause(Head, LDefs) ++ [?IND(2)]. + +collect_clause(Es, Opts) -> + Name = t_name(get_elem(erlangName, Es)), + Defs = get_elem(localdef, Es), + [Type] = get_elem(type, Es), + {format_spec(Name, Type, Opts), collect_local_defs(Defs, Opts)}. + +clause(Head, LDefs) -> + FC = [?IND(6),{head,Head}] ++ local_clause_defs(LDefs), + [?IND(4),{clause,FC}]. + +local_clause_defs([]) -> []; +local_clause_defs(LDefs) -> + LocalDefs = [{subtype,T} || T <- coalesce_local_defs(LDefs, [])], + [?IND(6),{guard,margin(8, LocalDefs)}]. + +types(Ts, Opts) -> + lists:flatmap(fun ({Name, E}) -> typedecl(Name, E, Opts) end, Ts). + +typedecl(Name, E=#xmlElement{content = Es}, Opts) -> + TD = get_content(typedef, Es), + TypeDef = typedef(E, TD, Opts), + [{type,(Name + ++ [?IND(2),{typedecl, TypeDef}] + ++ typedef_annos(TD))}, + ?NL]. + +type_name(#xmlElement{content = Es}) -> + Typedef = get_content(typedef, Es), + [E] = get_elem(erlangName, Typedef), + Args = get_content(argtypes, Typedef), + [] = get_attrval(module, E), + [?IND(2),{name,[atom(get_attrval(name, E))]}, + ?IND(2),{n_vars,[integer_to_list(length(Args))]}]. + +typedef(E, Es, Opts) -> + Ns = get_elem(erlangName, Es), + Name = + ([t_name(Ns), "("] + ++ seq(fun t_utype_elem/1, get_content(argtypes, Es), [")"])), + LDefs = collect_local_defs(get_elem(localdef, Es), Opts), + TypeHead = case get_elem(type, Es) of + [] -> label_anchor(Name, E); + Type -> (label_anchor(Name, E) + ++ format_type(Name, Type, Opts)) + end, + ([?IND(6),{typehead,TypeHead}] + ++ local_type_defs(LDefs, [])). + +local_type_defs([], _) -> []; +local_type_defs(LDefs, Last) -> + LocalDefs = [{local_def,T} || T <- coalesce_local_defs(LDefs, Last)], + [?IND(6),{local_defs,margin(8, LocalDefs)}]. + +collect_local_defs(Es, Opts) -> + [collect_localdef(E, Opts) || E <- Es]. + +collect_localdef(E = #xmlElement{content = Es}, Opts) -> + Name = case get_elem(typevar, Es) of + [] -> + label_anchor(N0 = t_abstype(get_content(abstype, Es)), E); + [V] -> + N0 = t_var(V) + end, + {Name,N0,format_type(N0, get_elem(type, Es), Opts)}. + +%% "A = t(), B = t()" is coalesced into "A = B = t()". +%% Names as B above are kept, but the formated string is empty. +coalesce_local_defs([], _Last) -> + []; +coalesce_local_defs([{Name,N0,TypeS} | L], Last) when Name =:= N0 -> + cld(L, [{Name,N0}], TypeS, Last); +coalesce_local_defs([{Name,N0,TypeS} | L], Last) -> + [local_def(N0, Name, TypeS, Last, L) | coalesce_local_defs(L, Last)]. + +cld([{Name,N0,TypeS} | L], Names, TypeS, Last) when Name =:= N0 -> + cld(L, [{Name,N0} | Names], TypeS, Last); +cld(L, Names0, TypeS, Last) -> + Names = [{_,Name0} | Names1] = lists:reverse(Names0), + NS = join([N || {N,_} <- Names], [" = "]), + ([local_def(Name0, NS, TypeS, Last, L) | + [local_def(N0, "", "", [], L) || {_,N0} <- Names1]] + ++ coalesce_local_defs(L, Last)). + +local_def(Name, NS, TypeS, Last, L) -> + [{typename,Name},{string,NS ++ TypeS ++ [Last || L =:= []]}]. + +%% join([], Sep) when is_list(Sep) -> +%% []; +join([H|T], Sep) -> + H ++ lists:append([Sep ++ X || X <- T]). + +%% Use the default formatting of EDoc, which creates references, and +%% then insert newlines and indentation according to erl_pp (the +%% (fast) Erlang pretty printer). +format_spec(Name, Type, #opts{pretty_print = erl_pp}=Opts) -> + try + L = t_clause(Name, Type), + O = pp_clause(Name, Type), + {R, ".\n"} = diaf(L, O, Opts), + R + catch _:_ -> + %% Example: "@spec ... -> record(a)" + format_spec(Name, Type, Opts#opts{pretty_print=default}) + end; +format_spec(Sep, Type, _Opts) -> + t_clause(Sep, Type). + +t_clause(Name, Type) -> + #xmlElement{content = [#xmlElement{name = 'fun', content = C}]} = Type, + [Name] ++ t_fun(C). + +pp_clause(Pre, Type) -> + Types = ot_utype([Type]), + Atom = lists:duplicate(iolist_size(Pre), $a), + L1 = erl_pp:attribute({attribute,0,spec,{{list_to_atom(Atom),0},[Types]}}), + "-spec " ++ L2 = lists:flatten(L1), + L3 = Pre ++ lists:nthtail(length(Atom), L2), + re:replace(L3, "\n ", "\n", [{return,list},global]). + +format_type(Name, Type, #opts{pretty_print = erl_pp}=Opts) -> + try + L = t_utype(Type), + O = pp_type(Name, Type), + {R, ".\n"} = diaf(L, O, Opts), + [" = "] ++ R + catch _:_ -> + %% Example: "t() = record(a)." + format_type(Name, Type, Opts#opts{pretty_print=default}) + end; +format_type(_Name, Type, _Opts) -> + [" = "] ++ t_utype(Type). + +pp_type(Prefix, Type) -> + Atom = list_to_atom(lists:duplicate(iolist_size(Prefix), $a)), + L1 = erl_pp:attribute({attribute,0,type,{Atom,ot_utype(Type),[]}}), + {L2,N} = case lists:dropwhile(fun(C) -> C =/= $: end, lists:flatten(L1)) of + ":: " ++ L3 -> {L3,9}; % compensation for extra "()" and ":" + "::\n" ++ L3 -> {"\n"++L3,6} + end, + Ss = lists:duplicate(N, $\s), + re:replace(L2, "\n"++Ss, "\n", [{return,list},global]). + +diaf(L, O0, Opts) -> + {R0, O} = diaf(L, [], O0, [], Opts), + R1 = rewrite_some_predefs(lists:reverse(R0)), + R = indentation(lists:flatten(R1)), + {R, O}. + +diaf([C | L], St, [C | O], R, Opts) -> + diaf(L, St, O, [[C] | R], Opts); +diaf(" "++L, St, O, R, Opts) -> + diaf(L, St, O, R, Opts); +diaf("", [Cs | St], O, R, Opts) -> + diaf(Cs, St, O, R, Opts); +diaf("", [], O, R, _Opts) -> + {R, O}; +diaf(L, St, " "++O, R, Opts) -> + diaf(L, St, O, [" " | R], Opts); +diaf(L, St, "\n"++O, R, Opts) -> + Ss = lists:takewhile(fun(C) -> C =:= $\s end, O), + diaf(L, St, lists:nthtail(length(Ss), O), ["\n"++Ss | R], Opts); +diaf([{seealso, HRef0, S0} | L], St, O0, R, Opts) -> + {S, O} = diaf(S0, app_fix(O0), Opts), + HRef = fix_mod_ref(HRef0, Opts), + diaf(L, St, O, [{seealso, HRef, S} | R], Opts); +diaf("="++L, St, "::"++O, R, Opts) -> + %% EDoc uses "=" for record field types; Dialyzer uses "::". Maybe + %% there should be an option for this, possibly affecting other + %% similar discrepancies. + diaf(L, St, O, ["=" | R], Opts); +diaf([Cs | L], St, O, R, Opts) -> + diaf(Cs, [L | St], O, R, Opts). + +rewrite_some_predefs(S) -> + xpredef(lists:flatten(S)). + +xpredef([]) -> + []; +xpredef("neg_integer()"++L) -> + ["integer() =< -1"] ++ xpredef(L); +xpredef("non_neg_integer()"++L) -> + ["integer() >= 0"] ++ xpredef(L); +xpredef("pos_integer()"++L) -> + ["integer() >= 1"] ++ xpredef(L); +xpredef([T | Es]) when is_tuple(T) -> + [T | xpredef(Es)]; +xpredef([E | Es]) -> + [[E] | xpredef(Es)]. + +indentation([]) -> + []; +indentation([$\n|L]) -> + [{br,[]}|indent(L)]; +indentation([T | Es]) when is_tuple(T) -> + [T | indentation(Es)]; +indentation([E|L]) -> + [[E]|indentation(L)]. + +indent([$\s|L]) -> + [{nbsp,[]}|indent(L)]; +indent(L) -> + indentation(L). + +app_fix(L) -> + try + {"//" ++ R1,L2} = app_fix(L, 1), + [App, Mod] = string:tokens(R1, "/"), + "//" ++ atom(App) ++ "/" ++ atom(Mod) ++ L2 + catch _:_ -> L + end. + +app_fix(L, I) -> % a bit slow + {L1, L2} = lists:split(I, L), + case erl_scan:tokens([], L1 ++ ". ", 1) of + {done, {ok,[{atom,_,Atom}|_],_}, _} -> {atom_to_list(Atom), L2}; + _ -> app_fix(L, I+1) + end. + +%% Remove the file suffix from module references. +fix_mod_ref(HRef, #opts{file_suffix = ""}) -> + HRef; +fix_mod_ref([{marker, S}]=HRef0, #opts{file_suffix = FS}) -> + {A, B} = lists:splitwith(fun(C) -> C =/= $# end, S), + case lists:member($:, A) of + true -> + HRef0; % should "save" most application references "http:" + false -> + case {lists:suffix(FS, A), B} of + {true, "#"++_} -> + [{marker, lists:sublist(A, length(A)-length(FS)) ++ B}]; + _ -> + HRef0 + end + end. + +see(E, Es) -> + case href(E) of + [] -> Es; + Ref -> + [{seealso, Ref, Es}] + end. + +href(E) -> + case get_attrval(href, E) of + "" -> []; + URI -> + [{marker, URI}] + end. + +atom(String) -> + io_lib:write_atom(list_to_atom(String)). + +t_name([E]) -> + N = get_attrval(name, E), + case get_attrval(module, E) of + "" -> atom(N); + M -> + S = atom(M) ++ ":" ++ atom(N), + case get_attrval(app, E) of + "" -> S; + A -> "//" ++ atom(A) ++ "/" ++ S + end + end. + +t_utype([E]) -> + t_utype_elem(E). + +t_utype_elem(E=#xmlElement{content = Es}) -> + case get_attrval(name, E) of + "" -> t_type(Es); + Name -> + T = t_type(Es), + case T of + [Name] -> T; % avoid generating "Foo::Foo" + T -> [Name] ++ ["::"] ++ T + end + end. + +t_type([E=#xmlElement{name = typevar}]) -> + t_var(E); +t_type([E=#xmlElement{name = atom}]) -> + t_atom(E); +t_type([E=#xmlElement{name = integer}]) -> + t_integer(E); +t_type([E=#xmlElement{name = range}]) -> + t_range(E); +t_type([E=#xmlElement{name = binary}]) -> + t_binary(E); +t_type([E=#xmlElement{name = float}]) -> + t_float(E); +t_type([#xmlElement{name = nil}]) -> + t_nil(); +t_type([#xmlElement{name = list, content = Es}]) -> + t_list(Es); +t_type([#xmlElement{name = nonempty_list, content = Es}]) -> + t_nonempty_list(Es); +t_type([#xmlElement{name = tuple, content = Es}]) -> + t_tuple(Es); +t_type([#xmlElement{name = 'fun', content = Es}]) -> + ["fun("] ++ t_fun(Es) ++ [")"]; +t_type([E = #xmlElement{name = record, content = Es}]) -> + t_record(E, Es); +t_type([E = #xmlElement{name = abstype, content = Es}]) -> + t_abstype(E, Es); +t_type([#xmlElement{name = union, content = Es}]) -> + t_union(Es). + +t_var(E) -> + [get_attrval(name, E)]. + +t_atom(E) -> + [get_attrval(value, E)]. + +t_integer(E) -> + [get_attrval(value, E)]. + +t_range(E) -> + [get_attrval(value, E)]. + +t_binary(E) -> + [get_attrval(value, E)]. + +t_float(E) -> + [get_attrval(value, E)]. + +t_nil() -> + ["[]"]. + +t_list(Es) -> + ["["] ++ t_utype(get_elem(type, Es)) ++ ["]"]. + +t_nonempty_list(Es) -> + ["["] ++ t_utype(get_elem(type, Es)) ++ [", ...]"]. + +t_tuple(Es) -> + ["{"] ++ seq(fun t_utype_elem/1, Es, ["}"]). + +t_fun(Es) -> + ["("] ++ seq(fun t_utype_elem/1, get_content(argtypes, Es), + [") -> "] ++ t_utype(get_elem(type, Es))). + +t_record(E, Es) -> + Name = ["#"] ++ t_type(get_elem(atom, Es)), + case get_elem(field, Es) of + [] -> + see(E, [Name, "{}"]); + Fs -> + see(E, Name) ++ ["{"] ++ seq(fun t_field/1, Fs, ["}"]) + end. + +t_field(#xmlElement{content = Es}) -> + t_type(get_elem(atom, Es)) ++ [" = "] ++ t_utype(get_elem(type, Es)). + +t_abstype(E, Es) -> + Name = t_name(get_elem(erlangName, Es)), + case get_elem(type, Es) of + [] -> + see(E, [Name, "()"]); + Ts -> + see(E, [Name]) ++ ["("] ++ seq(fun t_utype_elem/1, Ts, [")"]) + end. + +t_abstype(Es) -> + ([t_name(get_elem(erlangName, Es)), "("] + ++ seq(fun t_utype_elem/1, get_elem(type, Es), [")"])). + +t_union(Es) -> + seq(fun t_utype_elem/1, Es, " | ", []). + +seq(F, Es, Tail) -> + seq(F, Es, ", ", Tail). + +seq(F, [E], _Sep, Tail) -> + F(E) ++ Tail; +seq(F, [E | Es], Sep, Tail) -> + F(E) ++ [Sep] ++ seq(F, Es, Sep, Tail); +seq(_F, [], _Sep, Tail) -> + Tail. + +get_elem(Name, [#xmlElement{name = Name} = E | Es]) -> + [E | get_elem(Name, Es)]; +get_elem(Name, [_ | Es]) -> + get_elem(Name, Es); +get_elem(_, []) -> + []. + +get_attr(Name, [#xmlAttribute{name = Name} = A | As]) -> + [A | get_attr(Name, As)]; +get_attr(Name, [_ | As]) -> + get_attr(Name, As); +get_attr(_, []) -> + []. + +get_attrval(Name, #xmlElement{attributes = As}) -> + case get_attr(Name, As) of + [#xmlAttribute{value = V}] -> + V; + [] -> "" + end. + +get_content(Name, Es) -> + case get_elem(Name, Es) of + [#xmlElement{content = Es1}] -> + Es1; + [] -> [] + end. + +overview(_, _Options) -> []. + +package(_, _Options) -> []. + +type(_) -> []. + +%% --------------------------------------------------------------------- + +ot_utype([E]) -> + ot_utype_elem(E). + +ot_utype_elem(E=#xmlElement{content = Es}) -> + case get_attrval(name, E) of + "" -> ot_type(Es); + N -> + Name = {var,0,list_to_atom(N)}, + T = ot_type(Es), + case T of + Name -> T; + T -> {ann_type,0,[Name, T]} + end + end. + +ot_type([E=#xmlElement{name = typevar}]) -> + ot_var(E); +ot_type([E=#xmlElement{name = atom}]) -> + ot_atom(E); +ot_type([E=#xmlElement{name = integer}]) -> + ot_integer(E); +ot_type([E=#xmlElement{name = range}]) -> + ot_range(E); +ot_type([E=#xmlElement{name = binary}]) -> + ot_binary(E); +ot_type([E=#xmlElement{name = float}]) -> + ot_float(E); +ot_type([#xmlElement{name = nil}]) -> + ot_nil(); +ot_type([#xmlElement{name = list, content = Es}]) -> + ot_list(Es); +ot_type([#xmlElement{name = nonempty_list, content = Es}]) -> + ot_nonempty_list(Es); +ot_type([#xmlElement{name = tuple, content = Es}]) -> + ot_tuple(Es); +ot_type([#xmlElement{name = 'fun', content = Es}]) -> + ot_fun(Es); +ot_type([#xmlElement{name = record, content = Es}]) -> + ot_record(Es); +ot_type([#xmlElement{name = abstype, content = Es}]) -> + ot_abstype(Es); +ot_type([#xmlElement{name = union, content = Es}]) -> + ot_union(Es). + +ot_var(E) -> + {var,0,list_to_atom(get_attrval(name, E))}. + +ot_atom(E) -> + {ok, [Atom], _} = erl_scan:string(get_attrval(value, E), 0), + Atom. + +ot_integer(E) -> + {integer,0,list_to_integer(get_attrval(value, E))}. + +ot_range(E) -> + [I1, I2] = string:tokens(get_attrval(value, E), "."), + {type,0,range,[{integer,0,list_to_integer(I1)}, + {integer,0,list_to_integer(I2)}]}. + +ot_binary(E) -> + {Base, Unit} = + case string:tokens(get_attrval(value, E), ",:*><") of + [] -> + {0, 0}; + ["_",B] -> + {list_to_integer(B), 0}; + ["_","_",U] -> + {0, list_to_integer(U)}; + ["_",B,_,"_",U] -> + {list_to_integer(B), list_to_integer(U)} + end, + {type,0,binary,[{integer,0,Base},{integer,0,Unit}]}. + +ot_float(E) -> + {float,0,list_to_float(get_attrval(value, E))}. + +ot_nil() -> + {nil,0}. + +ot_list(Es) -> + {type,0,list,[ot_utype(get_elem(type, Es))]}. + +ot_nonempty_list(Es) -> + {type,0,nonempty_list,[ot_utype(get_elem(type, Es))]}. + +ot_tuple(Es) -> + {type,0,tuple,[ot_utype_elem(E) || E <- Es]}. + +ot_fun(Es) -> + Range = ot_utype(get_elem(type, Es)), + Args = [ot_utype_elem(A) || A <- get_content(argtypes, Es)], + {type,0,'fun',[{type,0,product,Args},Range]}. + +ot_record(Es) -> + {type,0,record,[ot_type(get_elem(atom, Es)) | + [ot_field(F) || F <- get_elem(field, Es)]]}. + +ot_field(#xmlElement{content = Es}) -> + {type,0,field_type, + [ot_type(get_elem(atom, Es)), ot_utype(get_elem(type, Es))]}. + +ot_abstype(Es) -> + ot_name(get_elem(erlangName, Es), + [ot_utype_elem(Elem) || Elem <- get_elem(type, Es)]). + +ot_union(Es) -> + {type,0,union,[ot_utype_elem(E) || E <- Es]}. + +ot_name(Es, T) -> + case ot_name(Es) of + [Mod, ":", Atom] -> + {remote_type,0,[{atom,0,list_to_atom(Mod)}, + {atom,0,list_to_atom(Atom)},T]}; + "tuple" when T =:= [] -> + {type,0,tuple,any}; + Atom -> + {type,0,list_to_atom(Atom),T} + end. + +ot_name([E]) -> + Atom = get_attrval(name, E), + case get_attrval(module, E) of + "" -> Atom; + M -> + case get_attrval(app, E) of + "" -> + [M, ":", Atom]; + A -> + ["//"++A++"/" ++ M, ":", Atom] % EDoc only! + end + end. + +%% Returns exactly those annotations that can be referred to. Note +%% that a Dialyzer type/spec (currently) can have more annotations +%% than can be represented by EDoc types. Note also that edoc_dia +%% has annotated all type variables with themselves. +typespec_annos([]) -> [?NL]; +typespec_annos([_|Es]) -> + annotations(clause_annos(Es)). + +clause_annos(Es) -> + [annos(get_elem(type, Es)), local_defs_annos(get_elem(localdef, Es))]. + +typedef_annos(Es) -> + annotations([(case get_elem(type, Es) of + [] -> []; + T -> annos(T) + end + ++ lists:flatmap(fun annos_elem/1, + get_content(argtypes, Es))), + local_defs_annos(get_elem(localdef, Es))]). + +local_defs_annos(Es) -> + lists:flatmap(fun localdef_annos/1, Es). + +localdef_annos(#xmlElement{content = Es}) -> + annos(get_elem(type, Es)). + +annotations(AnnoL) -> + Annos = lists:usort(lists:flatten(AnnoL)), + margin(2, Annos). + +margin(N, L) -> + lists:append([[?IND(N),E] || E <- L]) ++ [?IND(N-2)]. + +annos([E]) -> + annos_elem(E). + +annos_elem(E=#xmlElement{content = Es}) -> + case get_attrval(name, E) of + "" -> annos_type(Es); + "..." -> annos_type(Es); % compensate for a kludge in edoc_dia.erl + N -> + [{anno,[N]} | annos_type(Es)] + end. + +annos_type([#xmlElement{name = list, content = Es}]) -> + annos(get_elem(type, Es)); +annos_type([#xmlElement{name = nonempty_list, content = Es}]) -> + annos(get_elem(type, Es)); +annos_type([#xmlElement{name = tuple, content = Es}]) -> + lists:flatmap(fun annos_elem/1, Es); +annos_type([#xmlElement{name = 'fun', content = Es}]) -> + (annos(get_elem(type, Es)) + ++ lists:flatmap(fun annos_elem/1, get_content(argtypes, Es))); +annos_type([#xmlElement{name = record, content = Es}]) -> + lists:append([annos(get_elem(type, Es1)) || + #xmlElement{content = Es1} <- get_elem(field, Es)]); +annos_type([#xmlElement{name = abstype, content = Es}]) -> + lists:flatmap(fun annos_elem/1, get_elem(type, Es)); +annos_type([#xmlElement{name = union, content = Es}]) -> + lists:flatmap(fun annos_elem/1, Es); +annos_type([E=#xmlElement{name = typevar}]) -> + annos_elem(E); +annos_type(_) -> + []. |