aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Bolinder <[email protected]>2011-05-05 14:22:18 +0200
committerHans Bolinder <[email protected]>2011-05-16 13:33:08 +0200
commit38b2f44764e79a34048f686d98b6d741d18738d2 (patch)
treeedc44f6a2f7a71e37cd1c18d113817a671cfe6b0
parente375165f6421c86fb245843d787e021d5b7dd00d (diff)
downloadotp-38b2f44764e79a34048f686d98b6d741d18738d2.tar.gz
otp-38b2f44764e79a34048f686d98b6d741d18738d2.tar.bz2
otp-38b2f44764e79a34048f686d98b6d741d18738d2.zip
Improve erl_docgen's support for Dialyzer specs and types
The support for using Dialyzer specifications and types has been improved.
-rw-r--r--lib/erl_docgen/priv/bin/specs_gen.escript101
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl556
-rw-r--r--lib/erl_docgen/priv/xsl/db_man.xsl424
-rw-r--r--lib/erl_docgen/priv/xsl/db_pdf.xsl451
-rw-r--r--lib/erl_docgen/src/otp_specs.erl14
-rw-r--r--make/otp.mk.in5
6 files changed, 1069 insertions, 482 deletions
diff --git a/lib/erl_docgen/priv/bin/specs_gen.escript b/lib/erl_docgen/priv/bin/specs_gen.escript
index 840fed6dd5..982afece7f 100644
--- a/lib/erl_docgen/priv/bin/specs_gen.escript
+++ b/lib/erl_docgen/priv/bin/specs_gen.escript
@@ -2,7 +2,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010. All Rights Reserved.
+%% Copyright Ericsson AB 2011. 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
@@ -29,7 +29,7 @@
%%% "-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.
+%%% A empty specifications 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
@@ -67,34 +67,73 @@ usage() ->
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)
+ ReadOpts = [{includes, InclFs}, {preprocess, true}],
+ ExtractOpts = [{report_missing_type, false}],
+ LayoutOpts = [{pretty_printer, erl_pp}, {layout, otp_specs}],
+ File = case FileSpec of
+ {file, File0} -> File0;
+ {module, Module0} -> Module0
+ end,
+ try
+ Fs = case FileSpec of
+ {file, _} ->
+ Fs0 = read_file(File, ReadOpts),
+ clauses(Fs0);
+ {module, Module} ->
+ [{attribute,0,module,list_to_atom(Module)}]
+ end,
+ Doc = extract(File, Fs, ExtractOpts),
+ Text = edoc:layout(Doc, LayoutOpts),
+ ok = write_text(Text, File, Dir),
+ rename(Dir, File)
catch
_:_ ->
io:format("EDoc could not process file '~s'\n", [File]),
- clean_up(Dir, File, TmpFile),
+ clean_up(Dir),
halt(3)
end.
+read_file(File, Opts) ->
+ edoc:read_source(File, Opts).
+
+extract(File, Forms, Opts) ->
+ Env = edoc_lib:get_doc_env([], [], [], _Opts=[]),
+ {_Module, Doc} = edoc_extract:source(Forms, File, Env, Opts),
+ Doc.
+
+clauses(Fs) ->
+ clauses(Fs, no).
+
+clauses([], no) ->
+ [];
+clauses([F | Fs], Spec) ->
+ case F of
+ {attribute,_,spec,_} ->
+ clauses(Fs, F);
+ {function,_,_N,_A,_Cls} when Spec =/= no->
+ {attribute,_,spec,{Name,FunTypes}} = Spec,
+ %% [throw({no,Name,{_N,_A}}) || Name =/= {_N,_A}],
+ %% EDoc doesn't care if a function appears more than once;
+ %% this is how overloaded specs are handled:
+ (lists:append([[setelement(4, Spec, {Name,[T]}),F] ||
+ T <- FunTypes])
+ ++ clauses(Fs, no));
+ _ ->
+ [F | clauses(Fs, Spec)]
+ end.
+
+write_text(Text, File, Dir) ->
+ Base = filename:basename(File, ".erl"),
+ OutFile = filename:join(Dir, Base) ++ ".specs",
+ case file:write_file(OutFile, Text) of
+ ok ->
+ ok;
+ {error, R} ->
+ R1 = file:format_error(R),
+ io:format("could not write file '~s': ~s\n", [File, R1]),
+ halt(2)
+ end.
+
rename(Dir, F) ->
Mod = filename:basename(F, ".erl"),
Old = filename:join(Dir, Mod ++ ".specs"),
@@ -108,22 +147,10 @@ rename(Dir, F) ->
halt(2)
end.
-clean_up(Dir, File, TmpFile) ->
- [file:delete(File) || TmpFile],
+clean_up(Dir) ->
_ = [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/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index c6375ea621..982572aeef 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -22,12 +22,15 @@
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common"
+ extension-element-prefixes="exsl"
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"
+ See also the templates matching "name" and "seealso" as well as
+ the template "menu.funcs"
-->
<xsl:param name="specs_file" select="''"/>
@@ -38,49 +41,58 @@
<xsl:key name="mod2app" match="module" use="@name"/>
<xsl:template name="err">
+ <xsl:param name="f"/>
<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"/>
+ Error <xsl:if test="$f != ''">in <xsl:value-of select ="$f"/>:</xsl:if>
+ <xsl:if test="$m != ''"><xsl:value-of select ="$m"/>:</xsl:if>
+ <xsl:value-of select="$n"/>
+ <xsl:if test="$a != ''">/<xsl:value-of
+ select ="$a"/></xsl:if>: <xsl:value-of select="$s"/>
</xsl:message>
</xsl:template>
- <xsl:template name="spec_name">
+ <xsl:template name="find_spec">
<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="clause_i" select="@clause_i"/>
<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:variable name="spec" select="$spec0[string-length($clause_i) = 0
+ or position() = $clause_i]"/>
+
+ <xsl:if test="count($spec) != 1">
+ <xsl:variable name="why">
+ <xsl:choose>
+ <xsl:when test="count($spec) > 1">ambiguous spec</xsl:when>
+ <xsl:when test="count($spec) = 0">unknown spec</xsl:when>
+ </xsl:choose>
+ </xsl:variable>
<xsl:call-template name="err">
+ <xsl:with-param name="f" select="$curModule"/>
<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:with-param name="s" select="$why"/>
</xsl:call-template>
</xsl:if>
+ <xsl:copy-of select="$spec"/>
+ </xsl:template>
- <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:template name="spec_name">
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="spec0">
+ <xsl:call-template name="find_spec"/>
</xsl:variable>
+ <xsl:variable name="spec" select="exsl:node-set($spec0)/spec"/>
<xsl:choose>
<xsl:when test="ancestor::cref">
@@ -89,72 +101,189 @@
</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 test="preceding-sibling::name[position() = 1
+ and @name = $name and @arity = $arity]">
+ <!-- Avoid duplicated anchors.-->
+ </xsl:when>
+ <xsl:otherwise>
+ <a name="{$name}-{$arity}"></a>
+ </xsl:otherwise>
</xsl:choose>
+
+ <xsl:variable name="global_types" select="ancestor::erlref/datatypes"/>
+ <xsl:variable name="local_types"
+ select="../type[string-length(@name) > 0]"/>
+ <xsl:apply-templates select="$spec/contract/clause/head">
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ </xsl:apply-templates>
</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:param name="local_types"/>
+ <xsl:param name="global_types"/>
<span class="bold_code">
- <xsl:apply-templates/>
+ <xsl:apply-templates mode="local_type">
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ </xsl:apply-templates>
</span>
<br/>
</xsl:template>
- <xsl:template name="guard">
- <xsl:param name="guard"/>
+ <!-- The *last* <name name="..." arity=".."/> -->
+ <xsl:template match="name" mode="types">
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="spec0">
+ <xsl:call-template name="find_spec"/>
+ </xsl:variable>
+ <xsl:variable name="spec" select="exsl:node-set($spec0)/spec"/>
+ <xsl:variable name="clause" select="$spec/contract/clause"/>
+
+ <xsl:variable name="global_types" select="ancestor::erlref/datatypes"/>
+ <xsl:variable name="type_desc" select="../type_desc"/>
+ <!-- $type is data types to be presented as guards ("local types") -->
+ <xsl:variable name="type"
+ select="../type[string-length(@name) > 0
+ or string-length(@variable) > 0]"/>
+ <xsl:variable name="type_variables"
+ select ="$type[string-length(@variable) > 0]"/>
+ <xsl:variable name="local_types"
+ select ="$type[string-length(@name) > 0]"/>
+ <xsl:variable name="output_subtypes" select="count($type_variables) = 0"/>
+
+ <!-- It is assumed there is no support for overloaded specs
+ (there is no spec with more than one clause) -->
+ <xsl:if test="count($clause/guard) > 0 or count($type) > 0">
+ <div class="REFBODY"><p>Types:</p>
+
+ <xsl:choose>
+ <xsl:when test="$output_subtypes">
+ <xsl:call-template name="subtype">
+ <xsl:with-param name="subtype" select="$clause/guard/subtype"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="type_variables">
+ <xsl:with-param name="type_variables" select="$type_variables"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ <xsl:with-param name="fname" select="$name"/>
+ <xsl:with-param name="arity" select="$arity"/>
+ </xsl:call-template>
+
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:call-template name="local_type">
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ </xsl:call-template>
+ </div>
+
+ </xsl:if>
+ </xsl:template>
+
+ <!-- Handle <type variable="..." name_i="..."/> -->
+ <xsl:template name="type_variables">
+ <xsl:param name="type_variables"/>
<xsl:param name="type_desc"/>
- <div class="REFBODY"><p>Types:</p>
+ <xsl:param name="local_types"/>
+ <xsl:param name="global_types"/>
+ <xsl:param name="fname"/>
+ <xsl:param name="arity"/>
+
+ <xsl:variable name="names" select="../name[string-length(@arity) > 0]"/>
+ <xsl:for-each select="$type_variables">
+ <xsl:variable name="name_i">
+ <xsl:choose>
+ <xsl:when test="string-length(@name_i) > 0">
+ <xsl:value-of select="@name_i"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="count($names)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="spec0">
+ <xsl:for-each select="$names[position() = $name_i]">
+ <xsl:call-template name="find_spec"/>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="spec" select="exsl:node-set($spec0)/spec"/>
+ <xsl:variable name="clause" select="$spec/contract/clause"/>
+ <xsl:variable name="variable" select="@variable"/>
+ <xsl:variable name="subtype"
+ select="$clause/guard/subtype[typename = $variable]"/>
+
+ <xsl:if test="count($subtype) = 0">
+ <xsl:call-template name="err">
+ <xsl:with-param name="f" select="ancestor::erlref/module"/>
+ <xsl:with-param name="n" select="$fname"/>
+ <xsl:with-param name="a" select="$arity"/>
+ <xsl:with-param name="s">unknown type variable <xsl:value-of select="$variable"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
<xsl:call-template name="subtype">
- <xsl:with-param name="subtype" select="$guard/subtype"/>
- <xsl:with-param name="type_desc" select="$type_desc"/>
+ <xsl:with-param name="subtype" select="$subtype"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
</xsl:call-template>
- </div>
+ </xsl:for-each>
</xsl:template>
<xsl:template name="subtype">
<xsl:param name="subtype"/>
<xsl:param name="type_desc"/>
+ <xsl:param name="local_types"/>
+ <xsl:param name="global_types"/>
+
<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"/>
+ <xsl:apply-templates select="string" mode="local_type">
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ </xsl:apply-templates>
</span>
</div>
- <xsl:apply-templates select="$type_desc[@name = $tname]"/>
+ <xsl:apply-templates select="$type_desc[@variable = $tname]"/>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="local_type">
+ <xsl:param name="type_desc"/>
+ <xsl:param name="local_types"/>
+ <xsl:param name="global_types"/>
+
+ <xsl:for-each select="$local_types">
+ <div class="REFTYPES">
+ <xsl:call-template name="type_name">
+ <xsl:with-param name="mode" select="'local_type'"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ </xsl:call-template>
+ </div>
+ <xsl:variable name="tname" select="@name"/>
+ <xsl:variable name="tnvars" select="@n_vars"/>
+ <xsl:apply-templates select=
+ "$type_desc[@name = $tname
+ and (@n_vars = $tnvars
+ or string-length(@n_vars) = 0 and
+ string-length($tnvars) = 0)]"/>
</xsl:for-each>
</xsl:template>
@@ -193,130 +322,175 @@
<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>
+ <!-- The "mode" attribute of apply has been used to separate the case
+ when datatypes are copied into specifications' subtypes.
+ A local type has no anchor. There are no links to local types
+ from local types or guards/head of the same specification.
+ -->
<xsl:template name="type_name">
+ <xsl:param name="mode"/> <!-- '' if <datatype> -->
+ <xsl:param name="local_types" select="/.."/>
+ <xsl:param name="global_types" select="/.."/>
<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:variable name="n_vars" select="@n_vars"/>
<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
+ [name=$name
+ and (string-length($n_vars) = 0 or n_vars = $n_vars)
and (string-length($mod) = 0 or module = $mod)]"/>
<xsl:if test="count($type) != 1">
+ <xsl:variable name="why">
+ <xsl:choose>
+ <xsl:when test="count($type) > 1">ambiguous type</xsl:when>
+ <xsl:when test="count($type) = 0">unknown type</xsl:when>
+ </xsl:choose>
+ </xsl:variable>
<xsl:call-template name="err">
+ <xsl:with-param name="f" select="$curModule"/>
<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:with-param name="s" select="$why"/>
</xsl:call-template>
</xsl:if>
- <xsl:apply-templates select="$type/typedecl"/>
+ <xsl:choose>
+ <xsl:when test="$mode = ''">
+ <xsl:apply-templates select="$type/typedecl"/>
+ </xsl:when>
+ <xsl:when test="$mode = 'local_type'">
+ <xsl:apply-templates select="$type/typedecl" mode="local_type">
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ </xsl:apply-templates>
+ </xsl:when>
+ </xsl:choose>
</xsl:when>
- <xsl:otherwise>
+ <xsl:otherwise> <!-- <datatype> with <name> -->
<span class="bold_code">
- <xsl:value-of select="."/>
+ <xsl:apply-templates/>
</span>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
+ <xsl:template match="typehead">
+ <span class="bold_code">
+ <xsl:apply-templates/>
+ </span><br/>
+ </xsl:template>
+
+ <xsl:template match="typehead" mode="local_type">
+ <xsl:param name="local_types"/>
+ <xsl:param name="global_types"/>
+ <span class="bold_code">
+ <xsl:apply-templates mode="local_type">
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ </xsl:apply-templates>
+ </span><br/>
+ </xsl:template>
+
+ <!-- Not used right now -->
+ <!-- local_defs -->
+ <xsl:template match="local_defs">
+ <div class="REFBODY">
+ <xsl:apply-templates>
+ </xsl:apply-templates>
+ </div>
+ </xsl:template>
+
+ <!-- Not used right now -->
+ <xsl:template match="local_def">
+ <div class="REFTYPES">
+ <span class="bold_code">
+ <xsl:apply-templates/>
+ </span>
+ </div>
+ </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"/>
+ select="ancestor::type_desc/preceding-sibling::name
+ | 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 name="f" select="$curModule"/>
+ <xsl:with-param name="s">cannot find tag 'name' (anno <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>
+ <!-- Search "local types" as well -->
+ <xsl:variable name="local_types"
+ select="ancestor::desc/preceding-sibling::type
+ [string-length(@name) > 0]"/>
+ <xsl:variable name="has_anno_in_local_type">
+ <xsl:for-each select="$local_types">
+ <xsl:call-template name="anno_name">
+ <xsl:with-param name="curModule" select="$curModule"/>
+ <xsl:with-param name="anno" select="$anno"/>
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+
+ <xsl:variable name="has_anno">
+ <xsl:for-each select="$namespec">
+ <xsl:call-template name="anno_name">
+ <xsl:with-param name="curModule" select="$curModule"/>
+ <xsl:with-param name="anno" select="$anno"/>
+ </xsl:call-template>
+ </xsl:for-each>
</xsl:variable>
+
+ <xsl:if test="$has_anno = '' and $has_anno_in_local_type = ''">
+ <xsl:call-template name="err">
+ <xsl:with-param name="f" select="$curModule"/>
+ <xsl:with-param name="m" select="$namespec/@mod"/>
+ <xsl:with-param name="n" select="$namespec/@name"/>
+ <xsl:with-param name="a" select="'-'"/>
+ <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>
+
+ <xsl:template name="anno_name">
+ <xsl:param name="curModule"/>
+ <xsl:param name="anno"/>
+ <xsl:variable name="mod" select="@mod"/>
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="n_vars" select="@n_vars"/>
+ <xsl:variable name="clause_i" select="@clause_i"/>
+
<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]"/>
+ "$spec0[string-length($clause_i) = 0
+ or position() = $clause_i]/anno[.=$anno]"/>
<xsl:variable name="type_annos" select=
"$i/specs/module[@name=$curModule]/type
- [name=$name and n_vars=$n_vars
+ [name=$name
+ and (string-length($n_vars) = 0 or 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 test="count($spec_annos) != 0
+ or count($type_annos) != 0
+ or string-length($specs_file) = 0">
+ <xsl:value-of select="true()"/>
</xsl:if>
- <xsl:value-of select="$anno"/>
</xsl:template>
<!-- Used for indentation of formatted types and specs -->
@@ -324,6 +498,50 @@
<xsl:text>&#160;</xsl:text>
</xsl:template>
+ <xsl:template match="nbsp" mode="local_type">
+ <xsl:apply-templates select="."/>
+ </xsl:template>
+
+ <xsl:template match="br" mode="local_type">
+ <xsl:apply-templates select="."/>
+ </xsl:template>
+
+ <xsl:template match="marker" mode="local_type">
+ <xsl:param name="local_types"/>
+ <xsl:param name="global_types"/>
+ <!-- Craete no anchor -->
+ <!-- It would be possible to create a link to the global type
+ (if there is one), but that would mean even more code...
+ -->
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <!-- Does not look at @n_vars -->
+ <xsl:template match="seealso" mode="local_type">
+ <xsl:param name="local_types"/>
+ <xsl:param name="global_types"/>
+
+ <xsl:variable name="filepart"><xsl:value-of select="substring-before(@marker, '#')"/></xsl:variable>
+ <xsl:variable name="linkpart"><xsl:value-of select="translate(substring-after(@marker, '#'), '/', '-')"/></xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="string-length($filepart) > 0">
+ <xsl:call-template name="seealso"/>
+ </xsl:when>
+ <xsl:when test="count($local_types[concat('type-', @name) = $linkpart]) = 0">
+ <xsl:call-template name="seealso"/>
+ </xsl:when>
+ <xsl:when test="count($global_types/datatype/name[concat('type-', @name) = $linkpart]) > 0">
+ <!-- The type is both local and global; link to the global type -->
+ <xsl:call-template name="seealso"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- No link to local type -->
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
<!-- End of Dialyzer type/spec tags -->
<!-- Page layout -->
@@ -1178,14 +1396,7 @@
<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:value-of select="@arity"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="calc-arity">
@@ -1221,11 +1432,19 @@
</xsl:choose>
</xsl:variable>
- <li title="{$fname}-{$arity}">
- <a href="{$basename}.html#{$fname}-{$arity}">
- <xsl:value-of select="$fname"/>/<xsl:value-of select="$arity"/>
- </a>
- </li>
+ <xsl:choose>
+ <xsl:when test="preceding-sibling::name[position() = 1
+ and @name = $fname and @arity = $arity]">
+ <!-- Skip. Only works for Dialyzer specs. -->
+ </xsl:when>
+ <xsl:otherwise>
+ <li title="{$fname}-{$arity}">
+ <a href="{$basename}.html#{$fname}-{$arity}">
+ <xsl:value-of select="$fname"/>/<xsl:value-of select="$arity"/>
+ </a>
+ </li>
+ </xsl:otherwise>
+ </xsl:choose>
</xsl:when>
</xsl:choose>
@@ -1470,7 +1689,10 @@
<xsl:template match="func">
<xsl:param name="partnum"/>
- <p><xsl:apply-templates select="name"/></p>
+ <p><xsl:apply-templates select="name"/>
+ <xsl:apply-templates
+ select="name[string-length(@arity) > 0 and position()=last()]"
+ mode="types"/></p>
<xsl:apply-templates select="fsummary|type|desc">
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1478,7 +1700,6 @@
</xsl:template>
-
<xsl:template match="name">
<xsl:choose>
<!-- @arity is mandatory when referring to a specification -->
@@ -1488,6 +1709,11 @@
<xsl:when test="ancestor::datatype">
<xsl:call-template name="type_name"/>
</xsl:when>
+ <xsl:when test="string-length(text()) = 0 and ancestor::erlref">
+ <xsl:message terminate="yes">
+ Error <xsl:value-of select="@name"/>: arity is mandatory when referring to specifications!
+ </xsl:message>
+ </xsl:when>
<xsl:otherwise>
<xsl:call-template name="name"/>
</xsl:otherwise>
@@ -1556,12 +1782,17 @@
<xsl:template match="type">
<xsl:param name="partnum"/>
- <div class="REFBODY"><p>Types:</p>
+ <!-- The case where @name != 0 is taken care of in "type_name" -->
+ <xsl:if test="string-length(@name) = 0 and string-length(@variable) = 0">
- <xsl:apply-templates>
- <xsl:with-param name="partnum" select="$partnum"/>
- </xsl:apply-templates>
- </div>
+ <div class="REFBODY"><p>Types:</p>
+
+ <xsl:apply-templates>
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:apply-templates>
+ </div>
+
+ </xsl:if>
</xsl:template>
@@ -1612,7 +1843,10 @@
</xsl:template>
<xsl:template match="seealso">
+ <xsl:call-template name="seealso"/>
+ </xsl:template>
+ <xsl:template name="seealso">
<xsl:variable name="filepart"><xsl:value-of select="substring-before(@marker, '#')"/></xsl:variable>
<xsl:variable name="linkpart"><xsl:value-of select="translate(substring-after(@marker, '#'), '/', '-')"/></xsl:variable>
@@ -1633,16 +1867,16 @@
<xsl:variable name="app"
select="$m2a/mod2app/module[@name=$filepart]"/>
-->
- <xsl:variable name="reftext" select="text()"/>
+ <xsl:variable name="this" select="."/>
<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>
+ <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app}','{$filepart}.html#{$linkpart}');"><xsl:value-of select="$this"/></a></span>
</xsl:when>
<xsl:otherwise>
<!-- Unknown application; no link -->
- <xsl:value-of select="$reftext"/>
+ <xsl:value-of select="$this"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl
index 2a8fb9fe3e..25b62f68c5 100644
--- a/lib/erl_docgen/priv/xsl/db_man.xsl
+++ b/lib/erl_docgen/priv/xsl/db_man.xsl
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
- # Copyright Ericsson AB 2009-2010. All Rights Reserved.
+ # Copyright Ericsson AB 2009-2011. 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
@@ -21,13 +21,16 @@
-->
<xsl:stylesheet version="1.0"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common"
+ extension-element-prefixes="exsl">
<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"
+ <!-- Start of Dialyzer type/spec tags. See also the templates
+ matching "name" and "seealso"
-->
<!-- Note: specs data for *one* module (as opposed to html and pdf) -->
@@ -35,38 +38,58 @@
<xsl:variable name="i" select="document($specs_file)"></xsl:variable>
<xsl:template name="err">
+ <xsl:param name="f"/>
<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"/>
+ Error <xsl:if test="$f != ''">in <xsl:value-of select ="$f"/>:</xsl:if>
+ <xsl:if test="$m != ''"><xsl:value-of select ="$m"/>:</xsl:if>
+ <xsl:value-of select="$n"/>
+ <xsl:if test="$a != ''">/<xsl:value-of
+ select ="$a"/></xsl:if>: <xsl:value-of select="$s"/>
</xsl:message>
</xsl:template>
- <xsl:template name="spec_name">
+ <xsl:template name="find_spec">
<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="clause_i" select="@clause_i"/>
<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:variable name="spec" select="$spec0[string-length($clause_i) = 0
+ or position() = $clause_i]"/>
+
+ <xsl:if test="count($spec) != 1">
+ <xsl:variable name="why">
+ <xsl:choose>
+ <xsl:when test="count($spec) > 1">ambiguous spec</xsl:when>
+ <xsl:when test="count($spec) = 0">unknown spec</xsl:when>
+ </xsl:choose>
+ </xsl:variable>
<xsl:call-template name="err">
+ <xsl:with-param name="f" select="$curModule"/>
<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:with-param name="s" select="$why"/>
</xsl:call-template>
</xsl:if>
+ <xsl:copy-of select="$spec"/>
+ </xsl:template>
+
+ <xsl:template name="spec_name">
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="spec0">
+ <xsl:call-template name="find_spec"/>
+ </xsl:variable>
+ <xsl:variable name="spec" select="exsl:node-set($spec0)/spec"/>
<xsl:choose>
<xsl:when test="ancestor::cref">
@@ -75,42 +98,12 @@
</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:apply-templates select="$spec/contract/clause/head"/>
<xsl:text>&#10;.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>&#10;.nf&#10;</xsl:text>
<xsl:text>&#10;.B&#10;</xsl:text>
@@ -119,29 +112,141 @@
<xsl:text>&#10;.fi</xsl:text>
</xsl:template>
- <xsl:template name="guard">
- <xsl:param name="guard"/>
+ <!-- The *last* <name name="..." arity=".."/> -->
+ <xsl:template match="name" mode="types">
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="spec0">
+ <xsl:call-template name="find_spec"/>
+ </xsl:variable>
+ <xsl:variable name="spec" select="exsl:node-set($spec0)/spec"/>
+ <xsl:variable name="clause" select="$spec/contract/clause"/>
+
+ <xsl:variable name="type_desc" select="../type_desc"/>
+ <!-- $type is data types to be presented as guards ("local types") -->
+ <xsl:variable name="type"
+ select="../type[string-length(@name) > 0
+ or string-length(@variable) > 0]"/>
+ <xsl:variable name="type_variables"
+ select ="$type[string-length(@variable) > 0]"/>
+ <xsl:variable name="local_types"
+ select ="$type[string-length(@name) > 0]"/>
+ <xsl:variable name="output_subtypes" select="count($type_variables) = 0"/>
+
+ <!-- It is assumed there is no support for overloaded specs
+ (there is no spec with more than one clause) -->
+ <xsl:if test="count($clause/guard) > 0 or count($type) > 0">
+ <xsl:text>&#10;.RS</xsl:text>
+ <xsl:text>&#10;.TP</xsl:text>
+ <xsl:text>&#10;Types</xsl:text>
+
+ <xsl:choose>
+ <xsl:when test="$output_subtypes">
+ <xsl:call-template name="subtype">
+ <xsl:with-param name="subtype" select="$clause/guard/subtype"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="type_variables">
+ <xsl:with-param name="type_variables" select="$type_variables"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="fname" select="$name"/>
+ <xsl:with-param name="arity" select="$arity"/>
+ </xsl:call-template>
+
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:call-template name="local_type">
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ </xsl:call-template>
+ <xsl:text>&#10;.RE</xsl:text>
+
+ </xsl:if>
+ </xsl:template>
+
+ <!-- Handle <type variable="..." name_i="..."/> -->
+ <xsl:template name="type_variables">
+ <xsl:param name="type_variables"/>
<xsl:param name="type_desc"/>
- <xsl:text>&#10;.RS</xsl:text>
- <xsl:text>&#10;.TP</xsl:text>
- <xsl:text>&#10;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>&#10;.RE</xsl:text>
+ <xsl:param name="local_types"/>
+ <xsl:param name="fname"/>
+ <xsl:param name="arity"/>
+
+ <xsl:variable name="names" select="../name[string-length(@arity) > 0]"/>
+ <xsl:for-each select="$type_variables">
+ <xsl:variable name="name_i">
+ <xsl:choose>
+ <xsl:when test="string-length(@name_i) > 0">
+ <xsl:value-of select="@name_i"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="count($names)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="spec0">
+ <xsl:for-each select="$names[position() = $name_i]">
+ <xsl:call-template name="find_spec"/>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="spec" select="exsl:node-set($spec0)/spec"/>
+ <xsl:variable name="clause" select="$spec/contract/clause"/>
+ <xsl:variable name="variable" select="@variable"/>
+ <xsl:variable name="subtype"
+ select="$clause/guard/subtype[typename = $variable]"/>
+
+ <xsl:if test="count($subtype) = 0">
+ <xsl:call-template name="err">
+ <xsl:with-param name="f" select="ancestor::erlref/module"/>
+ <xsl:with-param name="n" select="$fname"/>
+ <xsl:with-param name="a" select="$arity"/>
+ <xsl:with-param name="s">unknown type variable <xsl:value-of select="$variable"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
+ <xsl:call-template name="subtype">
+ <xsl:with-param name="subtype" select="$subtype"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ </xsl:call-template>
+ </xsl:for-each>
</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>&#10;</xsl:text>
- <xsl:apply-templates select="string"/>
- <xsl:text>&#10;.br</xsl:text>
- <xsl:apply-templates select="$type_desc[@name = $tname]"/>
+ <xsl:text>&#10;</xsl:text>
+ <xsl:apply-templates select="string"/>
+ <xsl:text>&#10;.br</xsl:text>
+ <xsl:apply-templates select="$type_desc[@variable = $tname]"/>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="local_type">
+ <xsl:param name="type_desc"/>
+ <xsl:param name="local_types"/>
+
+ <xsl:for-each select ="$local_types">
+ <xsl:text>&#10;</xsl:text>
+ <xsl:call-template name="type_name">
+ <xsl:with-param name="mode" select="'local_type'"/>
+ </xsl:call-template>
+ <xsl:text>&#10;.br</xsl:text>
+ <xsl:variable name="tname" select="@name"/>
+ <xsl:variable name="tnvars" select="@n_vars"/>
+ <xsl:apply-templates select=
+ "$type_desc[@name = $tname
+ and (@n_vars = $tnvars
+ or string-length(@n_vars) = 0 and
+ string-length($tnvars) = 0)]"/>
</xsl:for-each>
</xsl:template>
@@ -164,59 +269,46 @@
<xsl:apply-templates/>
</xsl:template>
- <xsl:template match="typehead">
- <xsl:text>&#10;.nf&#10;</xsl:text>
- <xsl:text>&#10;.B&#10;</xsl:text>
- <xsl:apply-templates/>
- <xsl:text>&#10;.br</xsl:text>
- <xsl:text>&#10;.fi</xsl:text>
- </xsl:template>
-
- <xsl:template match="local_defs">
- <xsl:text>&#10;.RS</xsl:text>
- <xsl:apply-templates/>
- <xsl:text>&#10;.RE</xsl:text>
- </xsl:template>
-
- <xsl:template match="local_def">
- <xsl:text>&#10;</xsl:text>
- <xsl:apply-templates/>
- <xsl:text>&#10;.br</xsl:text>
- </xsl:template>
-
<xsl:template name="type_name">
+ <xsl:param name="mode"/> <!-- '' if <datatype> -->
<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:variable name="n_vars" select="@n_vars"/>
<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
+ [name=$name
+ and (string-length($n_vars) = 0 or n_vars = $n_vars)
and (string-length($mod) = 0 or module = $mod)]"/>
<xsl:if test="count($type) != 1">
+ <xsl:variable name="why">
+ <xsl:choose>
+ <xsl:when test="count($type) > 1">ambiguous type</xsl:when>
+ <xsl:when test="count($type) = 0">unknown type</xsl:when>
+ </xsl:choose>
+ </xsl:variable>
<xsl:call-template name="err">
+ <xsl:with-param name="f" select="$curModule"/>
<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:with-param name="s" select="$why"/>
</xsl:call-template>
</xsl:if>
- <xsl:apply-templates select="$type/typedecl"/>
+ <xsl:choose>
+ <xsl:when test="$mode = ''">
+ <xsl:apply-templates select="$type/typedecl"/>
+ </xsl:when>
+ <xsl:when test="$mode = 'local_type'">
+ <xsl:apply-templates select="$type/typedecl" mode="local_type"/>
+ </xsl:when>
+ </xsl:choose>
</xsl:when>
- <xsl:otherwise>
+ <xsl:otherwise> <!-- <datatype> with <name> -->
<xsl:text>&#10;.nf&#10;</xsl:text>
<xsl:text>&#10;.B&#10;</xsl:text>
<xsl:apply-templates/>
@@ -226,68 +318,109 @@
</xsl:choose>
</xsl:template>
+ <xsl:template match="typehead">
+ <xsl:text>&#10;.nf&#10;</xsl:text>
+ <xsl:text>&#10;.B&#10;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;.br</xsl:text>
+ <xsl:text>&#10;.fi</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="typehead" mode="local_type">
+ <xsl:text>.nf&#10;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;.fi</xsl:text>
+ </xsl:template>
+
+ <!-- Not used right now -->
+ <xsl:template match="local_defs">
+ <xsl:text>&#10;.RS</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;.RE</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="local_def">
+ <xsl:text>&#10;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;.br</xsl:text>
+ </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"/>
+ select="ancestor::type_desc/preceding-sibling::name
+ | 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 name="f" select="$curModule"/>
+ <xsl:with-param name="s">cannot find tag 'name' (anno <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>
+ <!-- Search "local types" as well -->
+ <xsl:variable name="local_types"
+ select="ancestor::desc/preceding-sibling::type
+ [string-length(@name) > 0]"/>
+ <xsl:variable name="has_anno_in_local_type">
+ <xsl:for-each select="$local_types">
+ <xsl:call-template name="anno_name">
+ <xsl:with-param name="curModule" select="$curModule"/>
+ <xsl:with-param name="anno" select="$anno"/>
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+
+ <xsl:variable name="has_anno">
+ <xsl:for-each select="$namespec">
+ <xsl:call-template name="anno_name">
+ <xsl:with-param name="curModule" select="$curModule"/>
+ <xsl:with-param name="anno" select="$anno"/>
+ </xsl:call-template>
+ </xsl:for-each>
</xsl:variable>
+
+ <xsl:if test="$has_anno = '' and $has_anno_in_local_type = ''">
+ <xsl:call-template name="err">
+ <xsl:with-param name="f" select="$curModule"/>
+ <xsl:with-param name="m" select="$namespec/@mod"/>
+ <xsl:with-param name="n" select="$namespec/@name"/>
+ <xsl:with-param name="a" select="'-'"/>
+ <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>
+
+ <xsl:template name="anno_name">
+ <xsl:param name="curModule"/>
+ <xsl:param name="anno"/>
+ <xsl:variable name="mod" select="@mod"/>
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="n_vars" select="@n_vars"/>
+ <xsl:variable name="clause_i" select="@clause_i"/>
+
<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]"/>
+ "$spec0[string-length($clause_i) = 0
+ or position() = $clause_i]/anno[.=$anno]"/>
<xsl:variable name="type_annos" select=
"$i/module[@name=$curModule]/type
- [name=$name and n_vars=$n_vars
+ [name=$name
+ and (string-length($n_vars) = 0 or 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 test="count($spec_annos) != 0
+ or count($type_annos) != 0
+ or string-length($specs_file) = 0">
+ <xsl:value-of select="true()"/>
</xsl:if>
- <xsl:value-of select="$anno"/>
</xsl:template>
<!-- Used for indentation of formatted types and specs -->
@@ -542,6 +675,9 @@
<xsl:template match="func">
<xsl:text>&#10;.LP</xsl:text>
<xsl:apply-templates select="name"/>
+ <xsl:apply-templates
+ select="name[string-length(@arity) > 0 and position()=last()]"
+ mode="types"/>
<xsl:apply-templates select="fsummary|type|desc"/>
</xsl:template>
@@ -554,6 +690,11 @@
<xsl:when test="ancestor::datatype">
<xsl:call-template name="type_name"/>
</xsl:when>
+ <xsl:when test="string-length(text()) = 0 and ancestor::erlref">
+ <xsl:message terminate="yes">
+ Error <xsl:value-of select="@name"/>: arity is mandatory when referring to specifications!
+ </xsl:message>
+ </xsl:when>
<xsl:otherwise>
<xsl:call-template name="name"/>
</xsl:otherwise>
@@ -569,11 +710,14 @@
<!-- Type -->
<xsl:template match="type">
- <xsl:text>&#10;.RS</xsl:text>
- <xsl:text>&#10;.TP</xsl:text>
- <xsl:text>&#10;Types</xsl:text>
- <xsl:apply-templates/>
- <xsl:text>&#10;.RE</xsl:text>
+ <!-- The case where @name != 0 is taken care of in "type_name" -->
+ <xsl:if test="string-length(@name) = 0 and string-length(@variable) = 0">
+ <xsl:text>&#10;.RS</xsl:text>
+ <xsl:text>&#10;.TP</xsl:text>
+ <xsl:text>&#10;Types</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;.RE</xsl:text>
+ </xsl:if>
</xsl:template>
@@ -622,7 +766,7 @@
<xsl:text>&gt;</xsl:text>
</xsl:template>
- <!-- Do not noramlize any text within pre and code tags. -->
+ <!-- Do not normalize any text within pre and code tags. -->
<xsl:template match="pre/text()">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="." />
diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl
index f500cd3fee..5119e3e36a 100644
--- a/lib/erl_docgen/priv/xsl/db_pdf.xsl
+++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl
@@ -21,6 +21,8 @@
-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common"
+ extension-element-prefixes="exsl"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>
@@ -28,45 +30,66 @@
<xsl:include href="db_pdf_params.xsl"/>
<!-- Start of Dialyzer type/spec tags.
- See also the template matching "name" and the template "bookmarks6"
+ See also the templates matching "name" and "seealso" as well as
+ 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="f"/>
<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"/>
+ Error <xsl:if test="$f != ''">in <xsl:value-of select ="$f"/>:</xsl:if>
+ <xsl:if test="$m != ''"><xsl:value-of select ="$m"/>:</xsl:if>
+ <xsl:value-of select="$n"/>
+ <xsl:if test="$a != ''">/<xsl:value-of
+ select ="$a"/></xsl:if>: <xsl:value-of select="$s"/>
</xsl:message>
</xsl:template>
- <xsl:template name="spec_name">
+ <xsl:template name="find_spec">
<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="clause_i" select="@clause_i"/>
<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:variable name="spec" select="$spec0[string-length($clause_i) = 0
+ or position() = $clause_i]"/>
+
+ <xsl:if test="count($spec) != 1">
+ <xsl:variable name="why">
+ <xsl:choose>
+ <xsl:when test="count($spec) > 1">ambiguous spec</xsl:when>
+ <xsl:when test="count($spec) = 0">unknown spec</xsl:when>
+ </xsl:choose>
+ </xsl:variable>
<xsl:call-template name="err">
+ <xsl:with-param name="f" select="$curModule"/>
<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:with-param name="s" select="$why"/>
</xsl:call-template>
</xsl:if>
+ <xsl:copy-of select="$spec"/>
+ </xsl:template>
+
+ <xsl:template name="spec_name">
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="spec0">
+ <xsl:call-template name="find_spec"/>
+ </xsl:variable>
+ <xsl:variable name="spec" select="exsl:node-set($spec0)/spec"/>
<xsl:choose>
<xsl:when test="ancestor::cref">
@@ -76,78 +99,175 @@
</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>
+ <xsl:apply-templates select="$spec/contract/clause/head"/>
</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 match="head">
+ <fo:block xsl:use-attribute-sets="function-name">
+ <xsl:apply-templates/>
+ </fo:block>
</xsl:template>
- <xsl:template name="clause">
- <xsl:param name="clause"/>
+ <!-- The *last* <name name="..." arity=".."/> -->
+ <xsl:template match="name" mode="types">
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="spec0">
+ <xsl:call-template name="find_spec"/>
+ </xsl:variable>
+ <xsl:variable name="spec" select="exsl:node-set($spec0)/spec"/>
+ <xsl:variable name="clause" select="$spec/contract/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"/>
+ <!-- $type is data types to be presented as guards ("local types") -->
+ <xsl:variable name="type"
+ select="../type[string-length(@name) > 0
+ or string-length(@variable) > 0]"/>
+ <xsl:variable name="type_variables"
+ select ="$type[string-length(@variable) > 0]"/>
+ <xsl:variable name="local_types"
+ select ="$type[string-length(@name) > 0]"/>
+ <xsl:variable name="output_subtypes" select="count($type_variables) = 0"/>
+
+ <!-- It is assumed there is no support for overloaded specs
+ (there is no spec with more than one clause) -->
+ <xsl:if test="count($clause/guard) > 0 or count($type) > 0">
+ <fo:block>
+ <xsl:text>Types:</xsl:text>
+ </fo:block>
+ <fo:list-block xsl:use-attribute-sets="type-listblock">
+ <xsl:choose>
+ <xsl:when test="$output_subtypes">
+ <xsl:call-template name="subtype">
+ <xsl:with-param name="subtype" select="$clause/guard/subtype"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="type_variables">
+ <xsl:with-param name="type_variables" select="$type_variables"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="fname" select="$name"/>
+ <xsl:with-param name="arity" select="$arity"/>
+ </xsl:call-template>
+
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:call-template name="local_type">
<xsl:with-param name="type_desc" select="$type_desc"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
</xsl:call-template>
- </xsl:if>
- </xsl:for-each>
+ </fo:list-block>
+ </xsl:if>
</xsl:template>
- <xsl:template match="head">
- <fo:block xsl:use-attribute-sets="function-name">
- <xsl:apply-templates/>
- </fo:block>
- </xsl:template>
+ <!-- Handle <type variable="..." name_i="..."/> -->
+ <xsl:template name="type_variables">
+ <xsl:param name="type_variables"/>
+ <xsl:param name="type_desc"/>
+ <xsl:param name="local_types"/>
+ <xsl:param name="fname"/>
+ <xsl:param name="arity"/>
+
+ <xsl:variable name="names" select="../name[string-length(@arity) > 0]"/>
+ <xsl:for-each select="$type_variables">
+ <xsl:variable name="name_i">
+ <xsl:choose>
+ <xsl:when test="string-length(@name_i) > 0">
+ <xsl:value-of select="@name_i"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="count($names)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="spec0">
+ <xsl:for-each select="$names[position() = $name_i]">
+ <xsl:call-template name="find_spec"/>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="spec" select="exsl:node-set($spec0)/spec"/>
+ <xsl:variable name="clause" select="$spec/contract/clause"/>
+ <xsl:variable name="variable" select="@variable"/>
+ <xsl:variable name="subtype"
+ select="$clause/guard/subtype[typename = $variable]"/>
+
+ <xsl:if test="count($subtype) = 0">
+ <xsl:call-template name="err">
+ <xsl:with-param name="f" select="ancestor::erlref/module"/>
+ <xsl:with-param name="n" select="$fname"/>
+ <xsl:with-param name="a" select="$arity"/>
+ <xsl:with-param name="s">unknown type variable <xsl:value-of select="$variable"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
- <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:with-param name="subtype" select="$subtype"/>
+ <xsl:with-param name="type_desc" select="$type_desc"/>
</xsl:call-template>
- </fo:list-block>
+ </xsl:for-each>
</xsl:template>
+ <!-- Substituted
+ <fo:block xsl:use-attribute-sets="function-name">
+ for
+ <fo:block font-weight="bold">
+ to get proper indentation (a monospace font)
+ -->
<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 xsl:use-attribute-sets="function-name">
+ <xsl:apply-templates select="string"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
- <xsl:apply-templates select="$type_desc[@name = $tname]"/>
+ <xsl:apply-templates select="$type_desc[@variable = $tname]"/>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="local_type">
+ <xsl:param name="type_desc"/>
+ <xsl:param name="local_types"/>
+
+ <xsl:for-each select="$local_types">
+ <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">
+ (use function-name in "typehead" instead) -->
+ <xsl:call-template name="type_name">
+ <xsl:with-param name="mode" select="'local_type'"/>
+ </xsl:call-template>
+ <!-- </fo:block> -->
+ </fo:list-item-body>
+ </fo:list-item>
+ <xsl:variable name="tname" select="@name"/>
+ <xsl:variable name="tnvars" select="@n_vars"/>
+ <xsl:apply-templates select=
+ "$type_desc[@name = $tname
+ and (@n_vars = $tnvars
+ or string-length(@n_vars) = 0 and
+ string-length($tnvars) = 0)]"/>
</xsl:for-each>
</xsl:template>
@@ -182,6 +302,53 @@
<xsl:apply-templates select="desc"/>
</xsl:template>
+ <xsl:template name="type_name">
+ <xsl:param name="mode"/> <!-- '' if <datatype> -->
+ <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" select="@n_vars"/>
+
+ <xsl:choose>
+ <xsl:when test="string-length($name) > 0">
+ <xsl:variable name="type" select=
+ "$i/specs/module[@name=$curModule]/type
+ [name=$name
+ and (string-length($n_vars) = 0 or n_vars = $n_vars)
+ and (string-length($mod) = 0 or module = $mod)]"/>
+
+ <xsl:if test="count($type) != 1">
+ <xsl:variable name="why">
+ <xsl:choose>
+ <xsl:when test="count($type) > 1">ambiguous type</xsl:when>
+ <xsl:when test="count($type) = 0">unknown type</xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:call-template name="err">
+ <xsl:with-param name="f" select="$curModule"/>
+ <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" select="$why"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test="$mode = ''">
+ <xsl:apply-templates select="$type/typedecl"/>
+ </xsl:when>
+ <xsl:when test="$mode = 'local_type'">
+ <xsl:apply-templates select="$type/typedecl" mode="local_type"/>
+ </xsl:when>
+ </xsl:choose>
+ </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>
+
<!-- Like <head>... -->
<xsl:template match="typehead">
<fo:block xsl:use-attribute-sets="function-name">
@@ -189,6 +356,20 @@
</fo:block>
</xsl:template>
+ <!-- Substituted
+ <fo:block xsl:use-attribute-sets="function-name">
+ for
+ <fo:block font-weight="bold">
+ to get proper indentation (a monospace font)
+ -->
+
+ <xsl:template match="typehead" mode="local_type">
+ <fo:block xsl:use-attribute-sets="function-name">
+ <xsl:apply-templates/>
+ </fo:block>
+ </xsl:template>
+
+ <!-- Not used right now -->
<!-- Like <guard>, except "Types:"... -->
<xsl:template match="local_defs">
<fo:list-block xsl:use-attribute-sets="type-listblock">
@@ -211,108 +392,82 @@
</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"/>
+ select="ancestor::type_desc/preceding-sibling::name
+ | 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 name="f" select="$curModule"/>
+ <xsl:with-param name="s">cannot find tag 'name' (anno <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>
+ <!-- Search "local types" as well -->
+ <xsl:variable name="local_types"
+ select="ancestor::desc/preceding-sibling::type
+ [string-length(@name) > 0]"/>
+ <xsl:variable name="has_anno_in_local_type">
+ <xsl:for-each select="$local_types">
+ <xsl:call-template name="anno_name">
+ <xsl:with-param name="curModule" select="$curModule"/>
+ <xsl:with-param name="anno" select="$anno"/>
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+
+ <xsl:variable name="has_anno">
+ <xsl:for-each select="$namespec">
+ <xsl:call-template name="anno_name">
+ <xsl:with-param name="curModule" select="$curModule"/>
+ <xsl:with-param name="anno" select="$anno"/>
+ </xsl:call-template>
+ </xsl:for-each>
</xsl:variable>
+
+ <xsl:if test="$has_anno = '' and $has_anno_in_local_type = ''">
+ <xsl:call-template name="err">
+ <xsl:with-param name="f" select="$curModule"/>
+ <xsl:with-param name="m" select="$namespec/@mod"/>
+ <xsl:with-param name="n" select="$namespec/@name"/>
+ <xsl:with-param name="a" select="'-'"/>
+ <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>
+
+ <xsl:template name="anno_name">
+ <xsl:param name="curModule"/>
+ <xsl:param name="anno"/>
+ <xsl:variable name="mod" select="@mod"/>
+ <xsl:variable name="name" select="@name"/>
+ <xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="n_vars" select="@n_vars"/>
+ <xsl:variable name="clause_i" select="@clause_i"/>
+
<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]"/>
+ "$spec0[string-length($clause_i) = 0
+ or position() = $clause_i]/anno[.=$anno]"/>
<xsl:variable name="type_annos" select=
"$i/specs/module[@name=$curModule]/type
- [name=$name and n_vars=$n_vars
+ [name=$name
+ and (string-length($n_vars) = 0 or 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 test="count($spec_annos) != 0
+ or count($type_annos) != 0
+ or string-length($specs_file) = 0">
+ <xsl:value-of select="true()"/>
</xsl:if>
- <xsl:value-of select="$anno"/>
</xsl:template>
<!-- Used for indentation of formatted types and specs -->
@@ -1227,6 +1382,9 @@
<xsl:param name="partnum"/>
<xsl:apply-templates select="name"/>
+ <xsl:apply-templates
+ select="name[string-length(@arity) > 0 and position()=last()]"
+ mode="types"/>
<xsl:apply-templates select="fsummary|type|desc">
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1245,6 +1403,11 @@
<xsl:when test="ancestor::datatype">
<xsl:call-template name="type_name"/>
</xsl:when>
+ <xsl:when test="string-length(text()) = 0 and ancestor::erlref">
+ <xsl:message terminate="yes">
+ Error <xsl:value-of select="@name"/>: arity is mandatory when referring to specifications!
+ </xsl:message>
+ </xsl:when>
<xsl:otherwise>
<fo:block xsl:use-attribute-sets="function-name">
<xsl:call-template name="name">
@@ -1276,15 +1439,20 @@
<xsl:template match="type">
<xsl:param name="partnum"/>
- <fo:block>
- <xsl:text>Types:</xsl:text>
- </fo:block>
+ <!-- The case where @name != 0 is taken care of in "type_name" -->
+ <xsl:if test="string-length(@name) = 0 and string-length(@variable) = 0">
- <fo:list-block xsl:use-attribute-sets="type-listblock">
- <xsl:apply-templates>
- <xsl:with-param name="partnum" select="$partnum"/>
- </xsl:apply-templates>
- </fo:list-block>
+ <fo:block>
+ <xsl:text>Types:</xsl:text>
+ </fo:block>
+
+ <fo:list-block xsl:use-attribute-sets="type-listblock">
+ <xsl:apply-templates>
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:apply-templates>
+ </fo:list-block>
+
+ </xsl:if>
</xsl:template>
@@ -1431,6 +1599,7 @@
</xsl:template>
+ <!-- Does not look at @n_vars -->
<xsl:template match="seealso">
<fo:inline font-style="italic">
<xsl:apply-templates/>
diff --git a/lib/erl_docgen/src/otp_specs.erl b/lib/erl_docgen/src/otp_specs.erl
index 728ddb2e6e..edb437a942 100644
--- a/lib/erl_docgen/src/otp_specs.erl
+++ b/lib/erl_docgen/src/otp_specs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. 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
@@ -380,6 +380,8 @@ t_type([E=#xmlElement{name = float}]) ->
t_float(E);
t_type([#xmlElement{name = nil}]) ->
t_nil();
+t_type([#xmlElement{name = paren, content = Es}]) ->
+ t_paren(Es);
t_type([#xmlElement{name = list, content = Es}]) ->
t_list(Es);
t_type([#xmlElement{name = nonempty_list, content = Es}]) ->
@@ -416,6 +418,9 @@ t_float(E) ->
t_nil() ->
["[]"].
+t_paren(Es) ->
+ ["("] ++ t_utype(get_elem(type, Es)) ++ [")"].
+
t_list(Es) ->
["["] ++ t_utype(get_elem(type, Es)) ++ ["]"].
@@ -532,6 +537,8 @@ ot_type([E=#xmlElement{name = float}]) ->
ot_float(E);
ot_type([#xmlElement{name = nil}]) ->
ot_nil();
+ot_type([#xmlElement{name = paren, content = Es}]) ->
+ ot_paren(Es);
ot_type([#xmlElement{name = list, content = Es}]) ->
ot_list(Es);
ot_type([#xmlElement{name = nonempty_list, content = Es}]) ->
@@ -582,6 +589,9 @@ ot_float(E) ->
ot_nil() ->
{nil,0}.
+ot_paren(Es) ->
+ {paren_type,0,[ot_utype(get_elem(type, Es))]}.
+
ot_list(Es) ->
{type,0,list,[ot_utype(get_elem(type, Es))]}.
@@ -697,5 +707,7 @@ 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([#xmlElement{name = paren, content = Es}]) ->
+ annos(get_elem(type, Es));
annos_type(_) ->
[].
diff --git a/make/otp.mk.in b/make/otp.mk.in
index bf287be416..a4e9dad46f 100644
--- a/make/otp.mk.in
+++ b/make/otp.mk.in
@@ -4,7 +4,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2010. All Rights Reserved.
+# Copyright Ericsson AB 1997-2011. 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
@@ -240,9 +240,10 @@ FOP = @FOP@
DOCGEN=$(ERL_TOP)/lib/erl_docgen
SPECS_ESRC = ../../src
+SPECS_EXTRACTOR=$(DOCGEN)/priv/bin/specs_gen.escript
# Extract specifications and types from Erlang source files (-spec, -type)
$(SPECDIR)/specs_%.xml: $(SPECS_ESRC)/%.erl
- escript $(DOCGEN)/priv/bin/specs_gen.escript $(SPECS_FLAGS) -o$(dir $@) $<
+ escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) -o$(dir $@) $<
$(MAN1DIR)/%.1: %.xml