diff options
author | Hans Bolinder <[email protected]> | 2011-05-16 13:33:57 +0200 |
---|---|---|
committer | Hans Bolinder <[email protected]> | 2011-05-16 13:33:57 +0200 |
commit | 69887e661bca4b2e38a5091ec60bfadec85d6bbf (patch) | |
tree | edc44f6a2f7a71e37cd1c18d113817a671cfe6b0 /lib | |
parent | e375165f6421c86fb245843d787e021d5b7dd00d (diff) | |
parent | 38b2f44764e79a34048f686d98b6d741d18738d2 (diff) | |
download | otp-69887e661bca4b2e38a5091ec60bfadec85d6bbf.tar.gz otp-69887e661bca4b2e38a5091ec60bfadec85d6bbf.tar.bz2 otp-69887e661bca4b2e38a5091ec60bfadec85d6bbf.zip |
Merge branch 'hb/erl_docgen/specs_and_types_improvements/OTP-9261' into dev
* hb/erl_docgen/specs_and_types_improvements/OTP-9261:
Improve erl_docgen's support for Dialyzer specs and types
Diffstat (limited to 'lib')
-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(_) -> []. |