diff options
Diffstat (limited to 'lib/erl_docgen')
| -rw-r--r-- | lib/erl_docgen/priv/bin/specs_gen.escript | 101 | ||||
| -rw-r--r-- | lib/erl_docgen/priv/xsl/db_html.xsl | 556 | ||||
| -rw-r--r-- | lib/erl_docgen/priv/xsl/db_man.xsl | 424 | ||||
| -rw-r--r-- | lib/erl_docgen/priv/xsl/db_pdf.xsl | 451 | ||||
| -rw-r--r-- | lib/erl_docgen/src/otp_specs.erl | 14 | 
5 files changed, 1066 insertions, 480 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> </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>
.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> @@ -119,29 +112,141 @@      <xsl:text>
.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>
.RS</xsl:text> +      <xsl:text>
.TP</xsl:text> +      <xsl:text>
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>
.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>
.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: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>
</xsl:text> -        <xsl:apply-templates select="string"/> -        <xsl:text>
.br</xsl:text> -      <xsl:apply-templates 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[@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>
</xsl:text> +      <xsl:call-template name="type_name"> +	<xsl:with-param name="mode" select="'local_type'"/> +      </xsl:call-template> +      <xsl:text>
.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>
.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: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>
.nf
</xsl:text>          <xsl:text>
.B
</xsl:text>          <xsl:apply-templates/> @@ -226,68 +318,109 @@      </xsl:choose>    </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="typehead" mode="local_type"> +    <xsl:text>.nf
</xsl:text> +    <xsl:apply-templates/> +    <xsl:text>
.fi</xsl:text> +  </xsl:template> + +  <!-- Not used right now --> +  <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> +    <!-- 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>
.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>
.RS</xsl:text> -    <xsl:text>
.TP</xsl:text> -    <xsl:text>
Types</xsl:text> -    <xsl:apply-templates/> -    <xsl:text>
.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>
.RS</xsl:text> +      <xsl:text>
.TP</xsl:text> +      <xsl:text>
Types</xsl:text> +      <xsl:apply-templates/> +      <xsl:text>
.RE</xsl:text> +    </xsl:if>    </xsl:template> @@ -622,7 +766,7 @@      <xsl:text>></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(_) ->      []. | 
