diff options
author | Hans Bolinder <[email protected]> | 2011-05-05 14:22:18 +0200 |
---|---|---|
committer | Hans Bolinder <[email protected]> | 2011-05-16 13:33:08 +0200 |
commit | 38b2f44764e79a34048f686d98b6d741d18738d2 (patch) | |
tree | edc44f6a2f7a71e37cd1c18d113817a671cfe6b0 /lib/erl_docgen/priv/xsl/db_man.xsl | |
parent | e375165f6421c86fb245843d787e021d5b7dd00d (diff) | |
download | otp-38b2f44764e79a34048f686d98b6d741d18738d2.tar.gz otp-38b2f44764e79a34048f686d98b6d741d18738d2.tar.bz2 otp-38b2f44764e79a34048f686d98b6d741d18738d2.zip |
Improve erl_docgen's support for Dialyzer specs and types
The support for using Dialyzer specifications and types has been
improved.
Diffstat (limited to 'lib/erl_docgen/priv/xsl/db_man.xsl')
-rw-r--r-- | lib/erl_docgen/priv/xsl/db_man.xsl | 424 |
1 files changed, 284 insertions, 140 deletions
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="." /> |