Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'src/current/include')
-rw-r--r--src/current/include/calc-display.xsl702
-rw-r--r--src/current/include/depgen.xsl526
-rw-r--r--src/current/include/display.xsl551
-rw-r--r--src/current/include/dslc-base.xsl90
-rw-r--r--src/current/include/entry-form.xsl323
-rw-r--r--src/current/include/exslt/str.tokenize.template.xsl65
-rw-r--r--src/current/include/orderizer.xsl268
-rw-r--r--src/current/include/preproc/domain.xsl226
-rw-r--r--src/current/include/preproc/eligclass.xsl261
-rw-r--r--src/current/include/preproc/expand.xsl691
-rw-r--r--src/current/include/preproc/macros.xsl456
-rw-r--r--src/current/include/preproc/package.xsl817
-rw-r--r--src/current/include/preproc/path.xsl230
-rw-r--r--src/current/include/preproc/symtable.xsl959
-rw-r--r--src/current/include/preproc/template.xsl1149
-rw-r--r--src/current/include/preprocess.xsl48
-rw-r--r--src/current/include/symbol-map.xml80
-rw-r--r--src/current/include/util.xsl186
18 files changed, 7628 insertions, 0 deletions
diff --git a/src/current/include/calc-display.xsl b/src/current/include/calc-display.xsl
new file mode 100644
index 0000000..4f9f0fa
--- /dev/null
+++ b/src/current/include/calc-display.xsl
@@ -0,0 +1,702 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Handles calculation output in LaTeX format for styling by Mathjax
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc">
+
+
+<!--
+ Recursively apply any child equations and then do the same in calc-after mode
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:*" mode="calc-recurse">
+ <xsl:apply-templates select="./c:*" />
+
+ <!-- invoke `after' templates, which allows inserting data for display after
+ the initial equation -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<!--
+ Style sum of values as a LaTeX equation
+
+ Note that this does not deal with the summation of a series; that's left to
+ the handling of the @of attribute.
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:sum">
+ <xsl:apply-templates select="." mode="sum-body" />
+</xsl:template>
+
+<xsl:template match="c:sum" mode="sum-body">
+ <xsl:for-each select="./c:*">
+ <!-- get value to display -->
+ <xsl:variable name="display">
+ <xsl:apply-templates select="." />
+ </xsl:variable>
+
+ <!-- delimit with +s if not first; if we're adding a negative, omit the
+ addition symbol as well (unless we're displaying a product, since
+ multiplying by a negative would otherwise appear to be subtraction) -->
+ <xsl:if test="
+ ( position() > 1 )
+ and (
+ not( substring( $display, 1, 1 ) = '-' )
+ or ( local-name() = 'product' )
+ )
+ ">
+
+ <xsl:text> + </xsl:text>
+ </xsl:if>
+
+ <!-- the only reason we would have a sum within a sum (that doesn't use
+ sigma-notation) is for grouping -->
+ <xsl:if test="( local-name() = 'sum' ) and not( @of )">
+ <xsl:text>\left(</xsl:text>
+ </xsl:if>
+
+ <xsl:copy-of select="$display" />
+
+ <xsl:if test="( local-name() = 'sum' ) and not( @of )">
+ <xsl:text>\right)</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+
+ <!-- since we looped manually, we must also invoke `after' templates
+ manually -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<!--
+ Style summation of a set as a LaTeX equation
+
+ Note that @of deals witht summation of sets only (rather, using the index of a
+ set to sum over the provided calculation). See the other template(s) for
+ summing values without a set.
+
+ An index may optionally be provided via an @index attribute; otherwise, one
+ will be chosen for you. The index is used for the lower limit; the upper limit
+ is omitted. The child nodes are then used to generate the equation to be
+ applied by the summation.
+
+ If no child nodes are provided, then the summation is meant to imply that each
+ value in the set should be summed. Adding child nodes overrides this behavior.
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:sum[@of]">
+ <xsl:variable name="of" select="@of" />
+
+ <!-- if no index is provided, simply use its symbol to indicate all values
+ within its domain -->
+ <xsl:variable name="index">
+ <xsl:choose>
+ <xsl:when test="@index">
+ <xsl:value-of select="@index" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <!-- TODO: Determine an index that is not in use -->
+ <xsl:text>k</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:variable name="ref">
+ <xsl:value-of select="@of" />
+ </xsl:variable>
+
+ <!-- retrieve the symbol associated with this value (no index) -->
+ <xsl:variable name="symbol">
+ <xsl:call-template name="get-symbol">
+ <xsl:with-param name="name" select="$ref" />
+ <xsl:with-param name="search" select="/" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <!-- also retrieve the symbol without its index -->
+
+ <!-- if an index was provided, set the lower limit to 0 (we do this in a
+ separate variable so that we can display the symbol on its own elsewhere)
+ -->
+ <xsl:variable name="index-limit">
+ <xsl:value-of select="$index" />
+
+ <!-- we only need the explicit notation if we are summing more than the
+ set -->
+ <xsl:if test="./c:*">
+ <xsl:text>=0</xsl:text>
+ </xsl:if>
+ </xsl:variable>
+
+ <xsl:text>\sum \limits_{</xsl:text>
+ <xsl:value-of select="$index-limit" />
+ <xsl:text>}</xsl:text>
+
+ <!-- upper limit is only necessary for clarification if they have provided a
+ more complex expression; if we're only summing over a single set, then
+ the extra notation is unnecessary and will just clutter -->
+ <xsl:if test="./c:*">
+ <!-- the upper limit of the summation will be denoted by #S, where S is the
+ symbol for a given set -->
+ <xsl:text>^{\grave\#</xsl:text>
+ <xsl:copy-of select="$symbol" />
+ <xsl:text>}</xsl:text>
+ </xsl:if>
+
+ <!-- if no children are provided, just sum @of -->
+ <xsl:if test="not(./c:*)">
+ <!-- output the symbol followed by its index, only if an index was provided
+ (and is therefore necessary) -->
+ <xsl:call-template name="get-symbol">
+ <xsl:with-param name="name" select="$ref" />
+ <xsl:with-param name="index-symbol" select="$index" />
+ <xsl:with-param name="search" select="/" />
+ </xsl:call-template>
+ </xsl:if>
+
+ <!-- output any additional expressions, if any -->
+ <xsl:apply-templates select="." mode="sum-body" />
+</xsl:template>
+
+
+<!--
+ Style product of values as a LaTeX equation
+
+ Note that this does not deal with the product of a series; that's left to
+ the handling of the @of attribute (TODO: @of not yet implemented for
+ products).
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:product">
+ <xsl:variable name="enclose" select="
+ @dot='true'
+ and (
+ preceding-sibling::c:*
+ or following-sibling::c:*
+ )
+ " />
+
+ <xsl:if test="$enclose">
+ <xsl:text>(</xsl:text>
+ </xsl:if>
+
+ <xsl:for-each select="./c:*">
+ <!-- Function symbols can have multiple chars, so we'll need to add the
+ multiplication symbol. Adjacent constants should also be separated by a
+ dot, otherwise it'll look like one giant number. -->
+ <xsl:if test="
+ (
+ local-name() = 'apply'
+ or ../@dot = 'true'
+ or (
+ ( local-name() = 'const' )
+ and ( local-name( preceding-sibling::*[1] ) = 'const' )
+ )
+ )
+ and ( position() > 1 )
+ ">
+ <xsl:text> \,\cdot\, </xsl:text>
+ </xsl:if>
+
+ <!-- if precedence of this operation is lower, we will need to include
+ parenthesis -->
+ <!-- XXX: Relies on hard-coded precedence rules in multiple locations;
+ refactor! -->
+ <xsl:if test="
+ ( local-name() = 'sum' )
+ or ( ( local-name() = 'product' ) and not( @of ) )
+ ">
+ <xsl:text>\left(</xsl:text>
+ </xsl:if>
+
+ <xsl:apply-templates select="." />
+
+ <!-- close parenthesis -->
+ <xsl:if test="
+ ( local-name() = 'sum' )
+ or ( ( local-name() = 'product' ) and not( @of ) )
+ ">
+ <xsl:text>\right)</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+
+ <xsl:if test="$enclose">
+ <xsl:text>)</xsl:text>
+ </xsl:if>
+
+ <!-- since we looped manually, we must also invoke `after' templates
+ manually -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<!--
+ Style quotient of two values as a LaTeX equation
+
+ This is used to divide two values and will be styled as a fraction. The
+ numerator should be the first calculation node and the denominator the second;
+ there should be no additional nodes.
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:quotient">
+ <!-- numerator (first child) -->
+ <xsl:text>\frac{</xsl:text>
+ <xsl:apply-templates select="./c:*[1]" />
+
+ <!-- denominator (second child) -->
+ <xsl:text>}{</xsl:text>
+ <xsl:apply-templates select="./c:*[2]" />
+ <xsl:text>}</xsl:text>
+
+ <!-- since we processed manually, we must also invoke `after' templates
+ manually -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<xsl:template match="c:let">
+ <!-- process the body of the let expression (the variables should have been
+ processed separately) -->
+ <xsl:apply-templates select="c:*" />
+</xsl:template>
+
+
+<!--
+ Style a value for display within a LaTeX equation
+
+ Forwards to calc-get-value template.
+-->
+<xsl:template match="c:value-of">
+ <xsl:apply-templates select="." mode="calc-get-value" />
+</xsl:template>
+
+
+<!--
+ Values from a c:let must have their names altered before looking up the symbol
+-->
+<xsl:template match="c:*[ @name=ancestor::c:let/c:values/c:value/@name ]" mode="calc-get-value">
+ <xsl:call-template name="calc-get-value">
+ <!-- :<let-name>:<our-name> -->
+ <xsl:with-param name="name" select="
+ concat( ':', ancestor::c:let[1]/@name, ':', @name )
+ " />
+ </xsl:call-template>
+</xsl:template>
+
+
+<!--
+ Style a value for display within a LaTeX equation
+
+ By default, the symbol for the given value (variable) will be rendered in
+ place of this node.
+
+ This element is not expected to have any children.
+
+ XXX: Refactor me; there are more clear and less convoluted ways to accomplish
+ this.
+
+ @return LaTeX equation
+-->
+<xsl:template name="calc-get-value" match="c:*" mode="calc-get-value">
+ <xsl:param name="name" select="@name" />
+
+ <xsl:variable name="index-symbol">
+ <xsl:if test="./c:index">
+ <xsl:for-each select="./c:index">
+ <!-- separate multiple indexes with commas -->
+ <xsl:if test="position() > 1">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+
+ <xsl:apply-templates select="./c:*[1]" />
+ </xsl:for-each>
+ </xsl:if>
+ </xsl:variable>
+
+ <xsl:variable name="sym" select="
+ /lv:*/preproc:symtable/preproc:sym[
+ @name=$name
+ ]
+ " />
+
+
+ <xsl:variable name="value">
+ <xsl:choose>
+ <!-- for scalar constants that do not have a symbol, simply inline their
+ value (if they have a symbol, then it is assumed that their symbolic
+ meaning is more meaningful than its value) -->
+ <xsl:when test="
+ $sym[
+ @type='const'
+ and @dim='0'
+ and ( not( @text ) or @tex='' )
+ ]
+ ">
+ <xsl:value-of select="$sym/@value" />
+ </xsl:when>
+
+ <!-- local index (generated with @of) -->
+ <xsl:when test="ancestor::c:*[ @of and @index=$name ]">
+ <xsl:value-of select="$name" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:call-template name="get-symbol">
+ <xsl:with-param name="name" select="$name" />
+ <xsl:with-param name="index" select="@index" />
+ <xsl:with-param name="index-symbol" select="$index-symbol" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:copy-of select="$value" />
+
+ <!-- yes, a value still may have things to appear after it -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<!--
+ Style a constant value for use in a LaTeX equation
+
+ Constant values are not treated as variables; instead, their value (rather
+ than their symbol) is immediately rendered.
+
+ Use this only if the value itself makes more sense (and is more clear) than a
+ variable.
+
+ This element is not expected to have any children.
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:const">
+ <!-- a constant value of 1 with Iverson's brackets is redundant -->
+ <xsl:if test="not( ( @value = '1' ) and ./c:when )">
+ <!-- display constant value -->
+ <xsl:value-of select="@value" />
+ </xsl:if>
+
+ <!-- a constant may still have things to appear after it -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<xsl:template match="c:ceil|c:floor">
+ <xsl:text>\left\l</xsl:text>
+ <xsl:value-of select="local-name()" />
+ <xsl:text> </xsl:text>
+ <xsl:apply-templates select="." mode="calc-recurse" />
+ <xsl:text>\right\r</xsl:text>
+ <xsl:value-of select="local-name()" />
+</xsl:template>
+
+
+<!--
+ Styles a function application for display in a LaTeX equation
+
+ Indicates a function application. A call to the function, with each of its
+ arguments in parenthesis, will be rendered.
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:apply">
+ <xsl:variable name="self" select="." />
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="fsym" select="//lv:function[@name=$name]/@sym" />
+
+ <xsl:call-template name="get-symbol">
+ <xsl:with-param name="name" select="@name" />
+ <xsl:with-param name="search" select="/" />
+ </xsl:call-template>
+
+ <!-- if a symbol is provided, then omit the parenthesis -->
+ <xsl:if test="not( $fsym )">
+ <xsl:text>\left(</xsl:text>
+ </xsl:if>
+
+ <!-- output the symbol associated with the value of each argument -->
+ <xsl:for-each select="./c:arg">
+ <!-- delimit params with a comma -->
+ <xsl:if test="position() > 1">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+
+ <xsl:variable name="valname" select="./c:*[1]/@name" />
+
+ <xsl:choose>
+ <!-- if this variable has been defined as an index, then simply output
+ it -->
+ <xsl:when test="ancestor::c:*[ @of and @index=$valname ]">
+ <xsl:value-of select="$valname" />
+ </xsl:when>
+
+ <!-- display the value of constants -->
+ <xsl:when test="local-name( ./c:*[1] ) = 'const'">
+ <xsl:value-of select="./c:*[1]/@value" />
+ </xsl:when>
+
+ <!-- otherwise, it's some other variable and we must look up its
+ symbol -->
+ <xsl:otherwise>
+ <xsl:apply-templates select="./c:*[1]" />
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <!-- we may have c:when, etc (args are their own sub-equations) -->
+ <xsl:apply-templates select="./c:*[1]/c:*" mode="calc-after" />
+ </xsl:for-each>
+
+ <xsl:if test="not( $fsym )">
+ <xsl:text>\right)</xsl:text>
+ </xsl:if>
+
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<!--
+ Outputs Iverson's brackets only if forced; see calc-after mode
+
+ This is hidden by default until calc-after to ensure that this is display
+ *after* the equation is output.
+
+ @param boolean force-show optionally force the display of the notation
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:when">
+ <xsl:param name="force-show" select="false()" />
+ <xsl:param name="standalone" select="false()" />
+
+ <!-- by default, we want to defer showing this until after the equation has
+ been output; however, the caller can force it to be displayed if needed -->
+ <xsl:if test="$force-show = true()">
+ <xsl:apply-templates select="." mode="calc-after">
+ <xsl:with-param name="standalone" select="$standalone" />
+ </xsl:apply-templates>
+ </xsl:if>
+</xsl:template>
+
+
+<!--
+ Outputs Iverson's brackets
+
+ This is called *after* the equation is output
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:when" mode="calc-after" priority="5">
+ <xsl:param name="brackets" select="true()" />
+ <xsl:param name="standalone" select="false()" />
+
+ <xsl:variable name="preceding" select="preceding-sibling::c:when" />
+
+ <!-- output bracket only if (a) requested and (b) first in set -->
+ <xsl:if test="$brackets and ( $standalone or not( $preceding ) )">
+ <xsl:text>\left[</xsl:text>
+ </xsl:if>
+
+ <!-- if we do have a preceding sibling, prefix with "and" -->
+ <xsl:if test="not( $standalone ) and $preceding">
+ <xsl:text>\text{ and }</xsl:text>
+ </xsl:if>
+
+ <!-- output the symbol for the variable we are comparing against -->
+ <xsl:apply-templates select="." mode="calc-get-value" />
+
+ <xsl:text> </xsl:text>
+ <xsl:apply-templates select="./c:*" mode="calc-iversons" />
+
+ <!-- output bracket only if (a) requested and (b) last in set -->
+ <xsl:if test="
+ $brackets and ( $standalone or not( following-sibling::c:when ) )
+ ">
+
+ <xsl:text>\right]</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template match="c:cases">
+ <xsl:text>\begin{cases}</xsl:text>
+ <xsl:apply-templates select="./c:case|./c:otherwise" />
+ <xsl:text>\end{cases}</xsl:text>
+
+ <!-- if any equations immediately follow, add some extra space so as not to
+ confuse the reader -->
+ <xsl:if test="following-sibling::c:*">
+ <xsl:text>\;\;\;</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+
+<!--
+ Generate a case
+
+ When $force-show is provided, as it is when displaying only small portions of
+ an equation, it will display the line using Iverson's brackets.
+-->
+<xsl:template match="c:cases/c:case|c:cases/c:otherwise">
+ <xsl:param name="force-show" select="false()" />
+
+ <!-- generate value -->
+ <xsl:apply-templates select="./c:*[ not( local-name() = 'when' ) ][1]" />
+
+ <xsl:choose>
+ <xsl:when test="not( $force-show )">
+ <xsl:text> &amp; </xsl:text>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text> [</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="local-name() != 'otherwise'">
+ <xsl:if test="not( $force-show )">
+ <xsl:text>\text{if } </xsl:text>
+ </xsl:if>
+
+ <!-- generate condition under which this value will apply -->
+ <xsl:apply-templates select="./c:when" mode="calc-after">
+ <xsl:with-param name="brackets" select="false()" />
+ </xsl:apply-templates>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text>\text{otherwise}</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <!-- determine how we end the line (more cases or end?) -->
+ <xsl:choose>
+ <xsl:when test="$force-show">
+ <xsl:text>]</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="following-sibling::c:case|following-sibling::c:otherwise">
+ <xsl:text>; \\</xsl:text>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text>.</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!--
+ Do nothing with calc-after for any unmatched calculations
+-->
+<xsl:template match="c:*" mode="calc-after" priority="1">
+ <!-- make sure nothing is done for all other nodes with calc-after -->
+</xsl:template>
+
+
+<!--
+ Display a notation intended for use within Iverson's brackets
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:eq|c:ne|c:gt|c:lt|c:gte|c:lte" mode="calc-iversons">
+ <xsl:variable name="name" select="local-name()" />
+
+ <!-- map to LaTeX equivalent -->
+ <xsl:variable name="map">
+ <c id="eq">=</c>
+ <c id="ne">\not=\;</c>
+ <c id="gt">\gt</c>
+ <c id="lt">\lt</c>
+ <c id="gte">\geq</c>
+ <c id="lte">\leq</c>
+ </xsl:variable>
+
+ <xsl:value-of select="$map/*[ @id=$name ]" />
+ <xsl:text> </xsl:text>
+
+ <xsl:apply-templates select="." mode="calc-recurse" />
+</xsl:template>
+
+
+<!--
+ TODO: Technically this is incorrect; sets cannot have duplicate values. This
+ would be best styled as a vector/matrix/etc.
+-->
+<xsl:template match="c:set" priority="1">
+ <xsl:text>\left[</xsl:text>
+ <xsl:for-each select="./c:*">
+ <xsl:if test="position() > 1">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+
+ <xsl:apply-templates select="." />
+ </xsl:for-each>
+ <xsl:text>\right]^T</xsl:text>
+</xsl:template>
+
+<!-- style subsets as matrices (easier to read) -->
+<xsl:template match="c:set[ ./c:set ]" priority="5">
+ <xsl:text>\left[\begin{array}\\</xsl:text>
+
+ <xsl:for-each select="./c:set">
+ <xsl:if test="position() > 1">
+ <xsl:text>\\</xsl:text>
+ </xsl:if>
+
+ <xsl:for-each select="./c:*">
+ <xsl:if test="position() > 1">
+ <xsl:text disable-output-escaping="yes"> &amp; </xsl:text>
+ </xsl:if>
+
+ <xsl:text>{</xsl:text>
+ <xsl:apply-templates select="." />
+ <xsl:text>}</xsl:text>
+ </xsl:for-each>
+ </xsl:for-each>
+
+ <xsl:text>\end{array}\right]</xsl:text>
+</xsl:template>
+
+
+<xsl:template match="c:length-of">
+ <xsl:text>\#\left(</xsl:text>
+ <xsl:apply-templates select="./c:*[1]" />
+ <xsl:text>\right)</xsl:text>
+</xsl:template>
+
+<xsl:template match="c:cons">
+ <xsl:text>\textrm{cons}\left(</xsl:text>
+ <xsl:apply-templates select="./c:*[1]" />
+ <xsl:text>,</xsl:text>
+ <xsl:apply-templates select="./c:*[2]" />
+ <xsl:text>\right)</xsl:text>
+</xsl:template>
+
+<xsl:template match="c:car">
+ <xsl:text>\left(</xsl:text>
+ <xsl:apply-templates select="./c:*[1]" />
+ <xsl:text>\right)_0</xsl:text>
+</xsl:template>
+
+<xsl:template match="c:cdr">
+ <xsl:text>\textrm{cdr}\left(</xsl:text>
+ <xsl:apply-templates select="./c:*[1]" />
+ <xsl:text>\right)</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/depgen.xsl b/src/current/include/depgen.xsl
new file mode 100644
index 0000000..d897c27
--- /dev/null
+++ b/src/current/include/depgen.xsl
@@ -0,0 +1,526 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ TODO: we can combine this dependency discovery with the symbol table
+ generation, eliminating extra passes
+
+ TODO: dependency symbols should not duplicate metadata
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:t="http://www.lovullo.com/rater/apply-template"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:ext="http://www.lovullo.com/ext"
+ xmlns:util="http://www.lovullo.com/util">
+
+
+<xsl:variable name="tex-defaults">
+ <preproc:syms>
+ <preproc:sym value="\alpha" vec="A" />
+ <preproc:sym value="\beta" vec="B" />
+ <preproc:sym value="\gamma" vec="\Gamma" />
+ <preproc:sym value="x" vec="X" />
+ <preproc:sym value="y" vec="Y" />
+ <preproc:sym value="z" vec="Z" />
+ </preproc:syms>
+</xsl:variable>
+
+
+<!-- simply allows invoking the template with dynamic input -->
+<xsl:template name="preproc:gen-deps">
+ <xsl:param name="pkg" as="element( lv:package )" />
+ <xsl:apply-templates select="$pkg" mode="preproc:gen-deps" />
+</xsl:template>
+
+
+<xsl:template match="*" mode="preproc:gen-deps">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:message>
+ <xsl:text>[depgen] *determining symbol dependencies...</xsl:text>
+ </xsl:message>
+
+ <xsl:apply-templates select="preproc:symtable" mode="preproc:depgen" />
+
+ <xsl:sequence select="*" />
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template match="preproc:symtable" mode="preproc:depgen" priority="9">
+ <xsl:variable name="symtable" select="." />
+
+ <preproc:sym-deps>
+ <!-- process dependencies for all non-imported symbols -->
+ <xsl:for-each select="preproc:sym[ not( @src ) ]">
+ <xsl:variable name="cursym" select="." />
+
+ <xsl:variable name="deps">
+ <preproc:deps>
+ <xsl:apply-templates select="." mode="preproc:depgen" />
+ </preproc:deps>
+ </xsl:variable>
+
+ <!-- do not output duplicates (we used to not output references
+ to ourselves, but we are now retaining them, since those
+ data are useful) -->
+ <xsl:variable name="uniq" select="
+ $deps/preproc:deps/preproc:sym-ref[
+ not( @name=preceding-sibling::preproc:sym-ref/@name )
+ ]
+ " />
+
+ <!-- symbols must not have themselves as their own dependency -->
+ <xsl:if test="$uniq[ not( $cursym/@allow-circular = 'true' )
+ and ( @name = $cursym/@name
+ or @parent = $cursym/@name ) ]">
+ <xsl:message terminate="yes"
+ select="concat( '[preproc] !!! fatal: symbol ',
+ $cursym/@name,
+ ' references itself ',
+ '(circular dependency)' )" />
+ </xsl:if>
+
+ <!-- grab the original source symbol for these references and augment them
+ with any additional dependency metadata -->
+ <xsl:variable name="syms-rtf">
+ <xsl:for-each select="$uniq">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="sym" select="
+ $symtable/preproc:sym[ @name=$name ]
+ " />
+
+ <!-- we should never have this problem. -->
+ <xsl:if test="not( $sym ) and not( @lax='true' )">
+ <xsl:message terminate="yes">
+ <xsl:text>[depgen] internal error: </xsl:text>
+ <xsl:text>could not locate dependency symbol `</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>' in local symbol table; needed by </xsl:text>
+ <xsl:value-of select="$cursym/@name" />
+ </xsl:message>
+ </xsl:if>
+
+ <!-- copy and augment (we set @name because $sym/@name may not exist
+ if @lax) -->
+ <preproc:sym name="{@name}">
+ <xsl:if test="$sym">
+ <xsl:sequence select="$sym/@*" />
+ </xsl:if>
+
+ <preproc:meta>
+ <!-- retain type -->
+ <xsl:sequence select="$sym/@type" />
+ <xsl:sequence select="$sym/@dim" />
+
+ <!-- copy any additional metadata -->
+ <xsl:sequence select="@*[ not( local-name() = 'name' ) ]" />
+ </preproc:meta>
+ </preproc:sym>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="syms" select="$syms-rtf/preproc:sym" />
+
+ <!-- only applicable if the symbol is @lax and the symbol was not
+ found in the local symbol table -->
+ <xsl:variable name="lax" select="
+ $uniq[
+ @lax='true'
+ and not( @name=$syms/@name )
+ ]
+ " />
+
+ <preproc:sym-dep name="{@name}">
+ <!-- process symbols that have not been found in the local symbol
+ table (only applicable when cursym is @lax) -->
+ <xsl:for-each select="$lax">
+ <!-- the @lax flag here is simply to denote that this symbol may not
+ actually exist and that ignoring the check was explicitly
+ requested (and not a bug in the depgen process) -->
+ <preproc:sym-ref name="{@name}" lax="true">
+ <xsl:sequence select="preproc:meta/@*" />
+ </preproc:sym-ref>
+ </xsl:for-each>
+
+ <!-- @tex provided an non-empty, or function -->
+ <xsl:for-each select="
+ $syms[
+ ( @tex and not( @tex='' ) )
+ or @type='func'
+ ]">
+
+ <xsl:choose>
+ <!-- even if function, @tex overrides symbol -->
+ <xsl:when test="@tex and not( @tex='' )">
+ <preproc:sym-ref tex="{@tex}">
+ <xsl:sequence select="@*" />
+ <xsl:sequence select="preproc:meta/@*" />
+ </preproc:sym-ref>
+ </xsl:when>
+
+ <!-- must be a function; use its name -->
+ <xsl:otherwise>
+ <preproc:sym-ref>
+ <xsl:sequence select="@*" />
+ <xsl:sequence select="preproc:meta/@*" />
+
+ <xsl:attribute name="tex">
+ <xsl:text>\textrm{</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>}</xsl:text>
+ </xsl:attribute>
+ </preproc:sym-ref>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+
+ <!-- no @tex, @tex empty, no function -->
+ <xsl:for-each select="
+ $syms[
+ ( not( @tex ) or @tex='' )
+ and not( @type='func' )
+ ]">
+
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="sym" select="." />
+
+ <preproc:sym-ref>
+ <!-- minimal attribute copy (avoid data duplication as much as
+ possible to reduce modification headaches later on) -->
+ <xsl:sequence select="@name, @parent" />
+ <xsl:sequence select="preproc:meta/@*" />
+
+ <!-- assign a symbol -->
+ <xsl:variable name="pos" select="position()" />
+ <xsl:attribute name="tex">
+ <xsl:variable name="texsym" select="
+ $tex-defaults/preproc:syms/preproc:sym[
+ position() = $pos
+ ]
+ " />
+
+ <xsl:choose>
+ <xsl:when test="$sym/@tex and not( $sym/@tex='' )">
+ <xsl:value-of select="$sym/@tex" />
+ </xsl:when>
+
+ <!-- scalar/vector default -->
+ <xsl:when test="$texsym and number( $sym/@dim ) lt 2">
+ <xsl:value-of select="$texsym/@value" />
+ </xsl:when>
+
+ <!-- matrix default -->
+ <xsl:when test="$texsym">
+ <xsl:value-of select="$texsym/@vec" />
+ </xsl:when>
+
+ <!-- no default available; generate one -->
+ <xsl:otherwise>
+ <xsl:value-of select="
+ if ( number( $sym/@dim ) lt 2 ) then '\theta'
+ else '\Theta'
+ " />
+ <xsl:text>_{</xsl:text>
+ <xsl:value-of select="$pos" />
+ <xsl:text>}</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ </preproc:sym-ref>
+ </xsl:for-each>
+ </preproc:sym-dep>
+ </xsl:for-each>
+ </preproc:sym-deps>
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @extern='true' ]" mode="preproc:depgen" priority="9">
+ <!-- externs will be processed once they are resolved in another package -->
+</xsl:template>
+
+
+<!-- all symbols with a @parent (e.g. generators) should depend on the parent
+ itself (which of course introduces the parent's dependencies into the tree) -->
+<xsl:template match="preproc:sym[ @parent ]" mode="preproc:depgen" priority="7">
+ <preproc:sym-ref name="{@parent}" />
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='rate' ]" mode="preproc:depgen" priority="5">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="pkg" as="element( lv:package )"
+ select="root(.)" />
+
+ <xsl:variable name="rate" as="element( lv:rate )"
+ select="$pkg/lv:rate[ @yields=$name ]" />
+
+ <xsl:apply-templates mode="preproc:depgen"
+ select="$rate" />
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='class' ]" mode="preproc:depgen" priority="5">
+ <!-- all class symbol names are prefixed with ":class:" -->
+ <xsl:variable name="as" select="substring-after( @name, ':class:' )" />
+ <xsl:variable name="pkg" as="element( lv:package )"
+ select="root(.)" />
+
+ <xsl:apply-templates
+ select="$pkg/lv:classify[ @as=$as ]"
+ mode="preproc:depgen" />
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='param' ]" mode="preproc:depgen" priority="5">
+ <xsl:variable name="name" select="@name" />
+ <xsl:apply-templates
+ select="root(.)/lv:param[ @name=$name ]"
+ mode="preproc:depgen" />
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='func' ]" mode="preproc:depgen" priority="5">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="pkg" as="element( lv:package )"
+ select="root(.)" />
+
+ <xsl:apply-templates
+ select="$pkg/lv:function[ @name=$name ]"
+ mode="preproc:depgen" />
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='type' ]" mode="preproc:depgen" priority="5">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="pkg" as="element( lv:package )"
+ select="root(.)" />
+
+ <!-- a typedef could optionally be contained within another typedef -->
+ <xsl:apply-templates mode="preproc:depgen" select="
+ $pkg/lv:typedef[ @name=$name ]
+ , $pkg/lv:typedef//lv:typedef[ @name=$name ]
+ " />
+</xsl:template>
+
+<xsl:template match="preproc:sym[ @type='lparam' ]" mode="preproc:depgen" priority="5">
+ <!-- do nothing -->
+</xsl:template>
+
+<xsl:template match="preproc:sym[ @type='const' ]" mode="preproc:depgen" priority="5">
+ <!-- do nothing -->
+</xsl:template>
+
+<xsl:template match="preproc:sym[ @type='tpl' ]" mode="preproc:depgen" priority="5">
+ <!-- do nothing -->
+</xsl:template>
+
+<xsl:template match="preproc:sym[ @type='meta' ]" mode="preproc:depgen" priority="5">
+ <!-- do nothing -->
+</xsl:template>
+
+
+<xsl:template match="preproc:sym" mode="preproc:depgen" priority="1">
+ <xsl:message terminate="yes">
+ <xsl:text>[depgen] error: unexpected symbol </xsl:text>
+ <xsl:sequence select="." />
+ </xsl:message>
+</xsl:template>
+
+
+<xsl:template name="preproc:depgen-c-normal" match="c:value-of|c:when" mode="preproc:depgen" priority="5">
+ <xsl:param name="name" select="@name" />
+ <xsl:variable name="pkg" as="element( lv:package )"
+ select="root(.)" />
+
+
+ <xsl:variable name="sym"
+ select="$pkg/preproc:symtable/preproc:sym[ @name=$name ]" />
+
+ <!-- see if there is a c:let associated with this name -->
+ <xsl:variable name="let" select="
+ ancestor::c:let[ c:values/c:value/@name=$name ]
+ " />
+
+ <xsl:choose>
+ <!-- c:let reference -->
+ <xsl:when test="$let">
+ <preproc:sym-ref name=":{$let/@name}:{$name}" />
+ </xsl:when>
+
+ <!-- scalar constant -->
+ <xsl:when test="( $sym/@type='const' ) and ( $sym/@dim='0' )">
+ <!-- while these are optimized away, they are still useful for evaluating
+ dependency trees and generating code -->
+ <preproc:sym-ref name="{$sym/@name}" />
+ </xsl:when>
+
+ <!-- function param reference -->
+ <xsl:when test="$name=ancestor::lv:function/lv:param/@name">
+ <xsl:variable name="fname" as="xs:string"
+ select="ancestor::lv:function/@name" />
+
+ <preproc:sym-ref name=":{$fname}:{$name}"
+ varname="{$name}"/>
+ </xsl:when>
+
+ <!-- index reference -->
+ <xsl:when test="$name=ancestor::c:*[ @of ]/@index" />
+
+ <!-- unknown symbol (it is important to do this after the above checks) -->
+ <xsl:when test="not( $sym )">
+ <!-- do not terminate; validator can provide additional information -->
+ <xsl:message>
+ <xsl:text>[depgen] warning: unknown symbol `</xsl:text>
+ <xsl:value-of select="$name" />
+ <xsl:text>'</xsl:text>
+ </xsl:message>
+ </xsl:when>
+
+ <xsl:when test="$sym/@parent">
+ <preproc:sym-ref name="{$sym/@name}" parent="{$sym/@parent}" />
+ </xsl:when>
+
+ <!-- just an average 'ol symbol -->
+ <xsl:otherwise>
+ <preproc:sym-ref name="{$name}" />
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:apply-templates mode="preproc:depgen" />
+</xsl:template>
+
+
+<xsl:template match="c:sum[@of]|c:product[@of]" mode="preproc:depgen" priority="5">
+ <!-- process using @of -->
+ <xsl:call-template name="preproc:depgen-c-normal">
+ <xsl:with-param name="name" select="@of" />
+ </xsl:call-template>
+</xsl:template>
+
+
+<xsl:template match="c:apply" mode="preproc:depgen" priority="5">
+ <!-- no special treatment yet -->
+ <xsl:call-template name="preproc:depgen-c-normal" />
+</xsl:template>
+
+<xsl:template match="c:apply/c:arg" mode="preproc:depgen" priority="5">
+ <!-- arguments may have calculations, so we must recurse -->
+ <xsl:apply-templates mode="preproc:depgen" />
+</xsl:template>
+
+
+<xsl:template match="c:let/c:values/c:value" mode="preproc:depgen" priority="5">
+ <!-- do not consider the c:value name -->
+ <xsl:apply-templates mode="preproc:depgen" />
+</xsl:template>
+
+
+<xsl:template name="preproc:depgen-match">
+ <xsl:param name="on" select="@on" />
+
+ <xsl:variable name="class" select="ancestor::lv:classify" />
+ <xsl:variable name="sym"
+ select="root(.)/preproc:symtable/preproc:sym[ @name=$on ]" />
+
+ <!-- are we depending on another classification? -->
+ <xsl:if test="$sym/@type='cgen'">
+ <xsl:variable name="cname" select="substring-after( $sym/@parent, ':class:' )" />
+
+ <!-- check if one of our dependencies wants to be external to the classifier,
+ but we're trying to pull them in...tug-of-war -->
+ <xsl:if test="$sym/@extclass='true' and not( $class/@external='true' )">
+ <xsl:message terminate="yes">
+ <xsl:text>[preproc] !!! fatal: internal classification `</xsl:text>
+ <xsl:value-of select="$class/@as" />
+ <xsl:text>' cannot pull in external classification `</xsl:text>
+ <xsl:value-of select="$cname" />
+ <xsl:text>'</xsl:text>
+ </xsl:message>
+ </xsl:if>
+ </xsl:if>
+
+ <!-- process the @on -->
+ <xsl:call-template name="preproc:depgen-c-normal">
+ <xsl:with-param name="name" select="$on" />
+ </xsl:call-template>
+</xsl:template>
+
+
+<xsl:template match="lv:match[ @value ]" mode="preproc:depgen" priority="5">
+ <!-- process the @value -->
+ <xsl:call-template name="preproc:depgen-c-normal">
+ <xsl:with-param name="name" select="@value" />
+ </xsl:call-template>
+
+ <xsl:call-template name="preproc:depgen-match" />
+</xsl:template>
+
+
+<xsl:template match="lv:match[ @anyOf ]" mode="preproc:depgen" priority="6">
+ <!-- process the "normal" match -->
+ <xsl:call-template name="preproc:depgen-match" />
+
+ <!-- we depend on the type -->
+ <preproc:sym-ref name="{@anyOf}" />
+ <xsl:call-template name="preproc:depgen-match" />
+</xsl:template>
+
+
+<xsl:template match="lv:match[ @pattern ]" mode="preproc:depgen" priority="5">
+ <!-- there are no pattern dependencies; process @on -->
+ <xsl:call-template name="preproc:depgen-match" />
+</xsl:template>
+
+
+<!-- match on calculated value -->
+<xsl:template match="lv:match[ c:* ]" mode="preproc:depgen" priority="6">
+ <!-- process the "normal" match -->
+ <xsl:call-template name="preproc:depgen-match" />
+
+ <!-- process the calculation dependencies -->
+ <xsl:apply-templates select="c:*" mode="preproc:depgen" />
+</xsl:template>
+
+
+<xsl:template match="lv:template/lv:param" mode="preproc:depgen" priority="9">
+ <!-- ignore -->
+</xsl:template>
+
+
+<xsl:template match="lv:param" mode="preproc:depgen" priority="5">
+ <!-- while the type is reduced to a primitive, let's still include the
+ dependency symbol -->
+ <preproc:sym-ref name="{@type}" />
+</xsl:template>
+
+
+<xsl:template match="lv:typedef" mode="preproc:depgen" priority="5">
+ <!-- we depend on any types that we create a union of -->
+ <xsl:for-each select="lv:union/lv:typedef">
+ <preproc:sym-ref name="{@name}" />
+ </xsl:for-each>
+</xsl:template>
+
+
+<!-- @class deps -->
+<xsl:template match="lv:class" mode="preproc:depgen" priority="5">
+ <preproc:sym-ref name=":class:{@ref}" class-no="{@no}" />
+</xsl:template>
+
+
+<xsl:template match="c:*|lv:*" mode="preproc:depgen" priority="3">
+ <!-- ignore -->
+ <xsl:apply-templates mode="preproc:depgen" />
+</xsl:template>
+
+
+<xsl:template match="text()" mode="preproc:depgen" priority="2">
+ <!-- not interested. nope. -->
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/display.xsl b/src/current/include/display.xsl
new file mode 100644
index 0000000..7296b56
--- /dev/null
+++ b/src/current/include/display.xsl
@@ -0,0 +1,551 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Display-related tasks
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:sym="http://www.lovullo.com/rater/symbol-map"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc"
+ xmlns:summary="http://www.lovullo.com/rater/summary"
+
+ xmlns:exsl="http://exslt.org/common"
+ extension-element-prefixes="exsl">
+
+
+<!-- maps certain elements to their default symbols -->
+<xsl:variable name="symbol-map" select="document( 'symbol-map.xml' )/sym:symbol-map/*" />
+
+<!-- easy-to-reference linked dependency list -->
+<xsl:variable name="edeps" select="/lv:*/preproc:deps/preproc:sym" />
+
+<xsl:template name="get-symbol-map">
+ <xsl:copy-of select="$symbol-map" />
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='rate' ]" mode="summary:desc" priority="5">
+ <span class="letlist-{@name}">
+ <a href="#{@name}">
+ <xsl:value-of select="@name" />
+ </a>
+ <xsl:text> scalar</xsl:text>
+ </span>
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='gen' ]" mode="summary:desc" priority="5">
+ <span class="letlist-{@parent}">
+ <a href="#{@parent}">
+ <xsl:value-of select="@name" />
+ </a>
+ <xsl:text> generator; vector</xsl:text>
+
+ <span class="param">
+ <xsl:text> (</xsl:text>
+ <a href="#{@parent}">
+ <xsl:value-of select="@parent" />
+ </a>
+ <xsl:text>)</xsl:text>
+ </span>
+ </span>
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='cgen' ]" mode="summary:desc" priority="5">
+ <xsl:variable name="parent" select="@parent" />
+ <xsl:variable name="sym" select="
+ ancestor::preproc:symtable/preproc:sym[ @name=$parent ]
+ " />
+
+ <xsl:apply-templates select="$sym" mode="summary:desc" />
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='class' ]" mode="summary:desc" priority="5">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="document" select="
+ if ( @src ) then
+ document( concat( @src, '.xmlo' ), . )/lv:*
+ else
+ /lv:*
+ " />
+ <xsl:variable name="class" select="
+ $document/lv:classify[
+ @as=substring-after( $name, ':class:' )
+ ]
+ " />
+
+ <span class="letlist-{$class/@as}">
+ <xsl:text>"</xsl:text>
+ <xsl:value-of select="$class/@desc" />
+ <xsl:text>"</xsl:text>
+ <xsl:text> classification </xsl:text>
+
+ <xsl:choose>
+ <xsl:when test="@dim = '0'">
+ <xsl:text>scalar</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="@dim = '1'">
+ <xsl:text>vector</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="@dim = '2'">
+ <xsl:text>matrix</xsl:text>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text> [dim </xsl:text>
+ <xsl:value-of select="@dim" />
+ <xsl:text>]</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <!-- TODO: use generator in letlist-* -->
+ <span class="param">
+ <xsl:text> (</xsl:text>
+ <a href="#:class:{$class/@as}">
+ <xsl:value-of select="$class/@as" />
+ </a>
+ <xsl:text>)</xsl:text>
+ </span>
+ </span>
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='const' ]" mode="summary:desc" priority="5">
+ <xsl:value-of select="@name" />
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='param' ]" mode="summary:desc" priority="5">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="document" select="
+ if ( @src ) then
+ document( concat( @src, '.xmlo' ), . )/lv:*
+ else
+ /lv:*
+ " />
+ <xsl:variable name="param" select="
+ $document/lv:param[
+ @name=$name
+ ]
+ " />
+
+ <xsl:value-of select="$param/@desc" />
+
+ <span class="param letlist-{$param/@name}">
+ <xsl:text> (</xsl:text>
+ <a href="#{$param/@name}">
+ <xsl:value-of select="$param/@name" />
+ </a>
+ <xsl:text>)</xsl:text>
+ </span>
+</xsl:template>
+
+
+<xsl:template match="preproc:sym" mode="summary:desc" priority="1">
+ <xsl:value-of select="@name" />
+ <xsl:text> (!)</xsl:text>
+</xsl:template>
+
+
+<xsl:template name="get-symbol">
+ <xsl:param name="name" select="@name" />
+ <xsl:param name="index" />
+ <xsl:param name="index-symbol" />
+ <xsl:param name="default" />
+
+ <preproc:sym-ref name="{$name}">
+ <!-- might be an empty string (if provided) -->
+ <xsl:if test="$default">
+ <xsl:attribute name="default" select="$default" />
+ </xsl:if>
+ </preproc:sym-ref>
+
+ <xsl:choose>
+ <xsl:when test="$index-symbol != ''">
+ <xsl:text>_{</xsl:text>
+ <xsl:value-of select="$index-symbol" />
+ <xsl:text>}</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="$index">
+ <xsl:text>_{</xsl:text>
+ <preproc:sym-ref name="{$index}" default="{$index}" />
+ <xsl:text>}</xsl:text>
+ </xsl:when>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template name="_get-index-symbol">
+ <xsl:param name="element" />
+ <xsl:param name="index" />
+ <xsl:param name="search" />
+
+ <xsl:call-template name="get-symbol">
+ <xsl:with-param name="name" select="$index" />
+ <xsl:with-param name="search" select="$search" />
+ <xsl:with-param name="default" select="$index" />
+ </xsl:call-template>
+</xsl:template>
+
+
+<!--
+ Retrieve the default symbol for the given type (in LaTeX)
+
+ If the type is "function", the given name will be used for its default symbol.
+
+ @param Node element node to retrieve symbol for
+ @param NodeSet search all document nodes
+
+ @return default symbol (LaTeX)
+-->
+<xsl:template name="_get-default-symbol">
+ <xsl:param name="element" />
+ <xsl:param name="name" />
+ <xsl:param name="index" />
+ <xsl:param name="search" />
+
+ <xsl:variable name="type">
+ <xsl:choose>
+ <xsl:when test="
+ ( local-name( $element ) = 'param' )
+ and ( local-name( $element/.. ) = 'function' )">
+
+ <!-- this is a function parameter; make a distinction between a global
+ parameter -->
+ <xsl:text>fparam</xsl:text>
+ </xsl:when>
+
+ <!-- if matching lv:classify/@as, then it represents an accumulator -->
+ <xsl:when test="
+ ( local-name( $element ) = 'classify' )
+ and ( $element/@as = $name )
+ ">
+
+ <xsl:text>class</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="$element/@generates = $name">
+ <xsl:text>generator</xsl:text>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:value-of select="local-name( $element )" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:variable name="symbol" select="$symbol-map[@type=$type]" />
+
+ <!-- output the symbol default -->
+ <xsl:choose>
+ <!-- certain types use their own name for a default (e.g. functions) -->
+ <xsl:when test="$symbol/sym:name">
+ <xsl:text>\textrm{</xsl:text>
+ <xsl:value-of select="$name" />
+ <xsl:text>}</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="$symbol/sym:nothing">
+ <!-- do nothing; no symbol is desired -->
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:if test="$index and ( $index != '' )">
+ <xsl:text>(</xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="$symbol" />
+
+ <!-- determine if our default index should be subscript or superscript -->
+ <xsl:variable name="subsup">
+ <xsl:choose>
+ <xsl:when test="$symbol/@index-pos">
+ <xsl:value-of select="$symbol/@index-pos" />
+ </xsl:when>
+
+ <!-- default to subscript -->
+ <xsl:otherwise>
+ <xsl:text>_</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <!-- in addition to the symbol itself, which alone is not likely to be
+ unique, we will add a subscript to uniquely identify it by number -->
+ <xsl:if test="$search">
+ <xsl:value-of select="$subsup" />
+ <xsl:text>{</xsl:text>
+
+ <xsl:call-template name="_get-name-index">
+ <xsl:with-param name="element" select="$element" />
+ <xsl:with-param name="name" select="$name" />
+ <xsl:with-param name="search" select="$search" />
+ </xsl:call-template>
+
+ <xsl:text>}</xsl:text>
+ </xsl:if>
+
+ <xsl:if test="$index and ( $index != '' )">
+ <xsl:text>)</xsl:text>
+ </xsl:if>
+
+ <!-- if an index was given, and our default index was *not* a subscript,
+ then we can dedicate the subscript to the index -->
+ <xsl:if test="$index and ( $index != '' )">
+ <xsl:text>_{</xsl:text>
+ <xsl:value-of select="$index" />
+ <xsl:text>}</xsl:text>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!--
+ Retrieve index of the element associated with the given name across all named
+ elements of the same type and parent type in all of $search
+
+ TODO: surely there's a more performant manner...not that speed is an issue
+ right now
+
+ @param Node element node to retrieve symbol for
+ @param NodeSet search all document nodes
+
+ @return index
+-->
+<xsl:template name="_get-name-index">
+ <xsl:param name="element" />
+ <xsl:param name="name" />
+ <xsl:param name="search" />
+
+ <xsl:choose>
+ <!-- functions are handled slightly differently, as they introduce scope -->
+ <xsl:when test="local-name( $element/.. ) = 'function'">
+ <xsl:for-each select="$element/../lv:param">
+ <xsl:if test="@name = $name">
+ <xsl:value-of select="position()" />
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:when>
+
+ <!-- non-function -->
+ <xsl:otherwise>
+ <xsl:value-of select="
+ $search//summary:default-indexes/summary:index[ @name=$name ]/@value"
+ />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!--
+ Retrieve description for the given element by name
+
+ $vardesc, for those who support it, is useful if the description describes the
+ node, not a variable generated from it. For example, lv:classify's description
+ is a short description of the classification, but if documenting @yields, we
+ want to describe what it is yielding, which would not be immediately clear
+ from the description.
+
+ @param string name name of element
+ @param NodeSet search all documents to search
+
+ @return element description
+-->
+<xsl:template name="get-desc">
+ <xsl:param name="name" />
+ <xsl:param name="search" />
+
+ <!-- XXX: Have to maintain this list! -->
+ <xsl:variable name="desc"
+ select="$search//summary:descs/summary:desc[ @name=$name ]/@desc" />
+
+ <xsl:choose>
+ <xsl:when test="$desc">
+ <xsl:copy-of select="$desc" />
+ </xsl:when>
+
+ <!-- if we cannot find the element, then display an error -->
+ <xsl:otherwise>
+ <span class="error">
+ <xsl:text>Unknown @name reference: </xsl:text>
+ <xsl:value-of select="$name" />
+ </span>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+
+
+
+<!--
+ Retrieve processed name for the given element by name
+
+ @param string name name of element
+ @param NodeSet search all documents to search
+
+ @return element description
+-->
+<xsl:template name="get-name">
+ <xsl:param name="name" />
+ <xsl:param name="search" />
+
+ <xsl:value-of select="
+ $search//summary:descs/summary:desc[ @name=$name ]/@display
+ " />
+</xsl:template>
+
+
+<xsl:template match="lv:rate" mode="gen-let-list" priority="5">
+ <xsl:param name="deps" />
+ <xsl:param name="context" />
+
+ <xsl:call-template name="do-gen-let-list">
+ <xsl:with-param name="symname" select="@yields" />
+ <xsl:with-param name="context" select="$context" />
+ </xsl:call-template>
+</xsl:template>
+
+
+<xsl:template match="lv:function" mode="gen-let-list" priority="5">
+ <xsl:param name="deps" />
+
+ <xsl:call-template name="do-gen-let-list">
+ <xsl:with-param name="symname" select="@name" />
+ </xsl:call-template>
+</xsl:template>
+
+
+<xsl:template match="*" mode="gen-let-list" priority="1">
+ <xsl:message terminate="yes">
+ <xsl:text>[summary] !!! unknown let-list type </xsl:text>
+ <xsl:value-of select="name()" />
+ </xsl:message>
+</xsl:template>
+
+
+<!--
+ Generate list of let statements describing each variable in the given node set
+
+ Variables come from various sources depending on the operation being
+ performed.
+-->
+<xsl:template name="do-gen-let-list">
+ <xsl:param name="context" />
+ <xsl:param name="symname" />
+
+ <xsl:variable name="deps" select="
+ /lv:*/preproc:sym-deps/preproc:sym-dep[
+ @name=$symname
+ ]
+ " />
+
+ <ul class="let">
+ <!-- output a description for each dependency -->
+ <xsl:variable name="result">
+ <xsl:for-each select="
+ /lv:*/preproc:symtable/preproc:sym[
+ not( @type='lparam' )
+ and @name=$deps/preproc:sym-ref/@name
+ ]
+ ">
+
+ <xsl:call-template name="_gen-let-list-item">
+ <xsl:with-param name="context" select="$context" />
+ </xsl:call-template>
+ </xsl:for-each>
+
+
+ <!-- handle c:let formatting separately -->
+ <xsl:for-each select="
+ /lv:*/preproc:symtable/preproc:sym[
+ @type='lparam'
+ and @name=$deps/preproc:sym-ref/@name
+ ]
+ ">
+
+ <xsl:call-template name="_gen-let-list-item">
+ <xsl:with-param name="context" select="$context" />
+ <xsl:with-param name="class" select="'letequ'" />
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+
+ <xsl:apply-templates select="$result" mode="typeset-final">
+ <xsl:with-param name="deps" select="$deps" />
+ </xsl:apply-templates>
+ </ul>
+</xsl:template>
+
+
+<xsl:template name="_gen-let-list-item">
+ <xsl:param name="context" />
+ <xsl:param name="class" />
+
+ <li>
+ <xsl:if test="$class">
+ <xsl:attribute name="class" select="$class" />
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="@type='lparam' and $context">
+ <xsl:text>\(</xsl:text>
+ <preproc:sym-ref name="{@name}" />
+ <xsl:text> = </xsl:text>
+
+ <xsl:variable name="varname" select="@varname" />
+
+ <xsl:apply-templates select="
+ $context//c:let/c:values/c:value[
+ @name=$varname
+ ]/c:*
+ " />
+ <xsl:text>\) </xsl:text>
+
+ <span class="letdesc">
+ <xsl:text>(</xsl:text>
+ <xsl:value-of select="@desc" />
+ <xsl:text>)</xsl:text>
+ </span>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text>let \(</xsl:text>
+ <preproc:sym-ref name="{@name}" />
+ <xsl:text>\) = </xsl:text>
+
+ <xsl:apply-templates select="." mode="summary:desc" />
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <!--
+ <xsl:variable name="param-name">
+ <xsl:call-template name="get-name">
+ <xsl:with-param name="name" select="$param" />
+ <xsl:with-param name="search" select="/" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:if test="$param-name != ''">
+ <span class="param letlist-{$param-name}">
+ <xsl:text> (</xsl:text>
+ <a href="#{$param-name}">
+ <xsl:value-of select="$param-name" />
+ </a>
+ <xsl:text>)</xsl:text>
+ </span>
+ </xsl:if>
+ -->
+ </li>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/dslc-base.xsl b/src/current/include/dslc-base.xsl
new file mode 100644
index 0000000..53a3195
--- /dev/null
+++ b/src/current/include/dslc-base.xsl
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Additional functionality provided by dslc
+
+ XSL does not provide every feature suitable for compilation (which is no
+ suprise, since this was not its intended use case). As such, dslc provides
+ additional features that are defined/abstracted within this file; every
+ template that is intended for use with dslc should include this.
+-->
+<xsl:stylesheet version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+
+<!--
+ Package source path, stripped of its extension
+
+ XSL does not provide a means of exposing the file path (nor should it,
+ really). This param will hold the source path of the package, sans its
+ extension, relative to the project root that was used during compilation.
+
+ I.e., given this source path:
+ suppliers/common/foo.xml
+ we would expect this value for __srcpkg:
+ suppliers/common/foo
+
+ By stripping the extension, we have the benefit of being void of any semantics
+ that may be associated with it (e.g. xml vs xmlo vs xmle); rather, that
+ information should be derived from the structe of the document itself and the
+ path can be used as an identifier to describe the document as a whole,
+ regardless of what form it is in.
+
+ Consequently, no two files are able to have the same __srcpkg string; this
+ value may therefore be used for disambiguation.
+-->
+<xsl:param name="__srcpkg" />
+
+
+<!--
+ Relative path to project root
+
+ The project root is determined entirely by __srcpath by repeating the string
+ "../" for the number of occurrances of "/".
+-->
+<xsl:param name="__relroot" />
+
+
+<!--
+ Random value that may be used to seed random values
+
+ XSLT is deterministic and does not offer support for generating random values;
+ its generate-id() function is not sufficient for cross-package generation.
+-->
+<xsl:param name="__rseed" />
+
+
+<!--
+ Root node of template on which stylesheet was invoked
+
+ This points to the original, unprocessed document. This is especially
+ important for `document' function calls, which use nodes as a reference
+ point for resolving relative paths.
+-->
+<xsl:variable name="__entry-root" select="/" />
+
+
+
+<!--
+ Apply relative root to PATH
+
+ If PATH is an absolute path, it will be prefixed with the relative root
+ with the leading path delimiter stripped; otherwise, it will be echoed
+ as-is.
+-->
+<xsl:template name="__apply-relroot">
+ <xsl:param name="path" />
+
+ <xsl:choose>
+ <xsl:when test="starts-with( $path, '/' )">
+ <xsl:value-of select="$__relroot" />
+ <xsl:value-of select="substring-after( $path, '/' )" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:value-of select="$path" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/entry-form.xsl b/src/current/include/entry-form.xsl
new file mode 100644
index 0000000..3d6b3c8
--- /dev/null
+++ b/src/current/include/entry-form.xsl
@@ -0,0 +1,323 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Outputs HTML form that can be used to feed values to the rater for testing
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:l="http://www.lovullo.com/rater/linker"
+ xmlns:util="http://www.lovullo.com/util"
+ xmlns:ext="http://www.lovullo.com/ext"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc"
+
+ xmlns:exsl="http://exslt.org/common"
+ xmlns:str="http://exslt.org/strings"
+ extension-element-prefixes="exsl str">
+
+
+<!--
+ Generate HTML entry form for testing
+
+ Allows for collection of data to feed to the rater.
+
+ The entry form will only be generated for raters, not other packages (since
+ actual rating will need to be performed).
+
+ @return form HTML
+-->
+<xsl:template match="lv:package" mode="entry-form">
+ <xsl:param name="root-pkg" />
+
+ <form class="entry-form">
+ <h1>Rating Test Case</h1>
+
+ <div class="foot">
+ <p id="prior-message"></p>
+
+ <div>
+ <input type="submit" value="Calculate Premium" />
+ <input type="reset" value="Reset" />
+ </div>
+
+ <div class="final-premium"></div>
+
+ <div class="final-accept">
+ <button id="final-accept-good">Looks Good!</button>
+ <button id="final-accept-bad">Incorrect</button>
+ </div>
+
+ <div class="final-comments">
+ <h1>Submit Test Case</h1>
+
+ <p>Submission comments (please describe what you were testing, the
+ desired result and, if the premium was incorrect, what went wrong):</p>
+
+ <textarea id="final-comments"></textarea>
+
+ <div id="final-expect-container">
+ <p>Expected premium (if known; must be exact); this will allow us to
+ automatically re-run this test when we believe that the problem has been
+ fixed. <strong>Otherwise, you must re-test manually:</strong></p>
+ <input type="text" id="final-expected" value="" />
+ <em>(Only fill out if it does not hit the minimum premium.)</em>
+ </div>
+
+ <br />
+ <label><input type="checkbox" id="final-waiting"> Requires Testing</input></label>
+
+ <br />
+ <button id="final-submit">Submit</button>
+ <button id="final-submit-new">Submit As New Test Case</button>
+ <button id="final-cancel">Nevermind. Cancel.</button>
+ </div>
+ </div>
+
+ <dl>
+ <!-- generate HTML elements for each *global* parameter, *but only if it
+ is used in the rater* -->
+ <xsl:apply-templates
+ select="/lv:package/l:dep/preproc:sym[ @type='param' ]"
+ mode="entry-form">
+
+ <xsl:with-param name="root-pkg" select="$root-pkg" />
+ </xsl:apply-templates>
+ </dl>
+ </form>
+
+ <script type="text/javascript" src="{$fw-path}/rater/scripts/entry-form.js"></script>
+</xsl:template>
+
+
+<!--
+ Generate text and input for a global parameter
+
+ @return parameter HTML
+-->
+<xsl:template match="preproc:sym" mode="entry-form">
+ <xsl:param name="root-pkg" />
+
+ <xsl:variable name="self" select="." />
+ <xsl:variable name="package" select="
+ if ( @src and not( @src='' ) ) then
+ document( concat( @src, '.xmlo' ), . )/lv:*
+ else
+ $root-pkg
+ " />
+
+ <xsl:variable name="name">
+ <xsl:value-of select="@name" />
+
+ <!-- if this is a set, then we will need to generate an array of
+ elements -->
+ <xsl:if test="number(@dim) gt 0">
+ <xsl:text>[]</xsl:text>
+ </xsl:if>
+ </xsl:variable>
+
+ <xsl:variable name="param"
+ select="$package/lv:param[ @name=$self/@name ]" />
+
+ <dt id="param-{@name}">
+ <xsl:value-of select="@desc" />
+ </dt>
+
+ <xsl:variable name="matrix">
+ <xsl:if test="number(@dim) gt 1">
+ <xsl:text> matrix</xsl:text>
+ </xsl:if>
+ </xsl:variable>
+
+ <!-- generate field itself -->
+ <dd id="param-input-{@name}">
+ <div class="entry-row{$matrix}">
+ <div class="entry-field">
+ <xsl:apply-templates select="$param" mode="entry-form-field">
+ <xsl:with-param name="name" select="$name" />
+ <xsl:with-param name="sym" select="$self" />
+ <xsl:with-param name="pkg" select="$package" />
+ </xsl:apply-templates>
+
+ <!-- if this is a set, add the ability to remove values -->
+ <xsl:if test="number(@dim) gt 0">
+ <button class="entry-rm">-</button>
+ </xsl:if>
+ </div>
+
+ <xsl:if test="number(@dim) gt 1">
+ <button class="entry-add-matrix">+</button>
+ </xsl:if>
+ </div>
+
+ <!-- if this is a set, add ability to add values -->
+ <xsl:if test="number(@dim) gt 0">
+ <button class="entry-add">+</button>
+ </xsl:if>
+ </dd>
+</xsl:template>
+
+
+<!--
+ Generate input field for integer parameters
+
+ @return parameter HTML
+-->
+<xsl:template match="lv:param[@type='integer']" mode="entry-form-field">
+ <xsl:param name="name" select="@name" />
+ <input type="text" name="{$name}" value="{@default}" />
+</xsl:template>
+
+
+<!--
+ Generate input field for float parameters
+
+ @return parameter HTML
+-->
+<xsl:template match="lv:param[@type='float']" mode="entry-form-field">
+ <xsl:param name="name" select="@name" />
+ <input type="text" name="{$name}" value="{@default}" />
+</xsl:template>
+
+
+<!--
+ Generate radio fields for boolean parameters
+
+ @return parameter HTML
+-->
+<xsl:template match="lv:param[@type='boolean']" mode="entry-form-field">
+ <xsl:param name="name" select="@name" />
+
+ <xsl:variable name="default-y">
+ <xsl:if test="@default = '1'">
+ <xsl:text>selected</xsl:text>
+ </xsl:if>
+ </xsl:variable>
+
+ <xsl:variable name="default-n">
+ <xsl:if test="@default = '0'">
+ <xsl:text>selected</xsl:text>
+ </xsl:if>
+ </xsl:variable>
+
+ <select name="{$name}">
+ <option selected="{$default-y}" value="1">Yes</option>
+ <option selected="{$default-n}" value="0">No</option>
+ </select>
+</xsl:template>
+
+
+<!--
+ Handle parameters that are either of unknown or user-defined types
+
+ @return parameter HTML
+-->
+<xsl:template match="lv:param" mode="entry-form-field">
+ <xsl:param name="name" select="@name" />
+ <xsl:param name="sym" />
+ <xsl:param name="pkg" />
+
+ <xsl:variable name="type" select="@type" />
+
+ <!-- the typedef may or may not be in the same package as the param -->
+ <xsl:variable name="typesym" select="
+ $pkg/preproc:symtable/preproc:sym[
+ @type='type'
+ and @name=$type
+ ]
+ " />
+
+ <!-- if the @src attribute is empty, then it resides within the same package
+ -->
+ <xsl:variable name="typesrc">
+ <xsl:choose>
+ <xsl:when test="@src">
+ <xsl:value-of select="@src" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:value-of select="$sym/@src" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <!-- load the typedef from the appropriate package -->
+ <xsl:variable name="typepkg" select="
+ if ( @src and not( @src='' ) ) then
+ document( concat( $typesrc, '.xmlo' ), $sym )/lv:*
+ else
+ $pkg
+ " />
+ <!-- this makes maintinance more difficult, but speeds up searching large
+ trees -->
+ <xsl:variable name="typedef" select="
+ $typepkg/lv:typedef[ @name=$type ]
+ |$typepkg/lv:typedef/lv:union/lv:typedef[ @name=$type ]
+ " />
+
+ <xsl:choose>
+ <xsl:when test="$typedef/lv:enum|$typedef/lv:union">
+ <xsl:apply-templates select="." mode="entry-form-field-enum">
+ <xsl:with-param name="name" select="$name" />
+ <xsl:with-param name="typedef" select="$typedef" />
+ </xsl:apply-templates>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:message>
+ <xsl:text>[summary] warning: unknown param type `</xsl:text>
+ <xsl:value-of select="$typesym/@src" />
+ <xsl:text>/</xsl:text>
+ <xsl:value-of select="@type" />
+ <xsl:text>'</xsl:text>
+ </xsl:message>
+
+ <span class="error">
+ <xsl:text>Unknown type: </xsl:text>
+ <xsl:value-of select="@type" />
+ </span>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!--
+ Generate HTML for enumerated lists
+
+ @return parameter HTML
+-->
+<xsl:template match="lv:param" mode="entry-form-field-enum">
+ <xsl:param name="name" select="@name" />
+ <xsl:param name="typedef" />
+
+ <xsl:variable name="type" select="@type" />
+
+ <!-- get all fields, even if they're within a union -->
+ <xsl:variable name="fields" select="$typedef//lv:enum/lv:item" />
+
+ <select name="{$name}" value="{@default}">
+ <option value=""></option>
+
+ <xsl:for-each select="$fields">
+ <xsl:variable name="value">
+ <xsl:choose>
+ <xsl:when test="@value">
+ <xsl:value-of select="@value" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <option value="{$value}">
+ <xsl:value-of select="@name" />
+ <xsl:text>: </xsl:text>
+ <xsl:value-of select="@desc" />
+ </option>
+ </xsl:for-each>
+ </select>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/exslt/str.tokenize.template.xsl b/src/current/include/exslt/str.tokenize.template.xsl
new file mode 100644
index 0000000..6da270b
--- /dev/null
+++ b/src/current/include/exslt/str.tokenize.template.xsl
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:str="http://exslt.org/strings"
+ extension-element-prefixes="str">
+
+<xsl:template name="str:tokenize">
+ <xsl:param name="string" select="''" />
+ <xsl:param name="delimiters" select="' &#x9;&#xA;'" />
+ <xsl:choose>
+ <xsl:when test="not($string)" />
+ <xsl:when test="not($delimiters)">
+ <xsl:call-template name="str:_tokenize-characters">
+ <xsl:with-param name="string" select="$string" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="str:_tokenize-delimiters">
+ <xsl:with-param name="string" select="$string" />
+ <xsl:with-param name="delimiters" select="$delimiters" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="str:_tokenize-characters">
+ <xsl:param name="string" />
+ <xsl:if test="$string">
+ <token><xsl:value-of select="substring($string, 1, 1)" /></token>
+ <xsl:call-template name="str:_tokenize-characters">
+ <xsl:with-param name="string" select="substring($string, 2)" />
+ </xsl:call-template>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template name="str:_tokenize-delimiters">
+ <xsl:param name="string" />
+ <xsl:param name="delimiters" />
+ <xsl:variable name="delimiter" select="substring($delimiters, 1, 1)" />
+ <xsl:choose>
+ <xsl:when test="not($delimiter)">
+ <token><xsl:value-of select="$string" /></token>
+ </xsl:when>
+ <xsl:when test="contains($string, $delimiter)">
+ <xsl:if test="not(starts-with($string, $delimiter))">
+ <xsl:call-template name="str:_tokenize-delimiters">
+ <xsl:with-param name="string" select="substring-before($string, $delimiter)" />
+ <xsl:with-param name="delimiters" select="substring($delimiters, 2)" />
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:call-template name="str:_tokenize-delimiters">
+ <xsl:with-param name="string" select="substring-after($string, $delimiter)" />
+ <xsl:with-param name="delimiters" select="$delimiters" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="str:_tokenize-delimiters">
+ <xsl:with-param name="string" select="$string" />
+ <xsl:with-param name="delimiters" select="substring($delimiters, 2)" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/orderizer.xsl b/src/current/include/orderizer.xsl
new file mode 100644
index 0000000..170bd2b
--- /dev/null
+++ b/src/current/include/orderizer.xsl
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ No, not "odorizer".
+
+ This is a powerful system that takes an immensely complex (and insurmountable)
+ task out of the programmer's hands. In particular, the system:
+
+ - Uses the map to recognize the order in which params appear in a UI
+ - Using that order, determines which fields in the UI could potentially
+ cause fields that appear previous to them to become invalid (e.g. hide)
+ due to classification criteria.
+ - Based on those conflicts, constructs a custom classification that ignores
+ only the conflicting portions, allowing a great deal of precision in
+ controlling field validity up to that particular point in the UI.
+
+ The result is highly-refined, custom-generated classifications per-question
+ for only the criteria that are needed to ensure that fields cannot hide fields
+ previous to them: A task that would otherwise be prohibitively complicated (or
+ would otherwise have to be far too coarse) if done manually in systems with
+ highly sophisticated classification schemes. Furthermore, the result is wholly
+ deterministic.
+
+ It should be noted that futher benefit can be realized when the map is altered
+ or questions in the UI are reordered; the system will simply re-calculate new
+ classifications that yield desirable results.
+-->
+
+<xsl:stylesheet version="2.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:lvp="http://www.lovullo.com"
+ xmlns:lvm="http://www.lovullo.com/rater/map"
+ xmlns:lvmc="http://www.lovullo.com/rater/map/compiler"
+ xmlns:gc="http://www.lovullo.com/calc/global-classifier"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:o="http://www.lovullo.com/rater/compiler/orderizer"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc">
+
+
+
+<!--
+ Determines param conflicts based on UI ordering
+-->
+<xsl:template name="o:analyze">
+ <xsl:param name="class-deps" />
+ <xsl:param name="ui" />
+ <xsl:param name="sdmap" />
+ <xsl:param name="param-classes" />
+
+ <xsl:variable name="rater" select="." />
+
+ <!-- put fields in the order that they appear in the UI -->
+ <!-- TODO: duplicate check (error) -->
+ <xsl:variable name="ordered">
+ <o:ordered>
+ <xsl:for-each select="$ui//lvp:question">
+ <xsl:variable name="id" select="@id" />
+ <xsl:copy-of select="$sdmap/lvmc:map[ @from=$id ]" />
+ </xsl:for-each>
+ </o:ordered>
+ </xsl:variable>
+
+ <!-- the param-class list gives us the classes that are directly used; let's
+ get a list of all classes that are used by those classes as well, which
+ will simplify the queries to come -->
+ <xsl:message>[orderizer] recursively discovering param classes...</xsl:message>
+ <xsl:variable name="param-classes-expanded">
+ <xsl:apply-templates select="$param-classes" mode="o:gen-param-reflist">
+ <xsl:with-param name="class-deps" select="$class-deps" />
+ </xsl:apply-templates>
+ </xsl:variable>
+
+ <xsl:variable name="initial">
+ <o:analysis>
+ <xsl:for-each select="$ordered//lvmc:*">
+ <xsl:variable name="cur" select="." />
+ <xsl:variable name="pref" select="@to" />
+
+ <!-- progress indicator -->
+ <xsl:message>
+ <xsl:text>[orderizer] checking previous UI siblings: </xsl:text>
+ <xsl:value-of select="@to" />
+ </xsl:message>
+
+ <!-- preceding -->
+ <xsl:for-each select="
+ $param-classes/gc:param[
+ @ref=$cur/preceding-sibling::lvmc:map/@to
+ ]">
+
+ <!-- immediate conflicts (we check these separately rather than in the
+ xpath above, which would be cleaner, so that they can be
+ processed -->
+ <xsl:variable name="conflicts" select="
+ .//gc:class[
+ @ref=$param-classes-expanded/o:param-refs/o:param[
+ @ref=$pref
+ ]/o:class/@ref
+ ]
+ " />
+
+ <xsl:if test="$conflicts">
+ <o:conflict ref="{@ref}" relative-to="{$pref}">
+ <xsl:for-each select="$conflicts">
+ <!-- record the immediate problem -->
+ <o:class ref="{@ref}" yields="{@yields}" />
+ </xsl:for-each>
+ </o:conflict>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:for-each>
+ </o:analysis>
+ </xsl:variable>
+
+ <xsl:apply-templates select="$initial/o:analysis" mode="o:reduce-analysis" />
+</xsl:template>
+
+
+<xsl:template match="gc:param-classes" mode="o:gen-param-reflist" priority="5">
+ <xsl:param name="class-deps" />
+
+ <o:param-refs>
+ <xsl:apply-templates select="gc:param" mode="o:gen-param-reflist">
+ <xsl:with-param name="class-deps" select="$class-deps" />
+ </xsl:apply-templates>
+ </o:param-refs>
+</xsl:template>
+
+<xsl:template match="gc:param" mode="o:gen-param-reflist" priority="5">
+ <xsl:param name="class-deps" />
+
+ <o:param ref="{@ref}">
+ <xsl:apply-templates select="gc:class" mode="o:gen-param-reflist">
+ <xsl:with-param name="class-deps" select="$class-deps" />
+ </xsl:apply-templates>
+ </o:param>
+</xsl:template>
+
+<xsl:template match="gc:class" mode="o:gen-param-reflist" priority="5">
+ <xsl:param name="class-deps" />
+
+ <!-- well, this class is certainly used -->
+ <o:class ref="{@ref}" />
+
+ <xsl:variable name="ref" select="@ref" />
+
+ <!-- but how about things that use this class? -->
+ <xsl:apply-templates select="$class-deps/preproc:class[ @ref=$ref ]"
+ mode="o:gen-param-reflist">
+ <xsl:with-param name="class-deps" select="$class-deps" />
+ </xsl:apply-templates>
+</xsl:template>
+
+<xsl:template match="preproc:class" mode="o:gen-param-reflist" priority="5">
+ <xsl:param name="class-deps" />
+
+ <o:class ref="{@ref}" />
+
+ <xsl:apply-templates mode="o:gen-param-reflist">
+ <xsl:with-param name="class-deps" select="$class-deps" />
+ </xsl:apply-templates>
+</xsl:template>
+
+<xsl:template match="*" mode="o:gen-param-reflist" priority="1">
+ <!-- do nothing -->
+</xsl:template>
+
+
+<xsl:template match="preproc:class" mode="o:get-indirect-params" priority="5">
+ <xsl:apply-templates mode="o:get-indirect-params" />
+</xsl:template>
+
+<xsl:template match="preproc:class-dep" mode="o:get-indirect-params" priority="5">
+ <xsl:variable name="ref" select="@ref" />
+
+ <xsl:apply-templates
+ select="ancestor::preproc:class-deps/preproc:class[ @ref=$ref ]"
+ mode="o:get-indirect-params" />
+</xsl:template>
+
+<xsl:template match="preproc:rate-dep" mode="o:get-indirect-params" priority="5">
+ <xsl:variable name="ref" select="@ref" />
+
+ <xsl:apply-templates
+ select="//preproc:rate-deps/preproc:rate[ @ref=$ref ]"
+ mode="o:get-indirect-params" />
+</xsl:template>
+
+<xsl:template match="preproc:param" mode="o:get-indirect-params" priority="5">
+ <xsl:copy-of select="." />
+</xsl:template>
+
+<xsl:template match="*" mode="o:get-indirect-params" priority="1">
+ <!-- do nothing -->
+</xsl:template>
+
+
+<!--
+ Combines initial analysis results, merging common refs and de-duplicating
+ conflicts.
+-->
+<xsl:template match="o:analysis" mode="o:reduce-analysis">
+ <!-- start by combining the contents of all unique refs -->
+ <xsl:variable name="combined">
+ <xsl:for-each select="
+ o:conflict[
+ not( @ref=preceding-sibling::o:conflict/@ref )
+ ]
+ ">
+
+ <xsl:variable name="ref" select="@ref" />
+ <xsl:variable name="dups" select="
+ following-sibling::o:conflict[ @ref=$ref ]
+ " />
+
+ <o:conflict ref="{@ref}">
+ <!-- add relativity nodes -->
+ <xsl:for-each select="$dups|.">
+ <o:relative-to ref="{@relative-to}" />
+ </xsl:for-each>
+
+ <!-- add class deps -->
+ <o:reasons>
+ <xsl:copy-of select="($dups|.)/o:class" />
+ </o:reasons>
+ </o:conflict>
+ </xsl:for-each>
+ </xsl:variable>
+
+ <!-- now, remove duplicates resulting from the above operation -->
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+
+ <xsl:apply-templates select="$combined/o:conflict"
+ mode="o:reduce-analysis" />
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="o:conflict" mode="o:reduce-analysis">
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+
+ <!-- unique relative-to nodes -->
+ <xsl:copy-of select="
+ o:relative-to[
+ not( @ref=preceding-sibling::o:relative-to/@ref )
+ ]
+ " />
+
+ <xsl:apply-templates select="o:reasons" mode="o:reduce-analysis" />
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="o:reasons" mode="o:reduce-analysis">
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+
+ <!-- unique reasons -->
+ <xsl:copy-of select="
+ o:class[
+ not( @ref=preceding-sibling::o:class/@ref )
+ ]
+ " />
+ </xsl:copy>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/preproc/domain.xsl b/src/current/include/preproc/domain.xsl
new file mode 100644
index 0000000..6dc436d
--- /dev/null
+++ b/src/current/include/preproc/domain.xsl
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Compiles domains from typedefs
+
+ The ultime goal is to implement typedefs as macros and move to a generic
+ domain system that is much more powerful.
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+
+ xmlns:preproc="http://www.lovullo.com/rater/preproc"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:c="http://www.lovullo.com/calc">
+
+
+<!--
+ Base typedefs (internal) are declarations only
+
+ TODO: We still want a domain generated.
+-->
+<xsl:template match="lv:typedef[ lv:base-type ]"
+ mode="preproc:mkdomain" priority="9">
+</xsl:template>
+
+
+<!--
+ Union typedefs
+
+ This generates not only the contained typedefs, but also a denormalized
+ domain containing the union of all the subdomain elements. This is
+ intended to improve lookup performance and reduce algorithmic complexity.
+-->
+<xsl:template match="
+ lv:typedef[
+ lv:union
+ ]
+ "
+ mode="preproc:mkdomain" priority="5">
+
+ <!-- generate all contained domains -->
+ <xsl:variable name="subdomains">
+ <xsl:variable name="union-types" select="
+ lv:union/lv:typedef" />
+
+ <!-- if a union is empty, then somebody probably made an oopsie or wrote
+ a defective/deficient template -->
+ <xsl:if test="count( $union-types ) = 0">
+ <xsl:message>
+ <xsl:text>warning: union `</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>' has no subdomains; something is probably wrong</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:apply-templates mode="preproc:mkdomain"
+ select="$union-types" />
+ </xsl:variable>
+
+ <!-- provide a denormalized domain for performance and to reduce
+ algorithmic complexity-->
+ <xsl:call-template name="preproc:mkdomain-union">
+ <xsl:with-param name="name" select="@name" />
+ <xsl:with-param name="subdomains" select="$subdomains" />
+ </xsl:call-template>
+
+ <xsl:copy-of select="$subdomains" />
+</xsl:template>
+
+
+<!--
+ Enumerated typedefs
+-->
+<xsl:template match="
+ lv:typedef[
+ lv:enum
+ ]
+ "
+ mode="preproc:mkdomain" priority="5">
+
+ <lv:domain name="{@name}">
+ <xsl:variable name="items" select="lv:enum/lv:item" />
+
+ <!-- if a typedef is empty, then somebody probably made an oopsie or
+ wrote a defective/deficient template -->
+ <xsl:if test="count( $items ) = 0">
+ <xsl:message>
+ <xsl:text>warning: typedef `</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>' is empty; something is probably wrong</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:apply-templates mode="preproc:mkdomain"
+ select="$items" />
+ </lv:domain>
+</xsl:template>
+
+
+<!--
+ Prohibit mixing explicit and auto-generated values
+
+ For the time being at least.
+-->
+<xsl:template match="
+ lv:typedef[
+ lv:enum/lv:item[ @value ]
+ and lv:enum/lv:item[ not( @value ) ]
+ ]"
+ mode="preproc:mkdomain" priority="2">
+
+ <xsl:message terminate="yes">
+ <xsl:text>error: typedef `</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>' must not contain both @value and non-@value items</xsl:text>
+ </xsl:message>
+</xsl:template>
+
+
+<!--
+ Unsupported typedef
+
+ Well, we know that it is a typedef, but its format is unknown. This
+ wouldn't be surprising, since it is presently very limited.
+-->
+<xsl:template match="lv:typedef"
+ mode="preproc:mkdomain" priority="2">
+
+ <xsl:message terminate="yes">
+ <xsl:text>error: malformed typedef `</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>'</xsl:text>
+ </xsl:message>
+</xsl:template>
+
+
+
+<!--
+ Generate a denormalized domain consisting of the union of its subdomains'
+ elements
+
+ As this is a union, duplicate elements will be removed; the user will not
+ be notified of this fact, as this allows domains to overlap in order to
+ interpret the same data in different manners.
+-->
+<xsl:template name="preproc:mkdomain-union">
+ <xsl:param name="name" />
+ <xsl:param name="subdomains" />
+
+ <xsl:variable name="union">
+ <preproc:elements>
+ <xsl:copy-of select="$subdomains/lv:domain/lv:element" />
+ </preproc:elements>
+ </xsl:variable>
+
+ <!-- remove duplicate values (yes, this will take the first description if
+ there are duplicates; whatever, for now) -->
+ <lv:domain name="{@name}">
+ <xsl:copy-of select="
+ $union/preproc:elements/lv:element[
+ not( @value = preceding-sibling::lv:element/@value )
+ ]" />
+ </lv:domain>
+</xsl:template>
+
+
+<!--
+ Enumerated items without values require calculation
+
+ Note the above validation that ensures that our value generation is
+ sufficient.
+-->
+<xsl:template match="lv:enum/lv:item[ not( @value ) ]"
+ mode="preproc:mkdomain" priority="5">
+
+ <xsl:variable name="augmented">
+ <xsl:copy>
+ <xsl:attribute name="value" select="position()" />
+ </xsl:copy>
+ </xsl:variable>
+
+ <!-- re-process using an augmented item with the value calculated -->
+ <xsl:apply-templates mode="preproc:mkdomain"
+ select="$augmented/lv:item" />
+</xsl:template>
+
+
+<!--
+ Convert typedef item into a domain element
+
+ This is a straightforward rename with sanity checking. Note that the
+ element may have an empty description.
+
+ We do not care about the name, since we use that to generate constants
+ elsewhere.
+-->
+<xsl:template match="lv:item"
+ mode="preproc:mkdomain" priority="4">
+
+ <!-- previous templates should have prevented this, but just in case -->
+ <xsl:if test="not( @value )">
+ <xsl:message terminate="yes">
+ <xsl:text>internal error: preproc:mkdomain on non-value item: </xsl:text>
+ <xsl:copy-of select="." />
+ </xsl:message>
+ </xsl:if>
+
+ <lv:element value="{@value}" desc="{@desc}" />
+</xsl:template>
+
+
+<!--
+ Unexpected node; terminate
+-->
+<xsl:template match="*"
+ mode="preproc:mkdomain" priority="1">
+
+ <xsl:message terminate="yes">
+ <xsl:text>internal error: unknown domain source: </xsl:text>
+ <xsl:copy-of select="." />
+ </xsl:message>
+</xsl:template>
+
+</xsl:stylesheet>
+
diff --git a/src/current/include/preproc/eligclass.xsl b/src/current/include/preproc/eligclass.xsl
new file mode 100644
index 0000000..8e78c09
--- /dev/null
+++ b/src/current/include/preproc/eligclass.xsl
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Package eligibility class generation
+
+ Here, the term "eligibility" means whether the package is eligible to be used
+ in a result set basead on the values of its params within their respective
+ domains and other factors such as the results of terminating classifications
+ and the eligibility of imported packages.
+
+ The goal of the eligibility classification is to create a cascading failure in
+ the event of bad data.
+-->
+
+<xsl:stylesheet version="2.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:c="http://www.lovullo.com/calc">
+
+
+
+<!--
+ Trigger eligibility class generation
+-->
+<xsl:template match="lv:package[ not( @preproc:elig-class-yields ) ]"
+ as="element( lv:package )"
+ priority="5"
+ mode="preproc:expand-elig-class">
+ <xsl:param name="orig-root" as="element( lv:package )" />
+
+ <xsl:variable name="elig-class" as="element( lv:classify )">
+ <xsl:apply-templates select="." mode="preproc:gen-elig-class">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ </xsl:apply-templates>
+ </xsl:variable>
+
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:attribute name="preproc:elig-class"
+ select="$elig-class/@as" />
+
+ <xsl:attribute name="preproc:elig-class-yields"
+ select="$elig-class/@yields" />
+
+ <xsl:sequence select="$elig-class" />
+ <xsl:apply-templates mode="preproc:macros" />
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template match="lv:package" as="element( lv:package )"
+ priority="1"
+ mode="preproc:expand-elig-class">
+
+ <!-- already processed -->
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+
+<!--
+ Generate eligibility classification asserting all data integrity aspects of a
+ package
+
+ The eligibility classification will yield a scalar.
+-->
+<xsl:template match="lv:package" as="element( lv:classify )"
+ mode="preproc:gen-elig-class">
+ <xsl:param name="orig-root" as="element( lv:package )" />
+
+ <xsl:message>[preproc/eligclass] generating eligibility class</xsl:message>
+
+
+ <!-- class-ify name -->
+ <xsl:variable name="as" as="xs:string"
+ select="preproc:gen-elig-class-name( @name )" />
+ <xsl:variable name="yields" as="xs:string"
+ select="preproc:gen-elig-class-yields( @name )" />
+
+
+ <lv:classify as="{$as}" yields="{$yields}"
+ desc="{@name} package is eligible">
+
+ <!-- TODO: this should really be a compile-time value -->
+ <xsl:if test="@keep-elig-class = 'true'">
+ <xsl:attribute name="keep" select="'true'" />
+ </xsl:if>
+
+ <!-- each of our imported packages' elig classes must be truthful -->
+ <xsl:apply-templates mode="preproc:gen-elig-class-matches"
+ select="lv:import">
+
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ </xsl:apply-templates>
+
+ <!-- param values must be within their domain -->
+ <!-- XXX: does not work when param is undefined due to no mapping
+ <xsl:apply-templates mode="preproc:gen-elig-param-class"
+ select="lv:param" />
+ -->
+
+ <!-- terminating classifications must not have matched -->
+ <xsl:apply-templates mode="preproc:gen-elig-term-class"
+ select="preproc:symtable/preproc:sym[ @type='class' ]" />
+ </lv:classify>
+</xsl:template>
+
+
+<!--
+ Generate eligibility classification name for package
+-->
+<xsl:function name="preproc:gen-elig-class-name"
+ as="xs:string">
+ <xsl:param name="name" />
+
+ <xsl:sequence select="
+ concat( '--elig-',
+ translate(
+ translate( $name, '.', '' ),
+ '/', '-'
+ )
+ )
+ " />
+</xsl:function>
+
+
+<!--
+ Generate eligibility result scalar name for package
+-->
+<xsl:function name="preproc:gen-elig-class-yields"
+ as="xs:string">
+ <xsl:param name="name" />
+
+ <xsl:sequence select="
+ concat(
+ 'isElig',
+ translate(
+ translate( $name, '.', '' ),
+ '/-', '' ) )" />
+</xsl:function>
+
+
+<!--
+ Generate matches on eligibility of imported packages
+
+ For each imported package, its eligibility classification must be true.
+-->
+<xsl:template match="lv:import[ @package ]"
+ as="element( lv:match )?"
+ priority="5"
+ mode="preproc:gen-elig-class-matches">
+ <xsl:param name="orig-root" as="element( lv:package )" />
+
+ <!-- FIXME: path may not yet be resolved due to preprocessing order -->
+ <xsl:variable name="pkg-path" as="xs:string">
+ <xsl:call-template name="__apply-relroot">
+ <xsl:with-param name="path" select="@package" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="pkg" as="element( lv:package )"
+ select="document( concat( $pkg-path, '.xmlo' ),
+ $__entry-root )
+ /lv:package" />
+
+ <xsl:if test="not( $pkg )">
+ <xsl:message terminate="yes">
+ <xsl:text>[preproc/eligclass] error: could not load `</xsl:text>
+ <xsl:value-of select="$pkg-path" />
+ <xsl:text>' object file</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:variable name="chk" as="xs:string?"
+ select="$pkg/@preproc:elig-class-yields" />
+
+ <xsl:choose>
+ <xsl:when test="not( $chk ) or ( $chk = '' )">
+ <!-- TODO: make this an error once we make maps part of the
+ conventional build process -->
+ <xsl:message>
+ <xsl:text>[preproc/eligclass] internal: empty eligibility </xsl:text>
+ <xsl:text>class for `</xsl:text>
+ <xsl:value-of select="$pkg/@name" />
+ <xsl:text>'; skipping</xsl:text>
+ </xsl:message>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <!-- use eligibility class as stated by the package -->
+ <lv:match on="{$chk}" value="TRUE" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template match="lv:import" priority="1"
+ mode="preproc:gen-elig-class-matches">
+
+ <!-- do nothing -->
+</xsl:template>
+
+
+<!--
+ Param values must be within their domain
+
+ This is a trivial operation.
+-->
+<xsl:template match="lv:param"
+ as="element( lv:any )"
+ mode="preproc:gen-elig-param-class" priority="5">
+
+ <lv:any>
+ <lv:match on="{@name}" anyOf="{@type}" />
+
+ <!-- TODO: defaults should always be within the domain! -->
+ <xsl:if test="@default">
+ <lv:match on="{@name}" anyOf="empty" />
+ </xsl:if>
+ </lv:any>
+</xsl:template>
+
+
+
+<!--
+ Terminating classification dependencies
+
+ All terminiating classifications defined in the package must yield false
+ for the package to be eligible.
+
+ N.B. This checks to ensure @extclass is not set; this prevents errors when
+ the eligibility classification attempts to pull in a terminating
+ classification marked as external to the classifier. There may or may not
+ be something we want to do about this in the future.
+-->
+<xsl:template match="preproc:sym[
+ not( @src )
+ and not( @pollute='true' )
+ and @type='class'
+ and @terminate='true'
+ and not( @extclass='true' )
+ ]"
+ as="element( lv:match )"
+ priority="5"
+ mode="preproc:gen-elig-term-class">
+
+ <lv:match on="{@yields}" value="FALSE" />
+</xsl:template>
+
+
+<xsl:template match="preproc:sym" priority="1"
+ mode="preproc:gen-elig-term-class">
+
+ <!-- do nothing -->
+</xsl:template>
+
+</xsl:stylesheet>
+
diff --git a/src/current/include/preproc/expand.xsl b/src/current/include/preproc/expand.xsl
new file mode 100644
index 0000000..57c6856
--- /dev/null
+++ b/src/current/include/preproc/expand.xsl
@@ -0,0 +1,691 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Handles node expansion
+
+ This process is responsible for expanding shorthand and various other data
+ into a consistent format for the compiler and other processes.
+-->
+
+<xsl:stylesheet
+ version="2.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:t="http://www.lovullo.com/rater/apply-template"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:w="http://www.lovullo.com/rater/worksheet">
+
+
+<xsl:include href="domain.xsl" />
+
+
+<xsl:template match="lv:package[ not( @preproc:name ) ]"
+ mode="preproc:expand" priority="5"
+ as="element( lv:package )">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <!-- generate name from source package identifier -->
+ <xsl:attribute name="name" select="$__srcpkg" />
+
+ <!-- relative path to root src directory (for resolving absolute include
+ paths) -->
+ <xsl:attribute name="__rootpath" select="$__relroot" />
+
+ <!-- TODO: temporary; remove -->
+ <xsl:attribute name="preproc:name" select="$__srcpkg" />
+
+ <xsl:apply-templates mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+
+
+<xsl:template match="*" mode="preproc:expand" priority="1">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:apply-templates mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+
+<!-- imports relative to project root -->
+<xsl:template match="lv:import[ starts-with( @package, '/' ) ]" mode="preproc:expand" priority="5">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <!-- resolve path into path relative to project root -->
+ <xsl:attribute name="package">
+ <xsl:call-template name="__apply-relroot">
+ <xsl:with-param name="path" select="@package" />
+ </xsl:call-template>
+ </xsl:attribute>
+ </xsl:copy>
+</xsl:template>
+
+
+<!--
+ Domain data are extracted from typedefs
+
+ Eventually, the typedefs will be converted into templates and removed entirely.
+-->
+<xsl:template match="lv:typedef"
+ mode="preproc:expand" priority="5">
+
+ <xsl:apply-templates select="." mode="preproc:mkdomain" />
+
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+ <xsl:apply-templates mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+
+<!--
+ Infer primitive type if not provided.
+-->
+<xsl:template mode="preproc:expand"
+ match="c:const[ not( @type ) ]
+ |lv:const[ not( @type ) ]"
+ priority="5">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:attribute name="type"
+ select="if ( substring-before( @value, '.' ) ) then
+ 'float'
+ else
+ 'integer'" />
+
+ <xsl:sequence select="*" />
+ </xsl:copy>
+</xsl:template>
+
+
+<!--
+ Give let's a name so that they may be easily referenced uniquely
+-->
+<xsl:template match="c:let[ not( @name ) ]" mode="preproc:expand" priority="5">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+ <xsl:attribute name="name" select="generate-id(.)" />
+
+ <xsl:apply-templates select="*" mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+
+<!--
+ Default label of c:let value expressions to description if no label is provided
+
+ This is useful for breakdown display.
+
+ TODO: play well with others; if we change the priority back to 5, we introduce
+ match ambiguities
+-->
+<xsl:template match="c:let/c:values/c:value/c:*[1][ not( @label ) ]" mode="preproc:expand" priority="4">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <!-- default the label to the description of the parent c:value -->
+ <xsl:attribute name="label" select="../@desc" />
+
+ <xsl:apply-templates select="*" mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+
+<!--
+ c:when with no children is shorthand for > 0
+
+ Note: we check for any children because we may have things like
+ template applications that we do not want wiped out.
+-->
+<xsl:template match="c:when[ not( * ) ]" mode="preproc:expand" priority="5">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <c:gt>
+ <c:value-of name="FALSE" />
+ </c:gt>
+ </xsl:copy>
+</xsl:template>
+
+
+<!--
+ c:when with multiple children
+-->
+<xsl:template match="c:when[ count( c:* ) gt 1 ]" mode="preproc:expand" priority="5">
+ <xsl:variable name="when" select="." />
+
+ <!-- expand into adjacent c:when's -->
+ <xsl:for-each select="c:*">
+ <c:when>
+ <xsl:sequence select="$when/@*" />
+ <xsl:apply-templates select="." mode="preproc:expand" />
+ </c:when>
+ </xsl:for-each>
+</xsl:template>
+
+
+<!--
+ Recursion shorthand
+
+ This exists simply because function application is so verbose and, when
+ recursing, generally only a small fraction of the arguments actually change.
+-->
+<xsl:template match="c:recurse" mode="preproc:expand" priority="5">
+ <xsl:variable name="self" select="." />
+ <xsl:variable name="fname" select="ancestor::lv:function/@name" />
+ <xsl:variable name="overrides" select="./c:arg" />
+
+ <c:apply name="{$fname}">
+ <!-- every non-@name attribute should be converted into an argument -->
+ <xsl:call-template name="preproc:arg-short-expand" />
+
+ <!-- include all non-overridden args -->
+ <xsl:for-each select="
+ ancestor::lv:function/lv:param[
+ not(
+ @name=$overrides/@name
+ or @name=$self/@*/local-name()
+ )
+ ]
+ ">
+
+ <!-- copy the arg value -->
+ <c:arg name="{@name}">
+ <c:value-of name="{@name}" />
+ </c:arg>
+ </xsl:for-each>
+
+ <!-- copy in the overrides -->
+ <xsl:apply-templates select="$overrides" mode="preproc:expand" />
+ </c:apply>
+</xsl:template>
+
+
+<!-- metadata constants have different semantics -->
+<!-- TODO: maybe ignore single-quoted? -->
+<xsl:template mode="preproc:expand" priority="6"
+ match="lv:meta/lv:prop/lv:const">
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+<!-- constants that contain 'e' (scientific notation) should be expanded; allows
+ for avoiding constants with many zeroes, which is hard to read -->
+<xsl:template mode="preproc:expand" priority="5"
+ match="c:const[ substring-before( @value, 'e' ) ]
+ |lv:const[ substring-before( @value, 'e' ) ]">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:attribute name="value">
+ <xsl:call-template name="preproc:expand-e">
+ <xsl:with-param name="number" select="@value" />
+ </xsl:call-template>
+ </xsl:attribute>
+
+ <xsl:apply-templates mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template mode="preproc:expand" priority="5"
+ match="c:const[ substring-before( @value, 'm' ) ]
+ |lv:const[ substring-before( @value, 'm' ) ]">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:attribute name="value">
+ <xsl:call-template name="preproc:expand-e">
+ <xsl:with-param name="number"
+ select="concat( substring-before( @value, 'm' ), 'e6' )" />
+ </xsl:call-template>
+ </xsl:attribute>
+
+ <xsl:apply-templates mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template mode="preproc:expand" priority="5"
+ match="c:const[ substring-before( @value, 'k' ) ]
+ |lv:const[ substring-before( @value, 'k' ) ]">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:attribute name="value">
+ <xsl:call-template name="preproc:expand-e">
+ <xsl:with-param name="number"
+ select="concat( substring-before( @value, 'k' ), 'e3' )" />
+ </xsl:call-template>
+ </xsl:attribute>
+
+ <xsl:apply-templates mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+
+<!-- expand scientific notation -->
+<!-- XXX: negatives not currently supported -->
+<xsl:template name="preproc:expand-e">
+ <xsl:param name="number" />
+ <xsl:param name="whole" select="substring-before( $number, '.' )" />
+ <xsl:param name="dec" select="substring-before( substring-after( $number, '.' ), 'e' )" />
+ <xsl:param name="count" as="xs:double"
+ select="number( substring-after( $number, 'e' ) )" />
+
+ <!-- output the whole number portion -->
+ <xsl:choose>
+ <xsl:when test="$whole and not( $whole = '' )">
+ <xsl:value-of select="$whole" />
+ </xsl:when>
+
+ <!-- if no decimal was provided, then use the entire number before 'e' -->
+ <xsl:when test="$number and not( $number = '' ) and ( $whole = '' )">
+ <xsl:value-of select="substring-before( $number, 'e' )" />
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="$count > 0">
+ <xsl:choose>
+ <!-- if we have a decimal, then use the first digit (as if we moved one
+ place to the right) -->
+ <xsl:when test="$dec and not( $dec = '' )">
+ <xsl:value-of select="substring( $dec, 1, 1 )" />
+ </xsl:when>
+
+ <!-- no decimal portion remaining; fill with 0 -->
+ <xsl:otherwise>
+ <xsl:text>0</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <!-- recursively expand -->
+ <xsl:call-template name="preproc:expand-e">
+ <!-- already processed the whole -->
+ <xsl:with-param name="whole" select="''" />
+
+ <xsl:with-param name="dec">
+ <!-- move to the right one decimal place; otherwise, no decimal -->
+ <xsl:if test="$dec">
+ <xsl:value-of select="substring( $dec, 2 )" />
+ </xsl:if>
+ </xsl:with-param>
+
+ <xsl:with-param name="count" select="$count - 1" />
+ </xsl:call-template>
+ </xsl:when>
+
+ <!-- output the remaining decimal, if any -->
+ <xsl:otherwise>
+ <xsl:if test="$dec and not( $dec = '' )">
+ <xsl:text>.</xsl:text>
+ <xsl:value-of select="$dec" />
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!--
+ Optimize away c:cases if they contain only c:otherwise
+
+ This is useful primarily for templates that may create a case statement for
+ conditional operations (using lv:if/lv:unless) and ensures that there is no
+ penalty for doing so if none of the template conditions result in a c:case.
+
+ Note that we should *not* perform these optimizations if there are templates
+ awaiting application or any other lv:* nodes that have not been expanded.
+-->
+<xsl:template mode="preproc:expand" priority="5" match="
+ c:cases[
+ not( lv:* or t:* )
+ and c:otherwise[
+ not( preceding-sibling::c:* or following-sibling::c:* )
+ ]
+ ]
+ ">
+
+ <!-- just replace with the content of the otherwise block (do not explicitly
+ process c:*, since there may be templates) -->
+ <xsl:apply-templates select="c:otherwise/*" mode="preproc:expand" />
+</xsl:template>
+
+
+<!--
+ Optimize away c:sum/c:product blocks that contain one or zero elements, so
+ long as they do not contain a generator (since that would remove a ref) or @of
+ (since that will actually loop through multiple).
+
+ Note that we should *not* perform these optimizations if there are templates
+ awaiting application or any other lv:* nodes that have not been expanded.
+-->
+<xsl:template match="c:sum[ lv:* or t:* ]|c:product[ lv:* or t:* ]" mode="preproc:expand" priority="7">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+ <xsl:apply-templates mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="c:sum[ not( @of or @generates ) and count( c:* ) &lt; 2 ]" mode="preproc:expand" priority="5">
+ <xsl:apply-templates select="c:*" mode="preproc:expand" />
+</xsl:template>
+<xsl:template match="c:product[ not( @of or @generates ) and count( c:* ) &lt; 2 ]" mode="preproc:expand" priority="5">
+ <xsl:apply-templates select="c:*" mode="preproc:expand" />
+</xsl:template>
+
+
+<!-- TODO: We could add shorthand for indexes too, e.g. name[i] or name[0] -->
+<xsl:template match="
+ c:apply[
+ @*[
+ not(
+ local-name() = 'name'
+ or local-name() = 'label'
+ )
+ ]
+ ]
+ "
+ mode="preproc:expand" priority="5">
+
+ <xsl:copy>
+ <!-- keep the name attribute, which specifies what function to apply -->
+ <xsl:sequence select="@name, @label" />
+
+ <!-- every other attribute should be converted into an argument -->
+ <xsl:call-template name="preproc:arg-short-expand" />
+
+ <xsl:apply-templates select="c:arg" mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template name="preproc:arg-short-expand">
+ <xsl:for-each select="@*[
+ not(
+ local-name() = 'name'
+ or local-name() = 'label'
+ )
+ ]">
+
+ <c:arg name="{local-name()}">
+ <c:value-of name="{.}" />
+ </c:arg>
+ </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template match="lv:rate[ lv:class ]|lv:function[ lv:class ]|lv:yield[ lv:class ]"
+ mode="preproc:expand" priority="9">
+ <!-- already processed -->
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+ <xsl:apply-templates mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+<!--
+ Add lv:class nodes containing the values of each individual class
+
+ This eliminates the need to tokenize later and drastically simplifies xpath
+ queries.
+-->
+<xsl:template match="lv:rate|lv:function|lv:yield" mode="preproc:expand" priority="5">
+ <xsl:variable name="self" select="." />
+
+ <xsl:variable name="classes" select="tokenize( @class, ' ' )" />
+ <xsl:variable name="no-classes" select="tokenize( @no, ' ' )" />
+
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <!-- convert classes into nodes to make life easier down the road (if any) -->
+ <xsl:for-each select="$classes">
+ <xsl:if test=".">
+ <lv:class ref="{.}" no="false" />
+ </xsl:if>
+ </xsl:for-each>
+
+ <xsl:for-each select="$no-classes">
+ <xsl:if test=".">
+ <lv:class ref="{.}" no="true" />
+ </xsl:if>
+ </xsl:for-each>
+
+ <xsl:apply-templates mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+
+
+<!--
+ To make life a bit easier, calculate the set type of a classification @yields
+ and add it to the node as a @set attribute
+-->
+<xsl:template match="lv:classify" mode="preproc:expand" priority="5">
+ <xsl:variable name="self" select="." />
+
+ <xsl:copy>
+ <!-- we just want to add an attribute that allows easy referencing of this
+ @yields set type, which will be a matrix if any matches match on a
+ matrix of values, otherwise it will be a vector -->
+ <xsl:attribute name="set">
+ <xsl:variable name="params"
+ select="root(.)//lv:param[ @name=$self//lv:match/@on ]" />
+
+ <xsl:choose>
+ <!-- XXX: This does not work properly with classes depending on other
+ classes -->
+ <xsl:when test="$params/@set = 'matrix'">
+ <xsl:text>matrix</xsl:text>
+ </xsl:when>
+
+ <!-- XXX: remove this when the above is fixed...note also that we have
+ to check for lv:join since it hasn't necessarily been preprocessed
+ yet...what a mess. Also note that, since templates and other things
+ may not have been expanded, we also fail this test if the
+ classification does not match on either a param or another
+ classification (since then things will get more complicated)-->
+ <xsl:when test="
+ not(
+ $self//lv:match
+ or $self//lv:join
+ )
+ or (
+ not( $params/@set )
+ and not(
+ .//lv:match[ @on=root(.)/lv:classify/@yields ]
+ )
+ and not( .//lv:join )
+ and (
+ $params
+ or .//lv:match[ @on=root(.)/lv:classify ]
+ )
+ )
+ ">
+ <!-- output nothing; it's just a scalar -->
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text>vector</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+
+ <!-- if there is no @yields attribute, then generate one -->
+ <xsl:if test="not( @yields )">
+ <xsl:attribute name="yields">
+ <xsl:text>__is</xsl:text>
+ <!-- certain characters are not valid for @yields -->
+ <xsl:value-of select="translate( @as, '-', '' )" />
+ </xsl:attribute>
+ </xsl:if>
+
+ <xsl:sequence select="@*" />
+
+ <!-- force @keep on @terminate -->
+ <xsl:if test="@terminate='true'">
+ <xsl:attribute name="keep" select="'true'" />
+ </xsl:if>
+
+ <!-- copy everything else -->
+ <xsl:apply-templates mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+
+<!-- default lv:match/@on short-hand to assert on a value of TRUE -->
+<xsl:template match="lv:match[ not( @value
+ or @anyOf
+ or @pattern
+ or * ) ]"
+ mode="preproc:expand" priority="7">
+
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+ <xsl:attribute name="value"
+ select="'TRUE'" />
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template mode="preproc:expand"
+ match="lv:join[ @all='true' ]"
+ priority="8">
+ <xsl:call-template name="preproc:mk-class-join-contents" />
+</xsl:template>
+
+
+<xsl:template mode="preproc:expand"
+ match="lv:join"
+ priority="7">
+ <lv:any>
+ <xsl:call-template name="preproc:mk-class-join-contents" />
+ </lv:any>
+</xsl:template>
+
+
+<xsl:template name="preproc:mk-class-join-contents">
+ <xsl:variable name="prefix" select="@prefix" />
+
+ <!-- TODO: remove lv:template nodes in a pass before this so that this
+ check is not necessary -->
+ <xsl:for-each select="root(.)/lv:classify[
+ starts-with( @as, $prefix )
+ and not( ancestor::lv:template )
+ ]">
+ <lv:match value="TRUE">
+ <xsl:attribute name="on">
+ <xsl:choose>
+ <xsl:when test="@yields">
+ <xsl:value-of select="@yields" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text>__is</xsl:text>
+ <xsl:value-of select="@as" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ </lv:match>
+ </xsl:for-each>
+</xsl:template>
+
+
+<!-- enums have implicit values (as they are, well, enumerated; @value overrides) -->
+<!-- TODO: should @value set the next implicit index? -->
+<xsl:template match="lv:item[ not( @value ) ]" mode="preproc:expand" priority="5">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+ <xsl:attribute name="value" select="count( preceding-sibling::* )" />
+ <xsl:apply-templates mode="preproc:expand" />
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template match="w:display[ @prefix ]" mode="preproc:expand" priority="5">
+ <xsl:variable name="prefix" select="@prefix" />
+ <xsl:variable name="children" select="w:*" />
+
+ <xsl:for-each select="root(.)//lv:rate[ starts-with( @yields, $prefix ) ]">
+ <w:display name="{@yields}">
+ <xsl:sequence select="$children" />
+ </w:display>
+ </xsl:for-each>
+</xsl:template>
+
+
+<!-- remove templates that have been copied from an external source for
+ processing -->
+<xsl:template match="lv:template[
+ @name=root()
+ /preproc:symtable/preproc:sym[ @src ]/@name ]"
+ mode="preproc:expand" priority="5">
+</xsl:template>
+
+<!-- IMPORTANT: do not process unexpanded templates -->
+<xsl:template match="lv:template" mode="preproc:expand" priority="4">
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+<xsl:template match="preproc:symtable" mode="preproc:expand" priority="5">
+ <!-- ignore -->
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+<xsl:template match="lv:__external-data" mode="preproc:expand" priority="5">
+ <!-- intended for use by code generators; data is not retained in object file
+ unless some other process overrides this template -->
+</xsl:template>
+
+</xsl:stylesheet>
+
+<!--
+Footnotes
+
+What!? We need footnotes for this project!?
+
+[0] This was a complicated issue to begin dealing with due to the information we
+ need and the information that is available. In particular, at this point, we
+ would like to exclude any non-external objects from appearing in the
+ rate-only output, but we cannot do that, since the preprocessor has not yet
+ reached that block! We cannot reorder, because the class order block depends
+ on the rate block!
+
+ (See the commit that introduced this footnote: In the past, the template at
+ this position passed an `external-only' flag to the template.)
+
+ Originally, the method was to ``guess'' based on the how the system was
+ currently being used (dangerous, but was meant to be temporary...though we
+ know how that goes...): implicit externals were ignored, meaning it may not
+ function as we would like. Now, this could be resolved in the short-term by
+ actually addinging explicit external attributes to everything that needed it
+ so that this code would run smoothly. Worked great! Well, so I had thought.
+
+ Then it came down to a certain classification that used the `frame'
+ classification. This classification was only used by an external
+ classification in scottsdale, but other companies used it for rating, so the
+ @external classifier was inappropriate. Of course, the system could easily
+ figure out if it was to be marked as external or not (it already does), but
+ we do not yet have access to that information. Therefore, what ended up
+ happening, was the frame classification was excluded from the classifier,
+ excluded from one of the iterations that this footnote references (because
+ it was not explicitly external) and included elsewhere where we didn't care
+ if it was external or not. When the dependency tree was flattened to
+ determine compilation order, the classification that uses `frame' was
+ compiled *before* the `frame' classification itself, due to that exclusion!
+ Since `frame' was excluded from the classifier, therefore, it was always
+ false! That is the situation I was trying to avoid with the explicit
+ @external attributes, but here, that solution would not work.
+
+ Therefore, checking for external-only here will not work; we must output
+ everything and work on post-processing the data once everything is said and
+ done, to remove the duplicates that are also present in the classifier.
+-->
diff --git a/src/current/include/preproc/macros.xsl b/src/current/include/preproc/macros.xsl
new file mode 100644
index 0000000..4c4f8e6
--- /dev/null
+++ b/src/current/include/preproc/macros.xsl
@@ -0,0 +1,456 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Handles macro preprocessing
+-->
+
+<xsl:stylesheet version="2.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:t="http://www.lovullo.com/rater/apply-template"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:ext="http://www.lovullo.com/ext">
+
+
+<xsl:include href="template.xsl" />
+<xsl:include href="eligclass.xsl" />
+
+
+<!--
+ Perform a macro expansion pass
+
+ This will continue to recurse until no preproc:repass nodes are found; this
+ allos macros to expand into macros for further processing.
+-->
+<xsl:template match="*" mode="preproc:macropass" priority="1"
+ as="node()+">
+ <xsl:variable name="result" as="node()+">
+ <xsl:apply-templates select="." mode="preproc:macros" />
+ </xsl:variable>
+
+ <xsl:variable name="nodeset" select="$result" />
+
+ <xsl:variable name="repass"
+ select="$nodeset//preproc:repass" />
+
+ <!-- halt if we are in error -->
+ <xsl:for-each select="$nodeset//preproc:error">
+ <xsl:message terminate="yes">
+ <xsl:text>!!! [preproc] error: </xsl:text>
+ <xsl:value-of select="." />
+ </xsl:message>
+ </xsl:for-each>
+
+ <xsl:choose>
+ <!-- if it was indicated that we must do so, recurse -->
+ <xsl:when test="$repass and not( $repass[ @need-sym ] )">
+
+ <!-- record the repass to keep a count -->
+ <!-- TODO: reintroduce
+ <preproc:repass-record />
+ -->
+
+ <xsl:message>[preproc] *REPASS*</xsl:message>
+
+ <!-- perform the repass -->
+ <xsl:apply-templates select="$nodeset" mode="preproc:macropass">
+ <xsl:with-param name="clear-tpl-step"
+ tunnel="yes"
+ select="false()" />
+ </xsl:apply-templates>
+ </xsl:when>
+
+ <!-- no more passes needed; macro expansion complete -->
+ <xsl:otherwise>
+ <xsl:sequence select="$nodeset" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template match="*" mode="preproc:macros" priority="1">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:apply-templates mode="preproc:macros" />
+ </xsl:copy>
+</xsl:template>
+
+
+<!--
+ Remove repass nodes left over from the previous pass
+
+ Otherwise, we would recurse indefinately.
+-->
+<xsl:template match="preproc:repass" mode="preproc:macros" priority="5">
+ <!-- remove; no longer needed -->
+</xsl:template>
+
+
+<xsl:template match="preproc:tpl-step" mode="preproc:macros" priority="5">
+ <xsl:param name="clear-tpl-step"
+ tunnel="yes"
+ select="true()" />
+
+ <xsl:choose>
+ <xsl:when test="$clear-tpl-step">
+ <!-- strip -->
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:copy-of select="." />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!--
+ lv:rater is just a special type of package
+-->
+<xsl:template match="lv:rater" mode="preproc:macros" priority="9">
+ <lv:package program="true">
+ <xsl:sequence select="@*, *" />
+ </lv:package>
+
+ <preproc:repass src="lv:rater" />
+</xsl:template>
+
+
+
+<!--
+ FOR PERFORMANCE ONLY:
+
+ These nodes (usually) contain nothing that can be processed on the macro pass,
+ so recursion is unnecessary; note the low priority.
+-->
+<xsl:template match="lv:typedef"
+ mode="preproc:macros" priority="2">
+
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+<!--
+ Expand values beginning with `#' into constants
+
+ It is a nuisance to have separate params (e.g. templates) for constants
+ and values.
+-->
+<xsl:template mode="preproc:macros"
+ match="c:value-of[ starts-with( @name, '#' ) ]"
+ priority="7">
+ <c:const value="{substring-after( @name, '#' )}"
+ type="float"
+ desc="Generated short-hand constant" />
+</xsl:template>
+
+
+<!--
+ Expand index values beginning with `#' into constants
+
+ It is a nuisance to have separate params (e.g. templates) for constants
+ and values.
+-->
+<xsl:template mode="preproc:macros"
+ match="c:value-of[ starts-with( @index, '#' ) ]"
+ priority="7">
+ <xsl:copy>
+ <xsl:copy-of select="@*[ not( name() = 'index' ) ]" />
+
+ <c:index>
+ <c:const value="{substring-after( @index, '#' )}"
+ type="float"
+ desc="Generated short-hand constant" />
+ </c:index>
+ </xsl:copy>
+</xsl:template>
+
+
+<!--
+ It does not make sense to try to take an index of a scalar
+-->
+<xsl:template mode="preproc:macros"
+ match="c:value-of[
+ @index
+ and starts-with( @name, '#' ) ]"
+ priority="9">
+ <preproc:error>
+ <xsl:text>Cannot take index of scalar value: </xsl:text>
+ <xsl:value-of select="@name" />
+ </preproc:error>
+</xsl:template>
+
+
+<!--
+ Classifications containing only an lv:any child node can be converted into
+ existential classifications
+-->
+<xsl:template match="lv:classify[ lv:any and count(*) = 1 ]" mode="preproc:macros" priority="8">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+ <xsl:attribute name="any" select="'true'" />
+
+ <xsl:sequence select="lv:any/*" />
+ </xsl:copy>
+
+ <preproc:repass src="lv:classify any" />
+</xsl:template>
+
+
+<xsl:template match="lv:classify[ .//lv:any|.//lv:all ]" mode="preproc:macros" priority="6">
+ <xsl:variable name="result">
+ <xsl:apply-templates select="." mode="preproc:class-groupgen" />
+ </xsl:variable>
+
+ <xsl:apply-templates select="$result/lv:classify" mode="preproc:class-extract" />
+
+ <preproc:repass src="lv:classify any|all" />
+</xsl:template>
+
+
+<xsl:template match="lv:classify" mode="preproc:class-groupgen" priority="5">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+ <xsl:apply-templates mode="preproc:class-groupgen" />
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template mode="preproc:class-groupgen" priority="9"
+ match="lv:any[ not( element() ) ]
+ |lv:all[ not( element() ) ]">
+ <!-- useless; remove -->
+</xsl:template>
+
+
+<xsl:template match="lv:any|lv:all" mode="preproc:class-groupgen" priority="5">
+ <!-- this needs to be unique enough that there is unlikely to be a conflict
+ between generated ids in various packages; generate-id is not enough for
+ cross-package guarantees (indeed, I did witness conflicts), so there is
+ a random seed passed into the stylesheet externally -->
+ <xsl:variable name="id" select="concat( $__rseed, generate-id(.) )" />
+
+ <xsl:variable name="parent-name" select="ancestor::lv:classify/@as" />
+ <xsl:variable name="yields" select="concat( 'is', $id )" />
+
+ <xsl:variable name="external" as="xs:string?"
+ select="ancestor::lv:classify/@external" />
+
+ <!-- this will be raised outside of the parent classification during
+ post-processing -->
+ <lv:classify as="{$id}" yields="{$yields}"
+ preproc:generated="true"
+ preproc:generated-from="{$parent-name}"
+ external="{$external}"
+ desc="(generated from predicate group of {$parent-name}">
+ <xsl:if test="local-name() = 'any'">
+ <xsl:attribute name="any" select="'true'" />
+ </xsl:if>
+
+ <xsl:apply-templates mode="preproc:class-groupgen" />
+ </lv:classify>
+
+ <!-- this will remain in its place -->
+ <lv:match on="{$yields}" value="TRUE" preproc:generated="true" />
+</xsl:template>
+
+
+<!-- retain everything else -->
+<xsl:template match="*" mode="preproc:class-groupgen" priority="1">
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+<xsl:template match="lv:classify" mode="preproc:class-extract" priority="5">
+ <xsl:apply-templates select="lv:classify" mode="preproc:class-extract" />
+
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+ <xsl:apply-templates mode="preproc:class-filter" />
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template match="*" mode="preproc:class-extract" priority="1">
+ <!-- ignore non-class -->
+</xsl:template>
+
+
+<xsl:template match="lv:classify" mode="preproc:class-filter" priority="5">
+ <!-- remove -->
+</xsl:template>
+
+
+<xsl:template match="*" mode="preproc:class-filter" priority="1">
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+<!--
+ Sections exist purely for organization and documentation. Move all
+ nodes out of it, so that we do not complicate parsing.
+-->
+<xsl:template mode="preproc:macros" priority="2"
+ match="lv:section">
+ <xsl:apply-templates select="*" mode="preproc:macros" />
+</xsl:template>
+
+
+<!--
+ lv:yield is simply another rate block with a special name that is recognized
+ by the linker
+-->
+<xsl:template match="lv:yield" mode="preproc:macros" priority="5">
+ <lv:rate yields="___yield" local="true">
+ <xsl:apply-templates mode="preproc:macros" />
+ </lv:rate>
+</xsl:template>
+
+
+<!-- this situation may occur both manually and from lv:rate-each-template -->
+<xsl:template match="lv:rate-each[ lv:apply-template ]" mode="preproc:macros" priority="9">
+ <xsl:variable name="apply">
+ <preproc:apply>
+ <xsl:apply-templates select="lv:apply-template" mode="preproc:macros" />
+ </preproc:apply>
+ </xsl:variable>
+
+ <xsl:choose>
+ <!-- did the template apply? (note that we only check for a single one,
+ since that's all that we should have) -->
+ <xsl:when test="$apply/preproc:apply/lv:apply-template">
+ <xsl:sequence select="." />
+
+ <xsl:message>
+ <xsl:text>[preproc] waiting to expand rate-each </xsl:text>
+ <xsl:value-of select="@yields" />
+ <xsl:text> (immediate template(s) need expansion)...</xsl:text>
+ </xsl:message>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <!-- it applied! -->
+ <xsl:copy>
+ <xsl:sequence select="@*, *[ not( local-name()='apply-template' ) ]" />
+ <xsl:sequence select="$apply/preproc:apply/*" />
+ </xsl:copy>
+
+ <!-- we'll process this block next time around -->
+ <preproc:repass src="lv:rate-each lv:apply-template" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!--
+ Convenience macro that expands to a lv:rate block summing over the magic
+ _CMATCH_ set with the product of its value
+
+ The intent here is to reduce highly repetitive code.
+-->
+<xsl:template match="lv:rate-each" mode="preproc:macros" priority="5">
+ <!-- TODO: debug flag
+ <xsl:message>
+ <xsl:text>[preproc] expanding rate-each </xsl:text>
+ <xsl:value-of select="@yields" />
+ <xsl:text>...</xsl:text>
+ </xsl:message>
+ -->
+
+ <lv:rate>
+ <xsl:sequence select="@*[
+ not( local-name() = 'index' )
+ and not( local-name() = 'generates' )
+ ]" />
+
+ <xsl:if test="not( @yields )">
+ <!-- if @generates is not supplied either, then we cannot continue -->
+ <xsl:choose>
+ <xsl:when test="not( @generates )">
+ <!-- TODO: some means of identifying this...the error isn't terribly
+ helpful... :x -->
+ <preproc:error>
+ <xsl:text>rate-each must provide either @yields or @generates</xsl:text>
+ </preproc:error>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:attribute name="yields"
+ select="concat( '_', @generates )" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:sequence select="./lv:class" />
+
+ <c:sum of="_CMATCH_" index="{@index}" sym="{@gensym}">
+ <!-- copy @generates, if it exists (has the benefit of copying nothing
+ if it does not exist) -->
+ <xsl:sequence select="@generates" />
+
+ <xsl:attribute name="desc">
+ <xsl:text>Set of individual </xsl:text>
+ <xsl:value-of select="@yields" />
+ <xsl:text> premiums</xsl:text>
+ </xsl:attribute>
+
+ <c:product>
+ <c:value-of name="_CMATCH_" index="{@index}">
+ <xsl:attribute name="label">
+ <xsl:text>Zero if not </xsl:text>
+ <xsl:value-of select="@class" />
+ <xsl:text>, otherwise one</xsl:text>
+ </xsl:attribute>
+ </c:value-of>
+
+ <xsl:apply-templates
+ select="*[
+ not(
+ local-name() = 'class'
+ )
+ ]"
+ mode="preproc:macros" />
+ </c:product>
+ </c:sum>
+ </lv:rate>
+</xsl:template>
+
+
+<!--
+ Generates a classifier for each boolean param
+
+ This is for convenience; a boolean can esssentially be considered its own
+ classifier, so let's generate one to cut down on the amount of code.
+
+ Technically not a macro, but needs to be done before preproc:expand.
+
+ XXX: Get rid of me! Now unused!
+-->
+<xsl:template match="lv:params[ not( @preproc:processed ) ]"
+ mode="preproc:macros" priority="5">
+
+ <xsl:copy>
+ <xsl:attribute name="preproc:processed" select="'true'" />
+ <xsl:sequence select="@*" />
+
+ <xsl:apply-templates mode="preproc:macros" />
+ </xsl:copy>
+
+ <xsl:for-each select="lv:param[ @type='boolean' ]">
+ <xsl:variable name="as" select="translate( @name, '_', '-' )" />
+ <xsl:variable name="genas" select="concat( 'is-', $as )" />
+
+ <!-- ensure that this name does not already exist -->
+ <xsl:if test="not( /lv:*/lv:classify[ @as=$genas ] )">
+ <!-- TODO: We're flagging as @keep for now due to gclass needs, but this
+ should be removed later -->
+ <lv:classify as="{$genas}" desc="{@desc}" keep="true">
+ <lv:match on="{@name}" value="TRUE" />
+ </lv:classify>
+ </xsl:if>
+ </xsl:for-each>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/preproc/package.xsl b/src/current/include/preproc/package.xsl
new file mode 100644
index 0000000..48536af
--- /dev/null
+++ b/src/current/include/preproc/package.xsl
@@ -0,0 +1,817 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Preprocesses package XML
+
+ This will preprocess a package XML suitable for compilation into an object
+ file.
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+
+ xmlns:preproc="http://www.lovullo.com/rater/preproc"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:t="http://www.lovullo.com/rater/apply-template"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:w="http://www.lovullo.com/rater/worksheet"
+ xmlns:lvv="http://www.lovullo.com/rater/validate"
+ xmlns:ext="http://www.lovullo.com/ext"
+ xmlns:util="http://www.lovullo.com/util">
+
+
+<xsl:include href="../dslc-base.xsl" />
+
+<!-- phases -->
+<xsl:include href="macros.xsl" />
+<xsl:include href="expand.xsl" />
+<xsl:include href="symtable.xsl" />
+
+<xsl:include href="../../compiler/fragments.xsl" />
+
+
+<!-- begin preprocessing from an arbitrary node -->
+<xsl:template name="preproc:pkg-compile" as="element( lv:package )"
+ match="*" mode="preproc:compile" priority="1">
+ <xsl:param name="orig-root" as="element()"
+ select="root(.)/lv:package" />
+
+ <xsl:param name="stopshort" />
+
+ <!-- should be provided externally -->
+ <xsl:if test="not( $__rseed ) or ( $__rseed = '' )">
+ <xsl:message terminate="yes">
+ <xsl:text>[preproc] error: missing random seed `__rseed'</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:message>
+ <xsl:text>[preproc] *beginning macro expansion...</xsl:text>
+ </xsl:message>
+
+ <!-- these can contain repass nodes, thus the element()+ -->
+
+ <!-- macro expansion -->
+ <xsl:variable name="stage1" as="element()+">
+ <xsl:apply-templates select="." mode="preproc:macropass" />
+
+ <xsl:message>
+ <xsl:text>[preproc] *macro pass complete; expanding...</xsl:text>
+ </xsl:message>
+ </xsl:variable>
+
+ <!-- expand shorthands, etc -->
+ <xsl:variable name="stage2" as="element()+">
+ <xsl:apply-templates select="$stage1"
+ mode="preproc:expand" />
+
+ <xsl:message>
+ <xsl:text>[preproc] *expansion complete; generating symbol table...</xsl:text>
+ </xsl:message>
+ </xsl:variable>
+
+ <xsl:variable name="stage3" as="element()+">
+ <xsl:apply-templates select="$stage2"
+ mode="preproc:sym-discover">
+
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ </xsl:apply-templates>
+
+ <xsl:message>
+ <xsl:text>[preproc] *symbol table generated; checking for </xsl:text>
+ <xsl:text>unprocessed templates...</xsl:text>
+ </xsl:message>
+ </xsl:variable>
+
+
+ <!-- TODO: resolve this mess -->
+ <xsl:variable name="stage3-pkg" as="element( lv:package )"
+ select="$stage3/preproc:symtable/parent::*" />
+
+ <!-- TODO: move me somewhere more appropriate and create an error
+ system that is _guaranteed_ to catch everything -->
+ <xsl:for-each select="$stage3-pkg/preproc:symtable/preproc:error">
+ <xsl:message terminate="yes">
+ <xsl:text>!!! [preproc] error: </xsl:text>
+ <xsl:value-of select="." />
+ </xsl:message>
+ </xsl:for-each>
+
+
+ <!-- determine if we should finish or simply return for further processing -->
+ <xsl:choose>
+ <xsl:when test="not( $stopshort )">
+ <!-- template expansions may have been deferred until their symbols were made
+ available -->
+ <xsl:variable name="final" as="element( lv:package )">
+ <xsl:call-template name="preproc:tpl-sym-recurse">
+ <xsl:with-param name="package" select="$stage3-pkg" />
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="extern-chk" as="element( preproc:error )*"
+ select="preproc:final-extern-check(
+ $final/preproc:symtable )" />
+
+
+ <xsl:if test="$extern-chk">
+ <xsl:for-each select="$extern-chk">
+ <xsl:message>
+ <xsl:text>!!! [preproc] error: </xsl:text>
+ <xsl:value-of select="." />
+ </xsl:message>
+ </xsl:for-each>
+
+ <xsl:message>~~~~[begin document dump]~~~~</xsl:message>
+ <xsl:message select="$final" />
+ <xsl:message>~~~~[end document dump]~~~~</xsl:message>
+
+ <xsl:message select="'Aborting due to unresolved externs'" />
+
+ <xsl:message terminate="yes"
+ select="'Document dumped.'" />
+ </xsl:if>
+
+ <!-- ensure that all template parameters have been expanded -->
+ <xsl:apply-templates select="$final" mode="preproc:tpl-check" />
+
+ <!-- perform validation before dependency generation to ensure that all
+ dependencies are available -->
+ <xsl:apply-templates select="$final" mode="preproc:pkg-validate" />
+
+ <!-- determine how many passes have been made -->
+ <!-- TODO: reintroduce
+ <xsl:variable name="repass-count"
+ select="count( $final//preproc:repass-record )" />
+ -->
+
+ <!-- assign unique ids to each node -->
+ <xsl:variable name="idized" as="element( lv:package )">
+ <xsl:apply-templates select="$final" mode="preproc:idize" />
+ </xsl:variable>
+
+ <!-- generate deps -->
+ <xsl:variable name="depd" as="element( lv:package )">
+ <xsl:apply-templates select="$idized" mode="preproc:gen-deps" />
+ </xsl:variable>
+
+ <!-- post-process symbol table to resolve any unknowns that require a
+ dependency tree -->
+ <xsl:variable name="resolvd" as="element( lv:package )">
+ <xsl:apply-templates select="$depd" mode="preproc:resolv-syms">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ </xsl:apply-templates>
+ </xsl:variable>
+
+
+ <!-- compile fragments -->
+ <xsl:message>
+ <xsl:text>[preproc] compiling fragments...</xsl:text>
+ </xsl:message>
+
+
+ <xsl:apply-templates select="$resolvd"
+ mode="preproc:compile-fragments" />
+
+
+ <!-- output a repass count, which could be a strong indicator of performance
+ issues -->
+ <!-- TODO: reintroduce
+ <xsl:message>
+ <xsl:text>[Preprocessor repass count: </xsl:text>
+ <xsl:value-of select="$repass-count" />
+ <xsl:text>] [Node count: </xsl:text>
+ <xsl:value-of select="count( $final//* )" />
+ <xsl:text>]</xsl:text>
+ </xsl:message>
+ -->
+ </xsl:when>
+
+ <!-- return for further processing -->
+ <xsl:otherwise>
+ <xsl:sequence select="$stage3" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!--
+ A very primitive guard against unexpanded template parameters.
+-->
+<xsl:template match="*[ starts-with( @*, '@' ) ]" mode="preproc:tpl-check" priority="5">
+ <xsl:message>
+ <xsl:text>[preproc] fatal: unexpanded template parameter: </xsl:text>
+ <xsl:sequence select="@*[ starts-with( ., '@' ) ]" />
+ </xsl:message>
+
+ <xsl:message>
+ <xsl:text>[preproc] fatal: reference node: </xsl:text>
+ <xsl:sequence select="." />
+ </xsl:message>
+
+ <xsl:message>~~~~[begin document dump]~~~~</xsl:message>
+ <xsl:message select="root(.)" />
+ <xsl:message>~~~~[end document dump]~~~~</xsl:message>
+
+ <xsl:message terminate="yes">[preproc] notice: Document dumped.</xsl:message>
+</xsl:template>
+
+
+<!-- this should never happen; but is has, so here's a failsafe -->
+<xsl:template match="lv:apply-template" mode="preproc:tpl-check" priority="5">
+ <xsl:message>
+ <xsl:text>[preproc] fatal: unexpanded template: </xsl:text>
+ <xsl:sequence select="." />
+ </xsl:message>
+
+ <xsl:message>
+ <xsl:text>[preproc] fatal: reference node: </xsl:text>
+ <xsl:sequence select="." />
+ </xsl:message>
+
+ <xsl:message select="'[preproc] internal error: there is a bug in the',
+ 'preprocessor; this should never happen!'" />
+
+ <xsl:message>~~~~[begin document dump]~~~~</xsl:message>
+ <xsl:message select="root(.)" />
+ <xsl:message>~~~~[end document dump]~~~~</xsl:message>
+
+ <xsl:message terminate="yes">[preproc] notice: Document dumped.</xsl:message>
+</xsl:template>
+
+
+<!-- skip things that cannot contain template applications -->
+<xsl:template match="lv:template|lv:const|lv:typedef"
+ mode="preproc:tpl-check" priority="9">
+</xsl:template>
+
+<xsl:template match="*" mode="preproc:tpl-check" priority="1">
+ <xsl:apply-templates select="*" mode="preproc:tpl-check" />
+</xsl:template>
+
+
+
+<!--
+ TODO: This needs to go away in the form of a more performant system
+ that marks a repass as needed *without* scanning the entire tree.
+-->
+<xsl:template name="preproc:tpl-sym-recurse" as="element( lv:package )">
+ <xsl:param name="package" as="element( lv:package )" />
+ <xsl:param name="orig-root" as="element()" />
+
+ <!-- number of iterations where no template applications have
+ happened -->
+ <xsl:param name="tpl-stall-count"
+ tunnel="yes"
+ select="0" />
+
+ <!-- get a list of needed template applications (ignoring applications that
+ are within templates and nested applications) -->
+ <xsl:variable name="apply" as="element( lv:apply-template )*"
+ select="$package//lv:apply-template[
+ not(
+ @name=$package/lv:template/@name
+ or ancestor::lv:template
+ or ancestor::lv:apply-template
+ )
+ ]" />
+ <xsl:variable name="napply" select="count( $apply )" />
+
+ <xsl:choose>
+ <xsl:when test="$apply">
+ <!-- get a list of required templates -->
+ <xsl:variable name="req">
+ <tpl>
+ <xsl:for-each select="$apply">
+ <xsl:copy>
+ <xsl:sequence select="@name" />
+ </xsl:copy>
+ </xsl:for-each>
+ </tpl>
+ </xsl:variable>
+
+ <xsl:variable name="requniq" as="element( lv:apply-template )*" select="
+ $req//lv:apply-template[
+ not( @name=preceding-sibling::lv:apply-template/@name
+ or @name=$package//lv:template/@name ) ]
+ " />
+
+ <xsl:message>
+ <xsl:text>[preproc] </xsl:text>
+ <xsl:value-of select="count( $apply )" />
+ <xsl:text> template(s) still need application: </xsl:text>
+
+ <xsl:for-each select="$apply">
+ <xsl:if test="position() gt 1">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="@name" />
+ </xsl:for-each>
+ </xsl:message>
+
+ <!-- load each of the requested templates (but only once) -->
+ <xsl:variable name="tpls">
+ <!-- TODO: we no longer need to load the templates; the
+ template replacement looks up the template on-demand from
+ the symbol table; we're no longer injecting them -->
+ <xsl:apply-templates mode="preproc:tpl-from-sym" select="$requniq">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ <xsl:with-param name="symtable" select="$package/preproc:symtable" />
+ </xsl:apply-templates>
+ </xsl:variable>
+
+ <!-- if we have recursed and have not decreased the application count at all,
+ then we have a problem -->
+ <xsl:if test="$requniq
+ and ( $package//preproc:sym-available )
+ and not( $package//preproc:repass[ @tpl-applied ] )">
+ <xsl:message terminate="yes">
+ <xsl:text>!!! [preproc] fatal: unable to locate symbols for </xsl:text>
+ <xsl:text>remaining templates: </xsl:text>
+
+ <xsl:for-each select="$requniq">
+ <xsl:if test="position() > 1">
+ <xsl:text>; </xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="@name" />
+ </xsl:for-each>
+ </xsl:message>
+ </xsl:if>
+
+ <!-- if there was an error during this part of the process, halt -->
+ <xsl:if test="$tpls//preproc:error">
+ <xsl:message terminate="yes">
+ <xsl:text>!!! [preproc] fatal: terminating due to errors</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <!-- perform expansion on the new package with the needed templates -->
+ <xsl:variable name="result" as="element( lv:package )">
+ <xsl:apply-templates select="$package" mode="preproc:compile">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ <xsl:with-param name="stopshort" select="true()" />
+ </xsl:apply-templates>
+
+ <xsl:message>
+ <xsl:text>[preproc] *expansion complete (recursive)</xsl:text>
+ </xsl:message>
+ </xsl:variable>
+
+ <!-- failsafe to prevent infinite recursion (5 (0-indexed)
+ should be plenty, since everything in the system results in
+ a template application in fewer steps -->
+ <xsl:if test="$requniq and $tpl-stall-count eq 4">
+ <xsl:message select="'!!! [preproc] internal: expansion deadlock!'" />
+ <xsl:message
+ select="'!!! [preproc] internal: stalled for 5 iterations'" />
+
+ <xsl:sequence select="preproc:dump-document( $result )" />
+
+ <xsl:message terminate="yes">
+ <xsl:text></xsl:text>
+ <xsl:text>!!! [preproc] fatal: expansion of remaining </xsl:text>
+ <xsl:text>templates aborted (have all been imported?): </xsl:text>
+
+ <xsl:for-each select="$requniq">
+ <xsl:if test="position() > 1">
+ <xsl:text>; </xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="@name" />
+ </xsl:for-each>
+ </xsl:message>
+ </xsl:if>
+
+ <!-- recurse to continue expanding if need be -->
+ <xsl:call-template name="preproc:tpl-sym-recurse">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ <xsl:with-param name="package" select="$result" />
+ <xsl:with-param name="tpl-stall-count"
+ tunnel="yes"
+ select="if ( $package//preproc:tpl-step ) then
+ 0
+ else
+ $tpl-stall-count + 1" />
+ </xsl:call-template>
+ </xsl:when>
+
+
+ <!-- expansion sequences and template short-hand expansions that
+ have not yet taken place, due to one reason or another (too
+ few passes: bug as far as I'm concerned) -->
+ <xsl:when test="$package//lv:expand-sequence[
+ not( ancestor::lv:template
+ or ancestor::lv:apply-template ) ]
+ |$package//t:*[
+ not( ancestor::lv:template
+ or ancestor::lv:apply-template ) ]">
+ <xsl:message select="'[preproc] pending expansions still present'" />
+
+ <xsl:variable name="result" as="element( lv:package )">
+ <xsl:apply-templates select="$package" mode="preproc:compile">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ <xsl:with-param name="stopshort" select="true()" />
+ </xsl:apply-templates>
+ </xsl:variable>
+
+ <xsl:call-template name="preproc:tpl-sym-recurse">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ <xsl:with-param name="package" select="$result" />
+ </xsl:call-template>
+ </xsl:when>
+
+
+ <!-- no further applications are necessary -->
+ <xsl:otherwise>
+ <!-- apply one final pass for the eligibility class generation -->
+ <xsl:call-template name="preproc:elig-class-pass">
+ <xsl:with-param name="package" select="$package" />
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template name="preproc:elig-class-pass" as="element( lv:package )">
+ <xsl:param name="package" as="element( lv:package )" />
+ <xsl:param name="orig-root" as="element()" />
+
+ <xsl:variable name="final-pkg" as="element( lv:package )">
+ <xsl:apply-templates select="$package" mode="preproc:expand-elig-class">
+ <xsl:with-param name="orig-root" select="$package" />
+ </xsl:apply-templates>
+ </xsl:variable>
+
+ <!-- yield the final pass against the elig-class-augmented package -->
+ <xsl:apply-templates select="$final-pkg" mode="preproc:compile">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ <xsl:with-param name="stopshort" select="true()" />
+ </xsl:apply-templates>
+</xsl:template>
+
+
+<!--
+ This is but a shell of its former self.
+
+ We are no longer injecting templates, so this can be removed or
+ adapted to do just enough to verify that the template symbols exist.
+-->
+<xsl:template match="lv:apply-template" mode="preproc:tpl-from-sym">
+ <xsl:param name="orig-root" as="element()" />
+
+ <xsl:param name="symtable" as="element( preproc:symtable )"
+ select="root(.)/preproc:symtable" />
+
+ <xsl:variable name="tplname" select="@name" />
+
+ <xsl:variable name="sym" as="element( preproc:sym )?" select="
+ $symtable/preproc:sym[
+ @name=$tplname
+ and @type='tpl'
+ ]
+ " />
+
+ <!-- if we have a symbol table, then attempt to locate it -->
+ <xsl:choose>
+ <!-- if we have located the template, then we know its source (@src must be
+ set, otherwise the template is defined in this package and should have
+ been available to begin with) -->
+ <xsl:when test="$sym">
+ <preproc:sym-available for="{$tplname}" />
+ </xsl:when>
+
+ <!-- nothing we can do yet -->
+ <xsl:otherwise>
+ <xsl:message>
+ <xsl:text>[preproc] template symbol not yet available: </xsl:text>
+ <xsl:value-of select="$tplname" />
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!-- TODO: we should use an attr besides _id; one more definitive -->
+<xsl:template match="*[ @_id ]" mode="preproc:macropass" priority="9">
+ <!-- already preprocessed -->
+ <xsl:sequence select="." />
+</xsl:template>
+<xsl:template match="*[ @_id ]" mode="preproc:idize" priority="9">
+ <!-- already preprocessed -->
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+
+<xsl:template match="preproc:repass-record" mode="preproc:idize" priority="9">
+ <!-- no longer needed; remove -->
+</xsl:template>
+
+
+<!-- do not idize preproc nodes (unneeded waste of cycles) -->
+<xsl:template match="preproc:*" mode="preproc:idize" priority="5">
+ <xsl:sequence select="." />
+</xsl:template>
+
+<!-- do not idize templates (will cause processing problems) -->
+<xsl:template match="lv:template" mode="preproc:idize" priority="5">
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+<!--
+ Generates a unique id for each element and stores it as @_id
+
+ This allows the node set to be copied and maintain its identity.
+-->
+<xsl:template match="*" mode="preproc:idize" priority="1">
+ <xsl:variable name="id">
+ <xsl:value-of select="generate-id(.)" />
+ </xsl:variable>
+
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:attribute name="_id">
+ <xsl:value-of select="$id" />
+ </xsl:attribute>
+
+ <xsl:apply-templates mode="preproc:idize" />
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template match="lv:package" mode="preproc:resolv-syms" as="element( lv:package )"
+ priority="9">
+ <xsl:param name="orig-root" as="element()" />
+ <xsl:param name="rpcount" select="0" />
+
+ <!-- arbitrary; intended to prevent infinite recursion -->
+ <!-- TODO: same method as for templates; ensure changes, but do not create
+ arbitrary limit -->
+ <xsl:if test="$rpcount = 100">
+ <xsl:sequence select="preproc:dump-document( root() )" />
+
+ <xsl:message terminate="yes">
+ <xsl:text>[preproc] !!! recursion limit reached in resolving `</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>' symbols</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:variable name="result" as="element( lv:package )">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:message>
+ <xsl:text>[preproc] *resolving symbol attributes...</xsl:text>
+ </xsl:message>
+
+ <xsl:apply-templates mode="preproc:resolv-syms">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ </xsl:apply-templates>
+ </xsl:copy>
+ </xsl:variable>
+
+ <xsl:variable name="repass"
+ select="$result//preproc:symtable/preproc:repass" />
+
+ <xsl:choose>
+ <!-- repass scheduled; go for it -->
+ <xsl:when test="$repass">
+ <xsl:message>[preproc] *SYM REPASS*</xsl:message>
+ <xsl:message>
+ <xsl:text>[preproc] The following </xsl:text>
+ <xsl:value-of select="count( $repass )" />
+ <xsl:text> symbol(s) are still unresolved:</xsl:text>
+ </xsl:message>
+
+ <xsl:for-each select="$repass">
+ <xsl:message>
+ <xsl:text>[preproc] - </xsl:text>
+ <xsl:value-of select="@ref" />
+ </xsl:message>
+ </xsl:for-each>
+
+ <xsl:apply-templates select="$result" mode="preproc:resolv-syms">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ <xsl:with-param name="rpcount" select="$rpcount + 1" />
+ </xsl:apply-templates>
+ </xsl:when>
+
+ <!-- no repass needed; done -->
+ <xsl:otherwise>
+ <xsl:sequence select="$result" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template match="preproc:symtable" mode="preproc:resolv-syms" priority="5">
+ <xsl:param name="orig-root" as="element()" />
+
+ <xsl:copy>
+ <xsl:apply-templates mode="preproc:resolv-syms">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ </xsl:apply-templates>
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ not( @src ) and @dim='?' ]" mode="preproc:resolv-syms" priority="5">
+ <xsl:param name="orig-root" as="element()" />
+
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="pkg" as="element( lv:package )"
+ select="root(.)" />
+
+ <xsl:variable name="deps" as="element( preproc:sym-dep )*" select="
+ $pkg/preproc:sym-deps/preproc:sym-dep[ @name=$name ]
+ " />
+
+ <xsl:variable name="depsyms-unresolv" as="element( preproc:sym )*" select="
+ $pkg/preproc:symtable/preproc:sym[
+ @name=$deps/preproc:sym-ref/@name
+ ]
+ " />
+
+ <xsl:variable name="depsyms-resolv">
+ <xsl:for-each select="$depsyms-unresolv">
+ <xsl:choose>
+ <xsl:when test="not( @src )">
+ <xsl:sequence select="." />
+ </xsl:when>
+
+ <!-- look up complete symbol -->
+ <xsl:otherwise>
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="sym" select="
+ document( concat( @src, '.xmlo' ), $orig-root )
+ /lv:package/preproc:symtable/preproc:sym[
+ @name=$name
+ ]
+ " />
+
+ <xsl:if test="not( $sym )">
+ <xsl:message terminate="yes">
+ <xsl:text>[preproc] !!! failed to look up symbol `</xsl:text>
+ <xsl:value-of select="$name" />
+ <xsl:text>'</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:sequence select="$sym" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:variable>
+
+ <xsl:variable name="depsyms" select="$depsyms-resolv/preproc:sym" />
+
+ <xsl:choose>
+ <!-- unresolved dependency dimensions; defer until next pass -->
+ <xsl:when test="
+ $depsyms/@dim = '?'
+ ">
+ <xsl:message>
+ <xsl:text>[preproc] deferring `</xsl:text>
+ <xsl:value-of select="$name" />
+ <xsl:text>' dimensions with unresolved dependencies</xsl:text>
+ </xsl:message>
+
+ <!-- schedule repass :x -->
+ <xsl:sequence select="." />
+ <preproc:repass src="preproc:sym resolv-syms"
+ ref="{$name}" />
+ </xsl:when>
+
+ <!-- all dependencies are resolved; calculate dimensions -->
+ <xsl:otherwise>
+ <!-- sort dependencies so that the largest dimension is at the top -->
+ <xsl:variable name="maxset">
+ <xsl:for-each select="$depsyms">
+ <xsl:sort select="@dim" data-type="number" order="descending" />
+ <xsl:sequence select="." />
+ </xsl:for-each>
+ </xsl:variable>
+
+ <xsl:variable name="max">
+ <xsl:choose>
+ <xsl:when test="count( $deps/preproc:sym-ref ) = 0">
+ <!-- no dependencies, unknown size, so it's a scalar -->
+ <xsl:text>0</xsl:text>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <!-- largest value -->
+ <xsl:value-of select="$maxset/preproc:sym[1]/@dim" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <!-- failure? -->
+ <xsl:if test="not( $max ) or $max = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>[preproc] !!! failed to determine dimensions of `</xsl:text>
+ <xsl:value-of select="$name" />
+ <xsl:text>'</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <!-- logging -->
+ <xsl:message>
+ <xsl:text>[preproc] resolved `</xsl:text>
+ <xsl:value-of select="$name" />
+ <xsl:text>' dimensions as `</xsl:text>
+ <xsl:value-of select="$max" />
+ <xsl:text>'</xsl:text>
+ </xsl:message>
+
+ <!-- copy, substituting calculated dimensions -->
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+ <xsl:attribute name="dim" select="$max" />
+ <xsl:sequence select="*" />
+ </xsl:copy>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template match="preproc:repass" mode="preproc:resolv-syms" priority="9">
+ <!-- strip -->
+</xsl:template>
+
+
+<xsl:template match="*" mode="preproc:resolv-syms" priority="1">
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+<xsl:template match="lv:package" mode="preproc:pkg-validate">
+ <xsl:variable name="symbol-map">
+ <xsl:call-template name="get-symbol-map" />
+ </xsl:variable>
+
+ <xsl:variable name="err">
+ <xsl:apply-templates select="." mode="lvv:validate">
+ <xsl:with-param name="symbol-map" select="$symbol-map" />
+ </xsl:apply-templates>
+ </xsl:variable>
+
+ <xsl:apply-templates select="$err//lvv:error" mode="preproc:handle-lvv-errors">
+ <xsl:with-param name="document" select="." />
+ </xsl:apply-templates>
+</xsl:template>
+
+
+<xsl:template match="*|text()" mode="preproc:pkg-validate">
+</xsl:template>
+
+
+<!-- errors should cause a failure -->
+<xsl:template match="lvv:error" mode="preproc:handle-lvv-errors" priority="5">
+ <xsl:param name="document" />
+
+ <!-- output error -->
+ <xsl:message>
+ <xsl:text>!!! </xsl:text>
+ <xsl:value-of select="@desc" />
+
+ <xsl:if test="@path != ''">
+ <xsl:text> (</xsl:text>
+ <xsl:value-of select="@path" />
+ <xsl:text>)</xsl:text>
+ </xsl:if>
+
+ <xsl:text>: </xsl:text>
+ <xsl:value-of select="." />
+ </xsl:message>
+
+ <!-- terminate after we've output each error -->
+ <xsl:if test="not( following-sibling::lvv:error )">
+ <!-- dump document for debugging -->
+ <xsl:sequence select="preproc:dump-document( $document )" />
+ <xsl:message terminate="yes">Compilation failed due to validation errors.</xsl:message>
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:function name="preproc:dump-document">
+ <xsl:param name="document" />
+
+ <xsl:message>~~~~[begin document dump]~~~~</xsl:message>
+ <xsl:message select="$document" />
+ <xsl:message>~~~~[end document dump]~~~~</xsl:message>
+ <xsl:message>internal: document dumped.</xsl:message>
+</xsl:function>
+
+
+<xsl:template match="node()|text()" mode="preproc:handle-lvv-errors" priority="1">
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/preproc/path.xsl b/src/current/include/preproc/path.xsl
new file mode 100644
index 0000000..469603d
--- /dev/null
+++ b/src/current/include/preproc/path.xsl
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Operations on paths
+-->
+<xsl:stylesheet version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc">
+
+
+<xsl:template name="preproc:get-path">
+ <xsl:param name="path" />
+ <xsl:param name="prev" select="''" />
+
+ <xsl:variable name="first" select="substring-before( $path, '/' )" />
+ <xsl:variable name="rest" select="substring-after( $path, '/' )" />
+
+ <xsl:choose>
+ <!-- if there's no $first, then there is no path separator, in which case
+ we're done; if there's no rest, then there is a path separator, but it
+ resulted in an empty string, meanaing that it ends in a path
+ separator, in which case we are also done -->
+ <xsl:when test="not( $first ) or not( $rest )">
+ <!-- no more path separators; we're done -->
+ <xsl:value-of select="$prev" />
+ </xsl:when>
+
+ <!-- keep recursing -->
+ <xsl:otherwise>
+ <xsl:call-template name="preproc:get-path">
+ <xsl:with-param name="path" select="$rest" />
+ <xsl:with-param name="prev">
+ <xsl:if test="not( $prev = '' )">
+ <xsl:value-of select="concat( $prev, '/' )" />
+ </xsl:if>
+
+ <xsl:value-of select="$first" />
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!-- FIXME: duplicate code with above -->
+<xsl:template name="preproc:get-basename">
+ <xsl:param name="path" />
+ <xsl:param name="prev" select="''" />
+
+ <xsl:variable name="first" select="substring-before( $path, '/' )" />
+ <xsl:variable name="rest" select="substring-after( $path, '/' )" />
+
+ <xsl:choose>
+ <!-- if there's no $first, then there is no path separator, in which case
+ we're done; if there's no rest, then there is a path separator, but it
+ resulted in an empty string, meanaing that it ends in a path
+ separator, in which case we are also done -->
+ <xsl:when test="not( $first ) or not( $rest )">
+ <!-- no more path separators; we're done -->
+ <xsl:value-of select="$path" />
+ </xsl:when>
+
+ <!-- keep recursing -->
+ <xsl:otherwise>
+ <xsl:call-template name="preproc:get-basename">
+ <xsl:with-param name="path" select="$rest" />
+ <xsl:with-param name="prev">
+ <xsl:if test="not( $prev = '' )">
+ <xsl:value-of select="concat( $prev, '/' )" />
+ </xsl:if>
+
+ <xsl:value-of select="$first" />
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template name="preproc:resolv-path">
+ <xsl:param name="path" />
+
+ <!-- in order: strip //, process ../, strip ./ -->
+ <xsl:call-template name="preproc:strip-sdot-path">
+ <xsl:with-param name="path">
+ <xsl:call-template name="preproc:resolv-rel-path">
+ <xsl:with-param name="path">
+ <xsl:call-template name="preproc:strip-extra-path">
+ <xsl:with-param name="path" select="$path" />
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+</xsl:template>
+
+
+<!-- XXX: warning, this won't like 'foo../' -->
+<xsl:template name="preproc:resolv-rel-path">
+ <xsl:param name="path" />
+
+ <!-- relative paths -->
+ <xsl:variable name="before" select="substring-before( $path, '../' )" />
+ <xsl:variable name="after" select="substring-after( $path, '../' )" />
+
+ <xsl:choose>
+ <xsl:when test="$before">
+ <xsl:call-template name="preproc:resolv-rel-path">
+ <xsl:with-param name="path">
+ <!-- remove the last directory before the ../ -->
+ <xsl:variable name="before-path">
+ <xsl:call-template name="preproc:get-path">
+ <xsl:with-param name="path" select="$before" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:value-of select="$before-path" />
+
+ <!-- the above get-path call will strip the trailing slash -->
+ <xsl:if test="not( $before-path = '' ) and not( $after = '' )">
+ <xsl:text>/</xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="$after" />
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+
+
+ <!-- if there's no $before but there is an $after, then we must begin with
+ '../', which we can do nothing with; output it and continue processing
+ the remainder of the path -->
+ <xsl:when test="$after">
+ <xsl:text>../</xsl:text>
+
+ <xsl:call-template name="preproc:resolv-rel-path">
+ <xsl:with-param name="path" select="$after" />
+ </xsl:call-template>
+ </xsl:when>
+
+
+ <!-- no relative paths remaining -->
+ <xsl:otherwise>
+ <xsl:value-of select="$path" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template name="preproc:strip-sdot-path">
+ <xsl:param name="path" />
+
+ <xsl:choose>
+ <!-- the only time this should be called with an unresolved relative path
+ is if it begins with one, in which case we'll simply output it and
+ continue processing without it -->
+ <xsl:when test="starts-with( $path, '../' )">
+ <xsl:text>../</xsl:text>
+
+ <!-- continue processing without it -->
+ <xsl:call-template name="preproc:strip-sdot-path">
+ <xsl:with-param name="path" select="substring-after( $path, '../' )" />
+ </xsl:call-template>
+ </xsl:when>
+
+
+ <!-- path is safe for processing -->
+ <xsl:otherwise>
+ <xsl:variable name="a" select="substring-before( $path, './' )" />
+ <xsl:variable name="b" select="substring-after( $path, './' )" />
+
+
+ <xsl:choose>
+ <!-- if we found one, recurse -->
+ <xsl:when test="$a or $b">
+ <xsl:call-template name="preproc:strip-sdot-path">
+ <xsl:with-param name="path">
+ <xsl:value-of select="$a" />
+
+ <xsl:if test="$a and $b">
+ <xsl:text>/</xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="$b" />
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+
+
+ <!-- done -->
+ <xsl:otherwise>
+ <xsl:value-of select="$path" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template name="preproc:strip-extra-path">
+ <xsl:param name="path" />
+
+ <xsl:variable name="a" select="substring-before( $path, '//' )" />
+ <xsl:variable name="b" select="substring-after( $path, '//' )" />
+
+
+ <xsl:choose>
+ <!-- if we found one, recurse -->
+ <xsl:when test="$a or $b">
+ <xsl:call-template name="preproc:strip-extra-path">
+ <xsl:with-param name="path">
+ <xsl:value-of select="$a" />
+
+ <xsl:if test="$a and $b">
+ <xsl:text>/</xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="$b" />
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+
+ <!-- we're done! -->
+ <xsl:otherwise>
+ <xsl:value-of select="$path" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/preproc/symtable.xsl b/src/current/include/preproc/symtable.xsl
new file mode 100644
index 0000000..9210c76
--- /dev/null
+++ b/src/current/include/preproc/symtable.xsl
@@ -0,0 +1,959 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Generates a symbol table from fully a expanded (preprocessed) package
+
+ It is important that this table be generated after fully expanding all
+ templates, macros, etc; otherwise, the table may be incomplete.
+
+ The preproc:sym/@tex attribute is a TeX symbol used for typsetting. This
+ process is not responsible for generating defaults; that should be done by the
+ linker to ensure that there are no conflicts after all symbols are known.
+
+ Here are the recognized types:
+ rate - lv:rate block
+ gen - generator (c:*/@generates)
+ cgen - class generator (lv:classify/@yields)
+ class - classification (lv:classify/@as)
+ param - global param (lv:param)
+ lparam - local param (lv:function/lv:param)
+ const - global constant (lv:const; lv:enum/lv:item)
+ tpl - template (lv:template)
+ type - datatype (lv:typedef)
+ func - function
+
+ Dimensions (think 0=point, 1=line, 2=plane, etc):
+ 0 - scalar
+ 1 - vector
+ 2 - matrix
+ ...
+
+ Symbols from imported packages will be consumed and added to the output,
+ unless local; this has a similiar effect to including a C header file.
+ External symbols are denoted by preproc:sym/@src, which specifies the name of
+ the package from which it was imported. If an imported symbol conflicts with
+ another symbol (imported or otherwise), an error will be produced. Symbols
+ that are imported are implicitly marked as local.
+
+ Certain symbols will "polute" the symbol table of every package that imports
+ it, every package that imports that one, etc; this is for compatibility with
+ the old system and will hopefully be phased out eventually. Pollution will
+ reserve the symbol, but will not provide enough information about that symbol
+ to be useful, which will ensure that a package has to import the symbol
+ explicitly in order to actually make use of it.
+-->
+
+<xsl:stylesheet version="2.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:symtable="http://www.lovullo.com/tame/symtable"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:c="http://www.lovullo.com/calc">
+
+
+<xsl:include href="path.xsl" />
+<xsl:include href="../../tame/src/symtable.xsl" />
+
+
+<!-- we will recurse through the entire tree rather than performing a series of
+ xpaths that are likely to hit the same nodes many times -->
+<xsl:template match="*" mode="preproc:symtable" priority="1">
+ <xsl:apply-templates mode="preproc:symtable" />
+</xsl:template>
+
+<xsl:template match="text()" mode="preproc:symtable" priority="9">
+ <!-- output nothing -->
+</xsl:template>
+
+
+<!-- an alternative way to invoke the preproc:sym-discover template; useful for
+ use on variables -->
+<xsl:template match="*" mode="preproc:sym-discover" as="element()">
+ <xsl:param name="orig-root" />
+
+ <xsl:call-template name="preproc:sym-discover">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ </xsl:call-template>
+</xsl:template>
+
+
+<xsl:template match="preproc:*" mode="preproc:sym-discover"
+ as="element()" priority="9">
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+<!--
+ Other systems may contribute to a symbol table by invoking this template and
+ supplying the necessary preproc:symtable templates
+
+ TODO: This guy needs some refactoring
+-->
+<xsl:template name="preproc:sym-discover" as="element()">
+ <xsl:param name="orig-root" />
+
+ <xsl:variable name="this-pkg" as="element( lv:package )"
+ select="." />
+
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:variable name="new">
+ <xsl:message>
+ <xsl:text>[preproc/symtable] discovering symbols...</xsl:text>
+ </xsl:message>
+
+ <preproc:syms>
+ <xsl:apply-templates mode="preproc:symtable">
+ <!-- we only need this param for the root children, so this is the only
+ template application that passes this -->
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ </xsl:apply-templates>
+ </preproc:syms>
+ </xsl:variable>
+
+ <!-- gather a list of overrides -->
+ <xsl:variable name="overrides" select="
+ $new/preproc:syms/preproc:sym[ @override='true' ]
+ " />
+
+ <!-- check for duplicates -->
+ <xsl:variable name="symdup" as="element( preproc:sym )*"
+ select="symtable:find-duplicates( $new/preproc:syms )" />
+
+ <!-- overrides that override nothing may be the sign of a bug (expectation
+ of something that isn't there) -->
+ <xsl:for-each select="$overrides[ not( @name=$symdup/@name ) ]">
+ <xsl:message>
+ <xsl:text>[preproc/symtable] warning: symbol /</xsl:text>
+ <xsl:value-of select="$this-pkg/@name" />
+ <xsl:text>/</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text> has @override set, but does not override anything</xsl:text>
+ </xsl:message>
+ </xsl:for-each>
+
+ <!-- perform non-override duplicate checks (TODO: @ignore-dup is
+ intended to be temporary while map __head and __tail
+ generation conflicts are resolved) -->
+ <xsl:variable name="symdup-problems" as="element( preproc:sym )*" select="
+ $symdup[
+ not( @name = $overrides/@name
+ and @virtual = 'true' )
+ and not( @ignore-dup = 'true' ) ]
+ " />
+
+ <xsl:for-each select="$symdup-problems">
+ <xsl:variable name="dupname" select="@name" />
+
+ <xsl:choose>
+ <!-- attempt to override a non-virtual symbol -->
+ <xsl:when test="@name=$overrides/@name and not( @virtual='true' )">
+ <xsl:message>
+ <xsl:text>[preproc/symtable] error: cannot override non-virtual symbol /</xsl:text>
+ <xsl:value-of select="$this-pkg/@name" />
+ <xsl:text>/</xsl:text>
+ <xsl:value-of select="@name" />
+ </xsl:message>
+ </xsl:when>
+
+ <!-- just a plain duplicate -->
+ <xsl:otherwise>
+ <xsl:message>
+ <xsl:text>[preproc/symtable] error: duplicate symbol /</xsl:text>
+ <xsl:value-of select="$this-pkg/@name" />
+ <xsl:text>/</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text> (defined in ./</xsl:text>
+
+ <!-- output sources -->
+ <xsl:for-each select="
+ $new/preproc:syms/preproc:sym[
+ @name=$dupname
+ and @src
+ and not( @extern='true' )
+ and not( @name=$overrides/@name and @virtual='true' )
+ ]
+ ">
+ <xsl:if test="position() gt 1">
+ <xsl:text> and ./</xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="@src" />
+ </xsl:for-each>
+ <xsl:text>)</xsl:text>
+
+ <!-- if virtual, suggest override as an alternative solution -->
+ <xsl:if test="@virtual='true'">
+ <xsl:text>; did you forget @override?</xsl:text>
+ </xsl:if>
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+
+ <!-- terminate if any duplicates are found, dumping documents for debugging -->
+ <xsl:if test="count( $symdup-problems ) gt 0">
+ <xsl:message>~~~~[begin document dump]~~~~</xsl:message>
+ <xsl:message select="$this-pkg" />
+ <xsl:message>~~~~[end document dump]~~~~</xsl:message>
+
+ <xsl:message>~~~~[begin symbol dump]~~~~</xsl:message>
+ <xsl:message select="$new" />
+ <xsl:message>~~~~[end symbol dump]~~~~</xsl:message>
+
+ <xsl:message terminate="yes">
+ <xsl:text>[preproc/symtable] fatal: aborting due to symbol errors</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+
+ <xsl:variable name="result" as="element( preproc:symtable )">
+ <preproc:symtable>
+ <!-- copy any existing symbols table -->
+ <preproc:syms>
+ <xsl:sequence select="preproc:symtable/preproc:sym" />
+ <xsl:sequence select="$new/preproc:syms/preproc:sym" />
+ </preproc:syms>
+ </preproc:symtable>
+ </xsl:variable>
+
+ <!-- output the symbols, checking for duplicates -->
+ <preproc:symtable>
+ <!-- validate imported externs -->
+ <xsl:variable name="extresults" as="element( preproc:syms )">
+ <xsl:call-template name="preproc:symtable-process-extern">
+ <xsl:with-param name="result" select="$result" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <!-- remove duplicates (if any) -->
+ <xsl:sequence select="
+ $extresults/preproc:sym[
+ not( @name=preceding-sibling::preproc:sym/@name )
+ ]
+ , $extresults//preproc:error
+ " />
+
+ <!-- process symbols (except imported externs) -->
+ <xsl:variable name="newresult" as="element( preproc:syms )">
+ <xsl:call-template name="preproc:symtable-process-symbols">
+ <xsl:with-param name="extresults" select="$extresults" />
+ <xsl:with-param name="new" select="$new/preproc:syms" />
+ <xsl:with-param name="this-pkg" select="$this-pkg" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="dedup" as="element( preproc:sym )*"
+ select="$newresult/preproc:sym[
+ not(
+ (
+ @pollute='true'
+ and not( @type )
+ and (
+ @name=preceding-sibling::preproc:sym/@name
+ or @name=$newresult/preproc:sym[ @type ]/@name
+ )
+ )
+ )
+ ]" />
+
+
+ <xsl:apply-templates mode="preproc:symtable-complete"
+ select="$dedup">
+ <xsl:with-param name="syms" select="$dedup" />
+ </xsl:apply-templates>
+ </preproc:symtable>
+
+ <xsl:message>
+ <xsl:text>[preproc/symtable] done.</xsl:text>
+ </xsl:message>
+
+ <!-- copy all of the original elements after the symbol table; we're not
+ outputting them as we go, so we need to make sure that we don't get
+ rid of them; discard any existing symbol table -->
+ <xsl:apply-templates mode="preproc:symtable-inject" />
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template match="preproc:symtable" mode="preproc:symtable-inject"
+ priority="5">
+ <!-- strip old symbol table -->
+</xsl:template>
+
+<xsl:template match="*" mode="preproc:symtable-inject">
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+<xsl:template name="preproc:symtable-process-extern"
+ as="element( preproc:syms )">
+ <xsl:param name="result" as="element( preproc:symtable )" />
+
+ <xsl:variable name="syms" as="element( preproc:syms )"
+ select="$result/preproc:syms" />
+
+ <preproc:syms>
+ <xsl:for-each select="$syms/preproc:sym[
+ @extern='true'
+ and @src
+ and not( @held ) ]">
+ <xsl:variable name="name" select="@name" />
+
+ <!-- our value may be concrete or an extern itself; we may also import
+ a package with a concrete definition -->
+ <xsl:variable name="ours" select="
+ $syms/preproc:sym[
+ @name=$name
+ and (
+ not( @src )
+ or ( @dtype and @src and not( @extern ) )
+ )
+ ]
+ " />
+
+ <xsl:choose>
+ <!-- we have our own symbol; ensure the important values match the
+ expected (unless @dim has not yet been resolved) -->
+ <!-- XXX: the @dim='?' check leaves room for a dimension mismatch to
+ slip through; re-order checks (see package.xsl) as necessary to
+ ensure that this doesn't happen -->
+ <xsl:when test="$ours">
+ <xsl:if test="
+ not(
+ @type=$ours/@type
+ and @dtype=$ours/@dtype
+ and (
+ @dim=$ours/@dim
+ or $ours/@dim='?'
+ )
+ )
+ ">
+
+ <preproc:error>
+ <xsl:text>extern mismatch: '</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>' (imported from </xsl:text>
+ <xsl:value-of select="@src" />
+ <xsl:text>)</xsl:text>
+
+ <xsl:for-each select="@type, @dtype, @dim">
+ <xsl:variable name="aname" select="local-name()" />
+ <xsl:text>; </xsl:text>
+
+ <xsl:value-of select="local-name()" />
+ <xsl:text>=</xsl:text>
+ <xsl:value-of select="$ours/@*[ local-name() = $aname ]" />
+ <xsl:text>, </xsl:text>
+ <xsl:value-of select="." />
+ <xsl:text> expected</xsl:text>
+ </xsl:for-each>
+ </preproc:error>
+ </xsl:if>
+
+ <!-- N.B.: there could potentially be multiple matches -->
+ <!-- TODO: pollution should be removed and l:resolv-extern
+ in the linker should look up the package that should
+ include the resolved extern from the processing stack -->
+ <preproc:sym pollute="true">
+ <xsl:sequence select="$ours[1]/@*|*" />
+ </preproc:sym>
+ </xsl:when>
+
+ <!-- we do not have our own symbol matching this extern;
+ ignore this for now, as it may be handled by a future
+ template expansion -->
+ <xsl:otherwise>
+ <preproc:sym held="true">
+ <xsl:sequence select="@*" />
+ </preproc:sym>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </preproc:syms>
+</xsl:template>
+
+
+<xsl:function name="preproc:final-extern-check" as="element(preproc:error )*">
+ <xsl:param name="symtable" as="element( preproc:symtable )" />
+
+ <!-- any remaining unresolved externs at this point are bad -->
+ <xsl:for-each select="$symtable/preproc:sym[
+ @extern = 'true'
+ and @src ]">
+
+ <!-- since @missing may be provided, let's include the actual
+ symbol in the runlog for debugging -->
+ <xsl:message select="'[preproc] missing extern: ', @name" />
+
+ <preproc:error>
+ <xsl:choose>
+ <xsl:when test="@missing and not( @missing = '' )">
+ <xsl:value-of select="normalize-space( @missing )" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text>unresolved extern '</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>'</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:text> (required by </xsl:text>
+ <xsl:value-of select="@src" />
+ <xsl:text>)</xsl:text>
+ </preproc:error>
+ </xsl:for-each>
+</xsl:function>
+
+
+<xsl:template name="preproc:symtable-process-symbols">
+ <xsl:param name="extresults" as="element( preproc:syms )" />
+ <xsl:param name="new" as="element( preproc:syms )" />
+ <xsl:param name="this-pkg" as="element( lv:package )" />
+
+ <preproc:syms>
+ <xsl:variable name="cursym" as="element( preproc:sym )*"
+ select="preproc:symtable/preproc:sym[
+ not( @held = 'true' ) ]" />
+
+ <xsl:sequence select="$cursym" />
+
+ <xsl:message>
+ <xsl:text>[preproc/symtable] processing symbol table...</xsl:text>
+ </xsl:message>
+
+ <xsl:for-each select="$new/preproc:sym[ not( @extern='true' and @src ) ]">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="src" select="@src" />
+ <xsl:variable name="dupall" select="
+ (
+ preceding-sibling::preproc:sym,
+ $cursym,
+ $extresults/preproc:sym
+ )[
+ @name=$name
+ ]
+ " />
+ <xsl:variable name="dup" select="
+ $dupall[
+ not(
+ @src=$src
+ or ( not( @src ) and not( $src ) )
+ )
+ ]
+ " />
+
+ <xsl:choose>
+ <xsl:when test="@pollute='true' and not( @type )">
+ <!-- we'll strip these out later -->
+ <xsl:sequence select="." />
+ </xsl:when>
+
+ <!-- note that dupall uses preceding-sibling, which will catch
+ duplicates in that case even if @override is not set -->
+ <xsl:when test="following-sibling::preproc:sym[ @name=$name and @override='true' ]">
+ <!-- overridden; we're obsolete :( -->
+ </xsl:when>
+
+ <!-- if we've gotten this far, then the override is good; clear it -->
+ <xsl:when test="@override='true'">
+ <xsl:copy>
+ <xsl:sequence select="@*[ not( name()='override' ) ], *" />
+ </xsl:copy>
+ </xsl:when>
+
+ <xsl:when test="$dupall[ @type ]">
+ <!-- there is already a symbol of this name from the same package;
+ let's not add duplicates -->
+ </xsl:when>
+
+ <xsl:otherwise>
+ <!-- this symbol is good; use it -->
+ <xsl:sequence select="." />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </preproc:syms>
+</xsl:template>
+
+
+<xsl:template match="preproc:symtable" mode="preproc:symtable" priority="9">
+ <!-- ignore existing symbol tables (for now at least) -->
+</xsl:template>
+
+
+<!-- do not re-import symbol tables that have already been imported -->
+<xsl:template match="lv:import[
+ @package=root(.)/preproc:symtable/preproc:sym[
+ @dtype
+ ]/@src
+ ]"
+ mode="preproc:symtable" priority="9">
+</xsl:template>
+
+
+<xsl:template name="preproc:symimport" match="lv:import[ @package ]" mode="preproc:symtable" priority="8">
+ <xsl:param name="orig-root" />
+ <xsl:param name="package" select="@package" />
+ <xsl:param name="export" select="@export" />
+ <xsl:param name="ignore-keep" select="@ignore-keep" />
+ <xsl:param name="no-extclass" select="@no-extclass" />
+ <xsl:param name="keep-classes" select="@keep-classes" />
+
+ <xsl:variable name="path" select="concat( $package, '.xmlo' )" />
+ <xsl:variable name="syms"
+ select="document( $path, $orig-root )/lv:*/preproc:symtable" />
+
+ <xsl:variable name="import-path" select="$package" />
+
+ <!-- if they're including a program package, do they realize what they're
+ doing!? -->
+ <!-- FIXME: @allow-nonpkg is no longer accurate terminology; change to
+ @allow-nonprg -->
+ <xsl:if test="
+ not( @allow-nonpkg = 'true' )
+ and $syms/parent::lv:package[ @program='true' ]
+ ">
+ <xsl:message terminate="yes">
+ <xsl:text>[preproc/symtable] error: refusing to import non-package </xsl:text>
+ <xsl:value-of select="$import-path" />
+ <xsl:text>; use @allow-nonpkg to force (if you know what you are doing)</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <!-- determine our path from our name -->
+ <xsl:variable name="our-path">
+ <xsl:call-template name="preproc:get-path">
+ <xsl:with-param name="path"
+ select="ancestor::lv:package/@name" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <!-- to keep everything consistent and to simplify package equality
+ assertions, resolve relative paths -->
+ <xsl:variable name="import-default-path" select="$import-path" />
+
+ <xsl:message>
+ <xsl:text>[preproc/symtable] importing symbol table of </xsl:text>
+ <xsl:value-of select="$import-path" />
+ <xsl:text>...</xsl:text>
+ </xsl:message>
+
+ <!-- attempt to import symbols from the processed package -->
+ <xsl:if test="not( $syms )">
+ <xsl:message terminate="yes">
+ <xsl:text>[preproc/symtable] internal error: </xsl:text>
+ <xsl:text>failed to locate symbol table: </xsl:text>
+ <xsl:value-of select="$path" />
+ </xsl:message>
+ </xsl:if>
+
+ <!-- copy directly into symbol table, setting external source; local symbols
+ will not be imported -->
+ <xsl:for-each select="
+ $syms/preproc:sym[
+ (
+ not( @local='true' )
+ or @pollute='true'
+ or (
+ ( @type='class' or @type='cgen' )
+ and $keep-classes='true'
+ )
+ )
+ and not( $no-extclass='true' and @extclass='true' )
+ ]
+ ">
+ <xsl:copy>
+ <xsl:choose>
+ <!-- pollution should have only the name and pollution status copied
+ over, which has the effect of reserving the symbol but not
+ providing enough information to actually make use of it; only
+ strip the data if this is a second-hand import -->
+ <!-- TODO: this list has gotten too large, but reducing it will require
+ refactoring other compilers and may reduce performance -->
+ <xsl:when test="@pollute='true' and @local='true'">
+ <xsl:sequence select="@name, @src, @pollute, @keep, @parent, @extclass" />
+ </xsl:when>
+
+ <!-- copy all the symbol information -->
+ <xsl:otherwise>
+ <xsl:sequence select="@*" />
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <!-- all imported symbols are implicitly local (so including one package
+ will not include symbols down the entire hierarchy), unless the
+ symbol is explicitly marked global or @export was provided on the
+ import node -->
+ <xsl:if test="not( $export='true' )">
+ <xsl:attribute name="local" select="'true'" />
+ </xsl:if>
+
+ <!-- determine the relative path to the import -->
+ <xsl:attribute name="src">
+ <xsl:choose>
+ <!-- if no @src is set, then the answer is simple: the relative path is
+ the import path -->
+ <xsl:when test="not( @src )">
+ <xsl:value-of select="$import-default-path" />
+ </xsl:when>
+
+ <!-- otherwise, we need to merge the import path into the existing
+ relative path by prepending the import path (sans the package name
+ itself) onto the existing relative path and resolving relative
+ paths -->
+ <xsl:otherwise>
+ <xsl:call-template name="preproc:resolv-path">
+ <xsl:with-param name="path">
+ <!-- get the path of the import, sans package name -->
+ <xsl:variable name="path">
+ <xsl:call-template name="preproc:get-path">
+ <xsl:with-param name="path" select="$import-path" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <!-- concatenate it with the existing relative path -->
+ <xsl:if test="not( $path = '' )">
+ <xsl:value-of select="concat( $path, '/' )" />
+ </xsl:if>
+
+ <xsl:value-of select="@src" />
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+
+ <!-- keep manipulation: *always* keep classes if requested, even if
+ @ignore-keep is provided; in the case of the latter, unsets @keep -->
+ <xsl:choose>
+ <!-- keep classes when requested -->
+ <xsl:when test="
+ ( @type = 'class' or @type = 'cgen' )
+ and $keep-classes = 'true'">
+
+ <xsl:attribute name="keep" select="'false'" />
+ </xsl:when>
+
+ <!-- demolish @keep if requested -->
+ <xsl:when test="$ignore-keep = 'true'">
+ <xsl:attribute name="keep" select="'false'" />
+ </xsl:when>
+ </xsl:choose>
+
+ <!-- children should always be copied, unless poluting -->
+ <xsl:if test="not( @pollute='true' and @local='true' )">
+ <xsl:sequence select="preproc:*" />
+ </xsl:if>
+ </xsl:copy>
+ </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template match="lv:template" mode="preproc:symtable" priority="9">
+ <!-- do not process template bodies; we're only interested in the symbols
+ they produce after expansion -->
+ <preproc:sym name="{@name}"
+ type="tpl" dim="0" desc="{@desc}" />
+</xsl:template>
+
+
+<xsl:template match="lv:rate" mode="preproc:symtable" priority="5">
+ <xsl:variable name="external" select="boolean( @external='true' )" />
+
+ <preproc:sym name="{@yields}" type="rate"
+ extclass="{$external}" keep="{boolean( @keep )}"
+ local="{@local}" dtype="float" dim="0" tex="{@sym}" />
+
+ <xsl:apply-templates mode="preproc:symtable" />
+</xsl:template>
+
+
+<xsl:template match="lv:const" mode="preproc:symtable" priority="5">
+ <xsl:variable name="dim">
+ <xsl:choose>
+ <!-- TODO: matrix/vector predicate to support either type via
+ @values -->
+ <xsl:when test="./lv:set or @values">
+ <xsl:text>2</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="./lv:item">
+ <xsl:text>1</xsl:text>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text>0</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <!-- TODO: remove magic support -->
+ <preproc:sym name="{@name}"
+ magic="{boolean( @magic='true' )}"
+ type="const" dtype="{@type}" dim="{$dim}" desc="{@desc}" tex="{@sym}">
+
+ <!-- may or may not exist -->
+ <xsl:sequence select="@value" />
+ </preproc:sym>
+
+ <!-- for performance, we will not recurse any further; the rest are simply
+ data declarations -->
+</xsl:template>
+
+
+<xsl:template match="c:*[ @generates ]" mode="preproc:symtable" priority="5">
+ <xsl:variable name="parent" select="ancestor::lv:rate" />
+
+ <preproc:sym name="{@generates}" keep="{boolean( $parent/@keep )}"
+ parent="{$parent/@yields}"
+ type="gen" dtype="float" dim="1" desc="{@desc}" tex="{@sym}" />
+
+ <xsl:apply-templates mode="preproc:symtable" />
+</xsl:template>
+
+
+<!-- note the @dim value; this is determined later from its dependencies -->
+<xsl:template match="lv:classify" mode="preproc:symtable" priority="5">
+ <xsl:variable name="external" select="boolean( @external='true' )" />
+ <xsl:variable name="terminate" select="boolean( @terminate='true' )" />
+ <xsl:variable name="keep" select="boolean( @keep='true' )" />
+
+ <preproc:sym name=":class:{@as}"
+ extclass="{$external}" terminate="{$terminate}" keep="{$keep}"
+ type="class" dim="?" desc="{@desc}" yields="{@yields}"
+ orig-name="{@as}">
+
+ <!-- copy preprocessor metadata to symbol for easy reference -->
+ <xsl:sequence select="@preproc:*" />
+ </preproc:sym>
+
+ <!-- generator if @yields is provided (note that we also have a @yields above
+ to avoid scanning separate object files for such common information)
+ -->
+ <xsl:if test="@yields">
+ <preproc:sym name="{@yields}" keep="{$keep}"
+ parent=":class:{@as}"
+ extclass="{$external}" terminate="{$terminate}"
+ type="cgen" dtype="boolean" dim="?" desc="{@desc}">
+
+ <xsl:sequence select="@preproc:*" />
+ </preproc:sym>
+ </xsl:if>
+
+ <xsl:apply-templates mode="preproc:symtable" />
+</xsl:template>
+
+
+<!-- Will be completed during post-processing so that typedefs can be
+ properly resolved -->
+<xsl:template match="lv:param" mode="preproc:symtable" priority="5">
+ <xsl:variable name="dim">
+ <xsl:call-template name="preproc:param-dim" />
+ </xsl:variable>
+
+ <!-- we use the primitive data type derived from the typedef to ensure that
+ the system can still make use of the type even when the typedef is not
+ exported; indeed, typedefs are simply restrictions that need only be
+ known for compiling (at least at present). Also note the keep="true" to
+ ensure that all param symbols are retained after linking -->
+ <preproc:sym name="{@name}" keep="true"
+ type="param" dtype="{@type}" dim="{$dim}" desc="{@desc}" tex="{@sym}" />
+</xsl:template>
+
+
+<xsl:template match="lv:typedef" mode="preproc:symtable" priority="5">
+ <!-- FIXME: this is a kluge -->
+ <xsl:variable name="dtype" as="xs:string?"
+ select="if ( lv:base-type ) then
+ @name
+ else
+ lv:enum/@type
+ , lv:union/lv:typedef[1]/lv:enum/@type" />
+
+ <xsl:if test="not( $dtype )">
+ <xsl:message terminate="yes">
+ <xsl:text>[preproc/symtable] internal error: </xsl:text>
+ <xsl:text>failed to resolve type primitve of `</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>'</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <preproc:sym name="{@name}" dtype="{$dtype}"
+ type="type" dim="0" desc="{@desc}" />
+
+ <xsl:apply-templates mode="preproc:symtable" />
+</xsl:template>
+
+
+<xsl:template match="lv:typedef/lv:enum/lv:item" mode="preproc:symtable" priority="5">
+ <xsl:variable name="dtype" select="parent::lv:enum/@type" />
+
+ <preproc:sym name="{@name}" value="{@value}"
+ type="const" dtype="{$dtype}" dim="0" desc="{@desc}" />
+</xsl:template>
+
+
+<xsl:template match="lv:function" mode="preproc:symtable" priority="5">
+ <!-- default TeX symbol to the function name -->
+ <xsl:variable name="tex">
+ <xsl:choose>
+ <xsl:when test="@sym">
+ <xsl:value-of select="@sym" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text>\textrm{</xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>}</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <!-- TODO: determine return data type from tail -->
+ <!-- TODO: same for dim -->
+ <!-- functions can have circular dependencies (recursion) -->
+ <preproc:sym name="{@name}" type="func" dtype="float" dim="0" desc="{@desc}"
+ tex="{$tex}" allow-circular="true">
+
+ <!-- we need to include the argument order and symbol refs so that the
+ compiler knows how to call the function -->
+ <xsl:variable name="fname" select="@name" />
+ <xsl:for-each select="lv:param">
+ <preproc:sym-ref name=":{$fname}:{@name}" />
+ </xsl:for-each>
+ </preproc:sym>
+
+ <xsl:apply-templates mode="preproc:symtable" />
+</xsl:template>
+
+
+<!--
+ Function parameters are local to the function and are represented differently
+ in the symbol table than most other symbols. In particular:
+ - They have type lparam, not param
+ - Their name begins with a colon, which is normally invalid (ensuring that
+ there will be no naming conflicts)
+ - The name following the colon is the concatenation of the function name,
+ an underscore and the param name
+-->
+<xsl:template match="lv:function/lv:param" mode="preproc:symtable" priority="6">
+ <!-- determine number of dimensions -->
+ <xsl:variable name="dim">
+ <xsl:call-template name="preproc:param-dim" />
+ </xsl:variable>
+
+ <xsl:variable name="fname" select="parent::lv:function/@name" />
+
+ <preproc:sym name=":{$fname}:{@name}" parent="{$fname}" varname="{@name}"
+ type="lparam" dtype="{@type}" dim="{$dim}" desc="{@desc}" tex="{@sym}">
+
+ <!-- may or may not be defined -->
+ <xsl:sequence select="@default" />
+ </preproc:sym>
+</xsl:template>
+
+
+<!--
+ Same concept as function params
+-->
+<xsl:template match="c:let/c:values/c:value" mode="preproc:symtable" priority="5">
+ <xsl:variable name="name" select="@name" />
+
+ <!-- determine number of dimensions -->
+ <xsl:variable name="dim">
+ <xsl:call-template name="preproc:param-dim" />
+ </xsl:variable>
+
+ <!-- the name is generated automatically by the preprocessor; the user cannot
+ set it -->
+ <xsl:variable name="lname" select="
+ ancestor::c:let[
+ c:values/c:value[ @name=$name ]
+ ]/@name
+ " />
+
+ <preproc:sym name=":{$lname}:{@name}" local="true" varname="{@name}"
+ type="lparam" dtype="{@type}" dim="{$dim}" desc="{@desc}" tex="{@sym}" />
+
+ <xsl:apply-templates mode="preproc:symtable" />
+</xsl:template>
+
+
+<xsl:template match="lv:extern" mode="preproc:symtable" priority="5">
+ <preproc:sym desc="{@name} extern" extern="true" missing="{@missing}">
+ <!-- copy all the user-supplied params -->
+ <xsl:sequence select="@*" />
+ </preproc:sym>
+</xsl:template>
+
+
+<xsl:template match="lv:meta" mode="preproc:symtable" priority="5">
+ <xsl:for-each select="lv:prop">
+ <preproc:sym name=":meta:{@name}" type="meta"
+ keep="true" />
+ </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template match="preproc:sym[ @type='param' ]" mode="preproc:symtable-complete" priority="5">
+ <xsl:param name="syms" as="element( preproc:sym )*" />
+
+ <!-- attempt to derive type information from a typedef -->
+ <!-- TODO: also check symbol table after import (post-process) -->
+ <xsl:variable name="type" select="@dtype" />
+ <xsl:variable name="typedef" as="element( preproc:sym )?"
+ select="$syms[ @type = 'type'
+ and @name = $type ]" />
+
+ <xsl:if test="not( $typedef and $typedef/@dtype )">
+ <xsl:message terminate="yes">
+ <xsl:text>[preproc/symtable] internal error: </xsl:text>
+ <xsl:text>failed to resolve type: </xsl:text>
+ <xsl:value-of select="$type" />
+ </xsl:message>
+ </xsl:if>
+
+ <!-- complete datatype with primitive -->
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+ <xsl:attribute name="dtype" select="$typedef/@dtype" />
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template match="*" mode="preproc:symtable-complete" priority="1">
+ <!-- symbol does not need completion -->
+ <xsl:sequence select="." />
+</xsl:template>
+
+<!--
+ Determines param dimension from its string definition:
+ vector = 1-dimensional;
+ matrix = 2-dimensional;
+ otherwise, scalar = 0-dimensional
+
+ Other dimensions are certainly supported, but @set's syntax does not support
+ their specification.
+-->
+<xsl:template name="preproc:param-dim">
+ <xsl:choose>
+ <xsl:when test="@set = 'vector'">
+ <xsl:text>1</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="@set = 'matrix'">
+ <xsl:text>2</xsl:text>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text>0</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/preproc/template.xsl b/src/current/include/preproc/template.xsl
new file mode 100644
index 0000000..e1e8edb
--- /dev/null
+++ b/src/current/include/preproc/template.xsl
@@ -0,0 +1,1149 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Performs template processing and expansion
+-->
+
+<xsl:stylesheet version="2.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:t="http://www.lovullo.com/rater/apply-template"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:ext="http://www.lovullo.com/ext"
+ xmlns:util="http://www.lovullo.com/util"
+ xmlns:eseq="http://www.lovullo.com/tame/preproc/expand/eseq"
+ exclude-result-prefixes="xs ext eseq lv util">
+
+<xsl:import href="../../tame/src/preproc/expand/expand-sequence.xsl" />
+
+
+<!--
+ Macro that abstracts away the boilerplate template application code when
+ dealing with a single root template
+
+ This macro will cause another macro expansion pass.
+-->
+<xsl:template match="lv:rate-each-template" mode="preproc:macros" priority="5">
+ <!-- TODO: debug flag
+ <xsl:message>
+ <xsl:text>[preproc] expanding rate-each-template </xsl:text>
+ <xsl:value-of select="@yields" />
+ <xsl:text>...</xsl:text>
+ </xsl:message>
+ -->
+
+ <lv:rate-each>
+ <!-- copy all attributes except for those we will explicitly handle below -->
+ <xsl:sequence select="@*[
+ not( local-name() = 'name' )
+ ]" />
+
+ <!-- since the entire body is composed from a template, we do not need to
+ accept an index from the user; traditionally, we use 'k' to leave
+ indexes like 'i' and 'j' open -->
+ <xsl:variable name="index">
+ <xsl:text>k</xsl:text>
+ </xsl:variable>
+
+ <xsl:attribute name="index">
+ <xsl:value-of select="$index" />
+ </xsl:attribute>
+
+ <!-- any lv:* nodes should be placed at the top -->
+ <xsl:sequence select="./lv:class" />
+
+ <!-- the template is expected to have an @index@ parameter -->
+ <lv:apply-template name="{@name}">
+ <lv:with-param name="@index@" value="{$index}" />
+
+ <!-- copy any user-provided params into the template application -->
+ <xsl:sequence select="./lv:with-param" />
+ </lv:apply-template>
+ </lv:rate-each>
+
+ <!-- since we generated another preprocessor macro (lv:rate-each), notify the
+ system that we will need to make another pass -->
+ <preproc:repass tpl="{@name}" />
+</xsl:template>
+
+
+<!--
+ If the symbol table is not yet available, defer short-hand
+ applications for now
+
+ It is far less costly to leave the node alone than it is to process
+ and copy potentially massive trees only to have to repass anyway.
+-->
+<xsl:template mode="preproc:macros" priority="9"
+ match="t:*[ not( root(.)/preproc:symtable ) ]">
+ <xsl:sequence select="." />
+ <preproc:repass need-sym="true" />
+</xsl:template>
+
+
+<!--
+ Converts shorthand template applications into full template expansions
+
+ TODO: This causes an extra pass; we'd like to avoid having to do that.
+-->
+<xsl:template match="t:*" mode="preproc:macros" priority="5">
+ <!-- TODO: debug flag
+ <xsl:message>
+ <xsl:text>[preproc] expanding template shorthand for </xsl:text>
+ <xsl:value-of select="local-name()" />
+ <xsl:text>...</xsl:text>
+ </xsl:message>
+ -->
+
+ <xsl:variable name="name" as="xs:string"
+ select="concat( '_', local-name(), '_' )" />
+
+ <xsl:variable name="params" as="element( lv:with-param )*">
+ <xsl:for-each select="@*">
+ <lv:with-param name="@{local-name()}@" value="{.}" />
+ </xsl:for-each>
+
+ <!-- there may be existing lv:with-param nodes -->
+ <xsl:sequence select="./lv:with-param" />
+
+ <xsl:variable name="paramnodes"
+ select="*[ not( local-name() = 'with-param' ) ]" />
+
+ <!-- if sub-nodes were provided, pass it as the "@values@" param -->
+ <xsl:if test="$paramnodes">
+ <lv:with-param name="@values@">
+ <xsl:sequence select="$paramnodes" />
+ </lv:with-param>
+ </xsl:if>
+ </xsl:variable>
+
+ <!-- XXX: a large chunk of this is duplicate code; factor out -->
+ <xsl:variable name="tpl" as="element( lv:template )?"
+ select="preproc:locate-template( $name, root( . ) )" />
+
+ <xsl:variable name="src-root" as="element( lv:package )"
+ select="if ( root(.)/lv:package ) then
+ root(.)/lv:package
+ else
+ root(.)" />
+
+ <xsl:choose>
+ <xsl:when test="$tpl">
+ <!-- avoid a costly repass; apply immediately -->
+ <xsl:sequence select="preproc:expand-template(
+ $tpl, $src-root, $params, . )" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <preproc:error>Undefined template <xsl:value-of select="$name" /></preproc:error>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:function name="preproc:locate-template"
+ as="element( lv:template )?">
+ <xsl:param name="name" as="xs:string" />
+ <xsl:param name="root" as="element( lv:package )" />
+
+ <xsl:variable name="sym" as="element( preproc:sym )?"
+ select="$root/preproc:symtable/preproc:sym[
+ @name = $name ]" />
+
+ <xsl:variable name="package" as="element( lv:package )?"
+ select="if ( $sym/@src ) then
+ document( concat( $sym/@src, '.xmlo' ), $__entry-root )
+ /lv:package
+ else
+ $root/lv:package" />
+
+ <!-- legacy lookup for inline-templates; needs to regenerate symbol
+ list, then this can be removed -->
+ <xsl:variable name="inline-match" as="element( lv:template )?"
+ select="$root//lv:template[ @name = $name ]" />
+
+ <xsl:sequence select="if ( $inline-match ) then
+ $inline-match
+ else
+ $package//lv:template[ @name=$name ]" />
+</xsl:function>
+
+
+
+<!--
+ Applies a template in place as if it were pasted directly into the XML in that
+ location
+
+ This works much like a C macro and is intended to be a very simple means of
+ code re-use that permits free construction of lv:rate blocks. See XSD
+ documentation.
+
+ It is *very important* that these macros be expanded before the templates
+ themselves are removed from the XML by further processing.
+
+ Note that if the attribute shorthand is used for params, one extra expansion
+ will have to occur, which is an additional performance hit.
+-->
+<xsl:template match="lv:apply-template[
+ @name=root(.)/preproc:symtable/preproc:sym/@name ]
+ |lv:apply-template[ @name=root(.)//lv:template/@name ]"
+ mode="preproc:macros" priority="6">
+
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="attrparams" select="@*[ not( local-name() = 'name' ) ]" />
+
+ <!-- used for type checking -->
+ <xsl:variable name="root" as="element( lv:package )"
+ select="if ( root( . ) instance of document-node() ) then
+ root( . )/lv:package
+ else
+ root( . )" />
+
+ <xsl:variable name="src-root" as="element( lv:package )"
+ select="if ( $root/lv:package ) then
+ $root/lv:package
+ else
+ $root" />
+
+ <xsl:variable name="tpl" as="element( lv:template )?"
+ select="preproc:locate-template( $name, $root )" />
+
+ <xsl:choose>
+ <xsl:when test="exists( $tpl ) and $attrparams">
+ <xsl:message>
+ <xsl:text>[preproc] expanding template parameters for </xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>...</xsl:text>
+ </xsl:message>
+
+ <xsl:variable name="params" as="element( lv:with-param )*">
+ <xsl:for-each select="$attrparams">
+ <lv:with-param name="@{local-name()}@" value="{.}" />
+ </xsl:for-each>
+
+ <!-- there may also be non-shorthand params -->
+ <xsl:sequence select="lv:with-param" />
+ </xsl:variable>
+
+ <!-- immediately apply without a wasteful repass -->
+ <xsl:sequence select="preproc:expand-template(
+ $tpl, $src-root, $params, . )" />
+ </xsl:when>
+
+ <xsl:when test="$tpl">
+ <xsl:sequence select="preproc:expand-template(
+ $tpl, $src-root, lv:with-param, . )" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <preproc:error>Undefined template <xsl:value-of select="$name" /></preproc:error>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:function name="preproc:expand-template">
+ <xsl:param name="tpl" as="element( lv:template )" />
+ <xsl:param name="src-root" />
+ <xsl:param name="params" as="element( lv:with-param )*" />
+ <xsl:param name="context" as="node()" />
+
+ <xsl:variable name="name" as="xs:string"
+ select="$tpl/@name" />
+
+ <!-- TODO: debug flag
+ <xsl:message>
+ <xsl:text>[preproc] applying template </xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text>...</xsl:text>
+ </xsl:message>
+ -->
+
+ <!-- check to ensure that each given argument is defined, unless @strict
+ is false -->
+ <xsl:for-each select="
+ $params[
+ not( @name=$tpl/lv:param/@name )
+ and not( @strict='false' )
+ ]
+ ">
+ <preproc:error>
+ <xsl:text>undefined template param </xsl:text>
+ <xsl:value-of select="$name" />/<xsl:value-of select="@name" />
+ <xsl:text>; available params are </xsl:text>
+
+ <xsl:for-each select="$tpl/lv:param/@name">
+ <xsl:if test="position() > 1">
+ <xsl:text>; </xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="." />
+ </xsl:for-each>
+ </preproc:error>
+ </xsl:for-each>
+
+ <!-- replace this node with a copy of all the child nodes of the given
+ template; this inlines it as if it were copied and pasted directly
+ into the XML, much like a C macro -->
+ <xsl:apply-templates
+ select="$tpl[ 1 ]/*"
+ mode="preproc:apply-template">
+
+ <xsl:with-param name="apply" select="$context"
+ tunnel="yes" />
+ <xsl:with-param name="apply-tpl-name" select="$name"
+ tunnel="yes" />
+ <xsl:with-param name="params" select="$params"
+ tunnel="yes" />
+
+ <xsl:with-param name="first-child" select="true()" />
+ <xsl:with-param name="src-root" select="$src-root"
+ tunnel="yes" />
+ </xsl:apply-templates>
+
+ <!-- since templates can include anything, we should perform another pass
+ to be sure that all macros that this template may contain/generate
+ are expanded -->
+ <preproc:repass tpl="{$name}" />
+ <preproc:tpl-step name="{$name}" type="apply-template" />
+</xsl:function>
+
+
+
+<!--
+ An inline template implicitly defines and then immediately applies a template
+ with an optional looping construct
+-->
+<xsl:template match="lv:inline-template" mode="preproc:macros" priority="5">
+ <xsl:variable name="name" select="concat( '___i', generate-id(.), '___' )" />
+ <xsl:variable name="inline" select="." />
+
+ <xsl:message>
+ <xsl:text>[preproc] preparing inline template </xsl:text>
+ <xsl:value-of select="$name" />
+ </xsl:message>
+
+ <!-- generate template -->
+ <lv:template name="{$name}" desc="Inline template" preproc:from-inline="{$name}">
+ <!-- generate params (from both our own attrs and any for-each sets) -->
+ <xsl:variable name="params">
+ <params>
+ <xsl:for-each select="@*, lv:for-each/lv:set/@*">
+ <!-- manual lv:param's will override default param generation -->
+ <xsl:if test="not( local-name() = $inline/lv:param/@name )">
+ <lv:param name="@{local-name()}@" desc="Generated param" />
+ </xsl:if>
+ </xsl:for-each>
+
+ <xsl:if test="lv:for-each/lv:sym-set">
+ <lv:param name="@sym_name@" desc="Symbol name" />
+ <lv:param name="@sym_type@" desc="Symbol type" />
+ <lv:param name="@sym_dim@" desc="Symbol degree (dimensions)" />
+ <lv:param name="@sym_desc@" desc="Symbol description (if any)" />
+ <lv:param name="@sym_yields@" desc="Symbol yield name (if any)" />
+ <lv:param name="@sym_parent@" desc="Symbol parent (if any)" />
+ <lv:param name="@sym_external@" desc="Symbol external to classifier" />
+ </xsl:if>
+ </params>
+ </xsl:variable>
+
+ <!-- use only unique params from each attribute source -->
+ <xsl:sequence select="
+ $params//lv:param[
+ not( @name=preceding-sibling::lv:param/@name )
+ ]
+ " />
+
+ <!-- include any params priovided by the user (they may be used to
+ generate content) -->
+ <xsl:sequence select="lv:param" />
+
+ <!-- copy template body -->
+ <!-- FIXME: do not use local-name here; use instance of -->
+ <xsl:sequence select="*[ not( local-name() = 'for-each' ) ]" />
+ </lv:template>
+
+ <xsl:choose>
+ <xsl:when test="lv:for-each">
+ <xsl:apply-templates select="lv:for-each/lv:*" mode="preproc:inline-apply">
+ <xsl:with-param name="name" select="$name" />
+ </xsl:apply-templates>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:apply-templates select="." mode="preproc:inline-apply">
+ <xsl:with-param name="name" select="$name" />
+ </xsl:apply-templates>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <!-- the next pass will perform the template application -->
+ <preproc:repass tpl="{$name}" />
+</xsl:template>
+
+
+<xsl:template match="lv:inline-template|lv:for-each/lv:set" mode="preproc:inline-apply">
+ <xsl:param name="name" />
+
+ <!-- immediately apply the template -->
+ <lv:apply-template name="{$name}">
+ <!-- each attribute will be considered to be a template param (and any
+ parent lv:inline-template attributes will be added to each and every
+ set) -->
+ <xsl:for-each select="@*|ancestor::lv:inline-template/@*">
+ <lv:with-param name="@{local-name()}@" value="{.}" />
+ </xsl:for-each>
+ </lv:apply-template>
+</xsl:template>
+
+
+<xsl:template mode="preproc:inline-apply"
+ match="lv:for-each/lv:sym-set">
+ <xsl:param name="name" />
+
+ <xsl:param name="src-root" as="element( lv:package )"
+ select="root(.)"
+ tunnel="yes" />
+
+ <!-- TODO: moar predicates! -->
+ <xsl:variable name="syms" as="element( preproc:sym )*"
+ select="$src-root/preproc:symtable/preproc:sym[
+ ( not( current()/@type )
+ or @type = current()/@type )
+ and ( not( current()/@yields )
+ or @yields = current()/@yields )
+ and ( not( current()/@parent )
+ or @parent = current()/@parent )
+ and ( not( current()/@external )
+ or @external = current()/@external )
+ and ( not( current()/@imports = 'true' )
+ or not( @src ) )
+ and ( not( current()/@name-prefix )
+ or substring( @name,
+ 1,
+ string-length(current()/@name-prefix ) )
+ = current()/@name-prefix
+ or substring( @orig-name,
+ 1,
+ string-length(current()/@name-prefix ) )
+ = current()/@name-prefix ) ]" />
+
+ <xsl:for-each select="$syms">
+ <!-- some symbols are modified to include a prefix; these internal
+ details should not be exposed to the user, since they are
+ useless within the DSL itself -->
+ <xsl:variable name="name-strip"
+ select="substring-after(
+ substring-after( @name, ':' ),
+ ':' )" />
+
+ <xsl:variable name="sym-name"
+ select="if ( $name-strip ) then
+ $name-strip
+ else
+ @name" />
+
+ <lv:apply-template name="{$name}">
+ <lv:with-param name="@sym_name@" value="{$sym-name}" />
+ <lv:with-param name="@sym_type@" value="{@type}" />
+ <lv:with-param name="@sym_dim@" value="{@dim}" />
+ <lv:with-param name="@sym_desc@" value="{@desc}" />
+ <lv:with-param name="@sym_yields@" value="{@yields}" />
+ <lv:with-param name="@sym_parent@" value="{@parent}" />
+ <lv:with-param name="@sym_external@" value="{@external}" />
+ </lv:apply-template>
+ </xsl:for-each>
+</xsl:template>
+
+
+<!--
+ This block is used when we attempt to apply a template that has not been
+ defined
+-->
+<xsl:template match="lv:apply-template" mode="preproc:macros" priority="5">
+ <!-- keep this application around for later -->
+ <xsl:sequence select="." />
+
+ <!-- nothing we can do yet -->
+ <xsl:message>
+ <xsl:text>[preproc] deferring application of unknown template </xsl:text>
+ <xsl:value-of select="@name" />
+ </xsl:message>
+
+ <preproc:repass need-sym="{@name}" />
+</xsl:template>
+
+
+<xsl:template match="lv:template/lv:param" mode="preproc:apply-template" priority="5">
+ <xsl:param name="first-child" select="false()" />
+
+ <!-- do not copy the template params for the template being applied; that
+ could result in some potentially inteesting bugs -->
+ <xsl:if test="not( $first-child )">
+ <xsl:sequence select="." />
+ </xsl:if>
+</xsl:template>
+
+
+<!--
+ Preprocesses template nodes
+
+ Currently, only attributes will be processed. Otherwise, the template ends up
+ recursing on all children to process all attributes.
+-->
+<xsl:template match="*" mode="preproc:apply-template" priority="1">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()"
+ mode="preproc:apply-template" />
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template match="lv:param-meta" mode="preproc:apply-template" priority="5">
+ <xsl:param name="apply" as="node()"
+ tunnel="yes" />
+
+ <!-- determine the value -->
+ <xsl:variable name="value">
+ <xsl:call-template name="preproc:template-param-value">
+ <xsl:with-param name="name" select="@value" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <preproc:tpl-meta name="{@name}" value="{$value}" />
+</xsl:template>
+
+
+<!--
+ Copies child nodes associated with the param during application into the
+ replacement
+
+ This effectively allows the definition of custom node types.
+-->
+<xsl:template match="lv:param-copy" mode="preproc:apply-template" priority="5">
+ <xsl:param name="params" as="element( lv:with-param )*"
+ tunnel="yes" />
+
+ <!-- if any metadata has been defined, retain it so that it may be queried by
+ future templates -->
+ <xsl:apply-templates mode="preproc:apply-template"
+ select="lv:param-meta" />
+
+ <xsl:variable name="varname" select="@name" />
+
+ <!-- determine the nodes to copy -->
+ <xsl:variable name="copy"
+ select="$params[ @name=$varname ]/*" />
+
+ <xsl:choose>
+ <!-- if the @expand flag is set, then immediately begin expanding any
+ template params that it may have (that we know of), in effect making
+ the body of the template application *part* of the template itself -->
+ <xsl:when test="@expand='true'">
+ <xsl:message>[preproc] expanding param-copy...</xsl:message>
+ <xsl:apply-templates select="$copy" mode="preproc:apply-template">
+ </xsl:apply-templates>
+ </xsl:when>
+
+ <!-- by default, expansion is not requested, meaning that no template param
+ expansion will take place (on this pass) for the copied nodes; if any
+ template params exist, they will be handled on the next pass -->
+ <xsl:otherwise>
+ <xsl:sequence select="$copy" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template match="lv:dyn-node" mode="preproc:apply-template" priority="5">
+ <xsl:variable name="dyn-name">
+ <xsl:call-template name="preproc:template-param-value">
+ <xsl:with-param name="name" select="@name" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:element name="{$dyn-name}">
+ <xsl:apply-templates mode="preproc:apply-template" />
+ </xsl:element>
+</xsl:template>
+
+
+<!--
+ Display an arbitrary error to the user during compilation
+
+ This produces a compile-time error and immediately halts
+ compilation.
+-->
+<xsl:template mode="preproc:apply-template" priority="5"
+ match="lv:error">
+ <xsl:param name="apply-tpl-name" as="xs:string"
+ tunnel="yes" />
+
+ <xsl:variable name="message">
+ <xsl:apply-templates mode="preproc:gen-param-value" />
+ </xsl:variable>
+
+ <preproc:error>
+ <xsl:value-of select="$apply-tpl-name" />
+ <xsl:text>: </xsl:text>
+ <xsl:value-of select="normalize-space( $message )" />
+ </preproc:error>
+</xsl:template>
+
+
+<!--
+ Display an arbitrary warning to the user during compilation
+
+ This produces a compile-time warning that is purely informational
+ and does not halt compilation. It is intended to point out
+ undesirable conditions.
+-->
+<xsl:template mode="preproc:apply-template" priority="5"
+ match="lv:warning">
+ <xsl:param name="apply-tpl-name" as="xs:string"
+ tunnel="yes" />
+
+ <xsl:variable name="message">
+ <xsl:apply-templates mode="preproc:gen-param-value" />
+ </xsl:variable>
+
+ <xsl:message>
+ <xsl:text>warning: </xsl:text>
+ <xsl:value-of select="$apply-tpl-name" />
+ <xsl:text>: </xsl:text>
+ <xsl:value-of select="normalize-space( $message )" />
+ </xsl:message>
+</xsl:template>
+
+
+<xsl:template mode="preproc:apply-template" priority="5"
+ match="text()">
+ <xsl:value-of select="." />
+</xsl:template>
+
+
+<!--
+ Basic conditional support within templates
+
+ Simple concept, powerful consequences.
+
+ ***No recursion limit check...TODO
+-->
+<xsl:template match="lv:if|lv:unless" mode="preproc:apply-template" priority="5">
+ <xsl:param name="apply-tpl-name" as="xs:string"
+ tunnel="yes" />
+
+ <xsl:choose>
+ <!-- if the param is unknown, retain; it may be intended for a generated
+ template -->
+ <xsl:when test="
+ not(
+ @name=ancestor::lv:template[
+ @name=$apply-tpl-name
+ ]/lv:param/@name
+ )
+ ">
+ <xsl:copy>
+ <xsl:sequence select="@*" />
+
+ <xsl:apply-templates select="*" mode="preproc:apply-template" />
+ </xsl:copy>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <!-- calculate the param value -->
+ <xsl:variable name="param-value">
+ <xsl:call-template name="preproc:template-param-value">
+ <xsl:with-param name="name" select="@name" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <!-- @value value -->
+ <xsl:variable name="cmp-value">
+ <xsl:call-template name="preproc:template-param-value">
+ <xsl:with-param name="name" select="@*[ not( local-name() = 'name' ) ]" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:apply-templates select="." mode="preproc:apply-template-cmp">
+ <xsl:with-param name="param-value" select="$param-value" />
+ <xsl:with-param name="cmp-value" select="$cmp-value" />
+
+ <xsl:with-param name="negate">
+ <xsl:choose>
+ <xsl:when test="local-name() = 'if'">
+ <xsl:value-of select="false()" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:value-of select="true()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:with-param>
+ </xsl:apply-templates>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template match="lv:*[@eq]" mode="preproc:apply-template-cmp" priority="5">
+ <xsl:param name="negate" select="false()" />
+ <xsl:param name="param-value" />
+ <xsl:param name="cmp-value" />
+
+ <xsl:if test="
+ ( ( $negate = 'true' ) and not( $param-value = $cmp-value ) )
+ or ( ( $negate = 'false' ) and ( $param-value = $cmp-value ) )
+ ">
+
+ <xsl:apply-templates select="*" mode="preproc:apply-template" />
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template match="lv:*[not(@*[not(local-name()='name')])]" mode="preproc:apply-template-cmp" priority="2">
+ <xsl:param name="negate" select="'false'" />
+ <xsl:param name="param-value" />
+ <xsl:param name="cmp-value" />
+
+ <!-- TODO: This is convoluted...we "know" it's empty because it'll return its
+ own name as a value by default... -->
+ <xsl:if test="
+ ( ( $negate = 'true' ) and ( $param-value = @name ) )
+ or ( ( $negate = 'false' ) and not( $param-value = @name ) )
+ ">
+
+ <xsl:apply-templates select="*" mode="preproc:apply-template" />
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="lv:*" mode="preproc:apply-template-cmp" priority="1">
+ <preproc:error>
+ <xsl:text>Unknown template comparison attribute for </xsl:text>
+ <xsl:value-of select="name()" />
+ <xsl:text> in </xsl:text>
+ <xsl:value-of select="ancestor::lv:template/@name" />
+ <xsl:text>:</xsl:text>
+
+ <xsl:for-each select="@*">
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="local-name()" />
+ <xsl:text>="</xsl:text>
+ <xsl:value-of select="." />
+ <xsl:text>"</xsl:text>
+ </xsl:for-each>
+ </preproc:error>
+</xsl:template>
+
+
+<xsl:template mode="preproc:gen-param-value" priority="5"
+ match="lv:param-add">
+ <!-- calculate the param value -->
+ <xsl:variable name="param-value">
+ <xsl:call-template name="preproc:template-param-value">
+ <xsl:with-param name="name" select="@name" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:value-of select="number($param-value) + number(@value)" />
+</xsl:template>
+
+
+<!--
+ Process template attributes
+
+ Provides primitive parameter support. If a parameter is found (convention is
+ that it must begin and end with '@', but that convention is not enforced
+ here), it is replaced by the value given by the calling lv:apply-template.
+
+ Note that we currently do not perform any string replacements. As such, we
+ only support full replacement of an attribute (that is, the attribute must
+ contain only a parameter, not a parameter as part of a larger string); it is
+ for this reason that the convention of beginning and ending with '@' arose: it
+ allows us to perform substring replacements later on with clear delimiters.
+
+ TODO: substring replacement for added flexibility
+-->
+<xsl:template match="@*" mode="preproc:apply-template" priority="5">
+ <xsl:variable name="name" select="local-name()" />
+ <xsl:variable name="varname" select="." />
+
+ <!-- compile param value -->
+ <xsl:variable name="value">
+ <xsl:call-template name="preproc:template-param-value">
+ <xsl:with-param name="name" select="$varname" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <!-- if the result is an empty string, then do not output the attribute (this
+ allows for conditional attributes -->
+ <xsl:if test="not( $value = '' )">
+ <xsl:attribute name="{$name}" select="$value" />
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template match="lv:with-param/@name" mode="preproc:apply-template" priority="9">
+ <!-- do not do any sort of expansion of recursive template param names -->
+ <xsl:copy />
+</xsl:template>
+
+
+<xsl:template name="preproc:template-param-value">
+ <xsl:param name="name" />
+ <xsl:param name="params" as="element( lv:with-param )*"
+ tunnel="yes" />
+
+ <xsl:variable name="after" select="substring-after( $name, '@' )" />
+
+ <!-- TODO: support multiple @vars@ per attribute -->
+ <xsl:choose>
+ <xsl:when test="$name = ''">
+ <!-- we're done; nothing more to do -->
+ </xsl:when>
+
+ <!-- no vars; just output and abort -->
+ <xsl:when test="not( $after )">
+ <xsl:value-of select="$name" />
+ </xsl:when>
+
+ <!-- if the variable is inline, output the value up until the inline
+ delimiter (curly brace); this supports inline vars at any point in the
+ string -->
+ <xsl:when test="not( starts-with( $name, '@' ) )">
+ <!-- this might be nothing (if we start with a curly brace) -->
+ <xsl:value-of select="substring-before( $name, '{' )" />
+
+ <!-- get the param between {} -->
+ <xsl:variable name="param"
+ select="substring-before( substring-after( $name, '{' ), '}' )" />
+
+ <!-- if a param was found, process it -->
+ <xsl:if test="$param">
+ <xsl:variable name="result">
+ <xsl:call-template name="preproc:template-param-value">
+ <xsl:with-param name="name" select="$param" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <!-- if the result is the same as the param name, then it was not found;
+ re-enclose in braces so that it can be processed later (where we
+ may find a value) -->
+ <xsl:choose>
+ <xsl:when test="$result = $param">
+ <xsl:text>{</xsl:text>
+ <xsl:value-of select="$result" />
+ <xsl:text>}</xsl:text>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:value-of select="$result" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+
+ <!-- recurse to generate the remainder of the string -->
+ <xsl:call-template name="preproc:template-param-value">
+ <xsl:with-param name="name" select="substring-after( $name, '}' )" />
+ </xsl:call-template>
+ </xsl:when>
+
+ <!-- starts with a macro param -->
+ <xsl:otherwise>
+ <!-- get the param, since we may have additional text following it -->
+
+ <!-- get the value of this parameter, if it exists, from the caller (note
+ below that we will consider a value of the same name as the param to
+ be undefined, allowing defaults to be generated; this is useful when
+ proxying params between templates)-->
+ <xsl:variable name="val"
+ select="$params[ @name=$name ]/@value" />
+
+ <!-- the param node itself -->
+ <xsl:variable name="param"
+ select="ancestor::lv:template/lv:param[ @name=$name ]" />
+
+
+ <xsl:choose>
+ <!-- this test is structured to fail if the param has not been defined
+ on the templates parameter list; this is a restriction imposed
+ purely for documentation; the preprocessor can do just fine without
+ -->
+ <xsl:when test="$val and not( $val = $name ) and $param">
+ <xsl:value-of select="$val" />
+ </xsl:when>
+
+ <!-- otherwise, if we just have the param and it has child nodes,
+ generate a value (in essence: generate a default value if one is
+ not provided) -->
+ <xsl:when test="$param and $param/lv:*">
+ <xsl:apply-templates select="$param/lv:*"
+ mode="preproc:gen-param-value" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:value-of select="$name" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template mode="preproc:gen-param-value" priority="6"
+ match="lv:param/lv:text[ @unique='true' ]">
+ <xsl:param name="apply" as="node()"
+ tunnel="yes" />
+
+ <xsl:value-of select="." />
+ <xsl:value-of select="generate-id( $apply )" />
+</xsl:template>
+
+
+<xsl:template match="lv:param/lv:text" mode="preproc:gen-param-value"
+ priority="4">
+ <xsl:value-of select="." />
+</xsl:template>
+
+
+<xsl:template mode="preproc:gen-param-value" priority="5"
+ match="lv:param/lv:param-inherit[@meta]">
+ <xsl:param name="apply" as="node()"
+ tunnel="yes" />
+
+ <xsl:variable name="name" select="@meta" />
+
+ <!-- find the metadata -->
+ <xsl:variable name="values"
+ select="$apply/ancestor::*/preceding-sibling::preproc:tpl-meta[ @name=$name ]/@value
+ , $apply/preceding-sibling::preproc:tpl-meta[ @name=$name ]/@value" />
+
+ <!-- take the last one (precedence) -->
+ <xsl:value-of select="$values[ count( $values ) ]" />
+</xsl:template>
+
+
+<xsl:template mode="preproc:gen-param-value" priority="4"
+ match="lv:param-value">
+ <xsl:param name="params" as="element( lv:with-param )*"
+ tunnel="yes" />
+
+ <!-- name of the parameter we're referencing -->
+ <xsl:variable name="pname" as="xs:string"
+ select="@name" />
+
+ <!-- the original string -->
+ <xsl:variable name="str" as="xs:string?"
+ select="$params[ @name=$pname ]/@value" />
+
+ <!-- apply @snake if need be -->
+ <xsl:variable name="processed">
+ <xsl:choose>
+ <!-- snakeify -->
+ <xsl:when test="@snake">
+ <xsl:value-of select="translate( $str, '-', '_' )" />
+ </xsl:when>
+
+ <!-- convert spaces and underscores to dashes -->
+ <xsl:when test="@dash">
+ <xsl:value-of select="translate( $str, '_ ', '--' )" />
+ </xsl:when>
+
+ <xsl:when test="@rmdash">
+ <xsl:value-of select="translate( $str, '-', '' )" />
+ </xsl:when>
+
+ <!-- do nothing -->
+ <xsl:otherwise>
+ <xsl:value-of select="$str" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <!-- perform any additional processing -->
+ <xsl:apply-templates select="." mode="preproc:gen-param-value-style">
+ <xsl:with-param name="str" select="$processed" />
+ </xsl:apply-templates>
+</xsl:template>
+
+<xsl:template match="lv:param-value[@ucfirst]" mode="preproc:gen-param-value-style" priority="5">
+ <xsl:param name="str" />
+
+ <xsl:call-template name="util:ucfirst">
+ <xsl:with-param name="str" select="$str" />
+ </xsl:call-template>
+</xsl:template>
+
+<!-- slightly higher priority than @ucfirst, since this obviously should
+ override -->
+<xsl:template match="lv:param-value[@upper]" mode="preproc:gen-param-value-style" priority="6">
+ <xsl:param name="str" />
+
+ <xsl:call-template name="util:uppercase">
+ <xsl:with-param name="str" select="$str" />
+ </xsl:call-template>
+</xsl:template>
+
+<xsl:template match="lv:param-value[@lower]" mode="preproc:gen-param-value-style" priority="6">
+ <xsl:param name="str" />
+
+ <xsl:call-template name="util:lowercase">
+ <xsl:with-param name="str" select="$str" />
+ </xsl:call-template>
+</xsl:template>
+
+<!-- convert into valid identifier name -->
+<xsl:template match="lv:param-value[@identifier]"
+ mode="preproc:gen-param-value-style" priority="6">
+ <xsl:param name="str" />
+
+ <xsl:sequence select="replace(
+ normalize-unicode( $str, 'NFC' ),
+ '[^a-zA-Z0-9_-]',
+ '' )" />
+</xsl:template>
+
+<!-- no other styling -->
+<xsl:template match="lv:param-value" mode="preproc:gen-param-value-style" priority="1">
+ <xsl:param name="str" />
+ <xsl:value-of select="$str" />
+</xsl:template>
+
+
+<!--
+ Converts class name to its @yields variable name
+-->
+<xsl:template mode="preproc:gen-param-value" priority="5"
+ match="lv:param-class-to-yields">
+ <xsl:param name="params" as="element( lv:with-param )*"
+ tunnel="yes" />
+
+ <xsl:param name="src-root" as="element( lv:package )"
+ select="root(.)"
+ tunnel="yes" />
+
+ <!-- get the class name from the param -->
+ <xsl:variable name="pname" select="@name" />
+ <xsl:variable name="as" select="$params[ @name=$pname ]/@value" />
+
+ <!-- get @yields from class -->
+ <xsl:variable name="yields" select="
+ $src-root/preproc:symtable/preproc:sym[
+ @name=concat( ':class:', $as )
+ ]/@yields
+ " />
+
+ <xsl:choose>
+ <xsl:when test="not( $yields ) or $yields=''">
+ <xsl:message>
+ <xsl:text>error: unable to determine @yields for class `</xsl:text>
+ <xsl:value-of select="$as" />
+ <xsl:text>' (has the class been imported?)</xsl:text>
+ </xsl:message>
+
+ <!-- just retain the name; it'll be used for an error message,
+ since it won't be foudn -->
+ <!-- TODO: this is dangerous; find a way to propagate the error -->
+ <xsl:value-of select="$as" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:value-of select="$yields" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template mode="preproc:gen-param-value" priority="5"
+ match="text()">
+ <xsl:value-of select="." />
+</xsl:template>
+
+
+<xsl:template mode="preproc:gen-param-value" priority="1"
+ match="node()">
+ <xsl:message terminate="yes">
+ <xsl:text>error: unknown param node content: </xsl:text>
+ <xsl:copy-of select="." />
+ </xsl:message>
+</xsl:template>
+
+
+<!-- Templates should never be expanded until they are actually replaced by
+ macro expansion using apply-templates; just keep ignoring this until it's
+ eventually removed by the expand phase -->
+<xsl:template match="lv:template" mode="preproc:macros" priority="5">
+ <xsl:sequence select="." />
+</xsl:template>
+
+
+<!--
+ expand-sequence
+
+ TODO: move to a better place
+-->
+<xsl:template mode="preproc:macros" priority="5"
+ match="lv:expand-sequence">
+ <xsl:sequence select="eseq:expand-step( . )" />
+</xsl:template>
+
+
+<!--
+ expand-group is our means of grouping together expressions to be
+ expanded as a group; this is far more efficient than expanding each
+ one individually, when that is unneeded.
+-->
+<xsl:template mode="preproc:macros" priority="5"
+ match="lv:expand-group">
+ <!-- strip expand-group -->
+ <xsl:apply-templates mode="preproc:macros" />
+</xsl:template>
+
+
+
+<xsl:function name="eseq:is-expandable" as="xs:boolean"
+ override="yes">
+ <xsl:param name="node" as="node()" />
+
+ <!-- TODO: what a mess; clean me up by changing the point at which
+ this is processed, which will expand all of these into
+ lv:apply-template -->
+ <xsl:sequence select="$node instance of element()
+ and not( $node instance of
+ element( lv:template ) )
+ and (
+ $node instance of
+ element( lv:apply-template )
+ or $node instance of
+ element( lv:inline-template )
+ or namespace-uri( $node )
+ = namespace-uri-for-prefix( 't', $node )
+ or (
+ $node//lv:inline-template,
+ $node//lv:apply-template,
+ $node//t:* )
+ [ not(
+ ancestor::lv:template
+ or ancestor::lv:apply-template ) ] )" />
+</xsl:function>
+
+
+
+<xsl:function name="eseq:expand-node" as="node()*"
+ override="yes">
+ <xsl:param name="node" as="node()" />
+
+ <xsl:apply-templates mode="preproc:macros"
+ select="$node" />
+</xsl:function>
+
+
+
+<xsl:template mode="preproc:macros" priority="9"
+ match="node()[ not( . instance of element() ) ]">
+ <xsl:sequence select="." />
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/preprocess.xsl b/src/current/include/preprocess.xsl
new file mode 100644
index 0000000..b0d8cd5
--- /dev/null
+++ b/src/current/include/preprocess.xsl
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Preprocesses the XML
+
+ This progress is aggressive; the resulting tree will follow the structure of
+ the original XML, but will be heavily augmented and some parts rewritten.
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+
+ xmlns:preproc="http://www.lovullo.com/rater/preproc"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:t="http://www.lovullo.com/rater/apply-template"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:w="http://www.lovullo.com/rater/worksheet"
+ xmlns:ext="http://www.lovullo.com/ext"
+ xmlns:util="http://www.lovullo.com/util">
+
+
+<xsl:include href="depgen.xsl" />
+<xsl:include href="preproc/package.xsl" />
+
+
+<!--
+ Raters themselves get special treatment
+-->
+<xsl:template match="lv:rater" mode="preproc:compile" priority="9">
+ <xsl:param name="orig-root" select="." />
+ <xsl:param name="stopshort" />
+
+ <xsl:message>
+ <xsl:text>[preproc] [rater]</xsl:text>
+ </xsl:message>
+
+ <!-- handle package preprocessing -->
+ <xsl:variable name="pkg-result">
+ <xsl:call-template name="preproc:pkg-compile">
+ <xsl:with-param name="orig-root" select="$orig-root" />
+ <xsl:with-param name="stopshort" select="$stopshort" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:copy-of select="$pkg-result" />
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/current/include/symbol-map.xml b/src/current/include/symbol-map.xml
new file mode 100644
index 0000000..9cf6421
--- /dev/null
+++ b/src/current/include/symbol-map.xml
@@ -0,0 +1,80 @@
+<symbol-map
+ xmlns="http://www.lovullo.com/rater/symbol-map"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.lovullo.com symbol-map.xsd">
+
+ <!-- global parameter -->
+ <symbol type="param">\Theta</symbol>
+
+ <!-- function parameter -->
+ <symbol type="fparam">\theta</symbol>
+
+ <!-- constant -->
+ <symbol type="const">C</symbol>
+
+ <!-- enum item -->
+ <symbol type="item">E</symbol>
+
+ <symbol type="classify">\kappa</symbol>
+
+ <!-- the class accumulator will accumulate the values returned by any lv:rate
+ that matches a given classification -->
+ <symbol type="class-accumulator">K</symbol>
+
+ <!-- map functions to their own name -->
+ <symbol type="function">
+ <name />
+ </symbol>
+
+ <!-- lv:rate yield (omega to denote "final result") -->
+ <symbol type="rate">\omega</symbol>
+
+ <!-- generating expressions -->
+ <symbol type="generator">G</symbol>
+
+ <symbol type="accumulator">\sigma</symbol>
+
+ <!-- typedefs should have no symbol by default; their plain-text domain can be
+ listed -->
+ <symbol type="typedef">
+ <nothing />
+ </symbol>
+
+
+ <!--
+ Explicit symbol reservations
+
+ Any symbol mentioned within this file will be disallowed from being used in
+ any @sym attribute within raters/packages.
+
+ Note that this list need not contain symbols defined elsewhere in the
+ framework. For example, symbols mentioned in symbol-map need not appear here.
+
+ Do not be overly picky with this list; include only those that are established
+ in the field of mathematics as a whole (not a specific category, unless it is
+ CS), where the symbol is almost always understood to have a particular
+ meaning. For example:
+
+ - We wouldn't want to allow \pi, since that is already established as the
+ ratio of a circle's circumference to its diameter
+ - Nor should we allow \delta, since that is commonly used in CS to represent
+ Kronecker's delta
+ - We should *not*, however, disallow \mu just because it is the Möbius
+ function in number theory
+ -->
+ <reserved>
+ <!-- commonly used as an alterative to Iverson's convention under certain
+ circumstances, so it's best to avoid the notation entirely even if it is
+ not used within the framework -->
+ <reserve sym="\delta" reason="Kronecker delta" />
+
+ <reserve sym="\pi" reason="Ratio of a circle's circumference to its diameter" />
+ <reserve sym="\phi" reason="The golden ratio (another established mathematical constant)" />
+ <reserve sym="\Sigma" reason="Summation symbol; sigma-notation" />
+ <reserve sym="\Pi" reasons="Product symbol; pi-notation" />
+
+ <!-- as common as this is in programming as an index, this is another
+ established mathematical constant (sqrt(-1)) -->
+ <reserve sym="i" reason="Imaginary number" />
+ </reserved>
+</symbol-map>
diff --git a/src/current/include/util.xsl b/src/current/include/util.xsl
new file mode 100644
index 0000000..0e0030f
--- /dev/null
+++ b/src/current/include/util.xsl
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Utility templates
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+
+ xmlns:util="http://www.lovullo.com/util"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:lvm="http://www.lovullo.com/rater/map"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:ext="http://www.lovullo.com/ext">
+
+
+<xsl:variable name="_chrlower" select="'abcdefghijklmnopqrstuvwxyz'" />
+<xsl:variable name="_chrupper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
+
+<!--
+ Path to map directory
+-->
+<xsl:param name="map-root" select="'../map/'" />
+<xsl:param name="retmap-root" select="concat( $map-root, 'return/' )" />
+
+
+<xsl:template name="util:load-package">
+ <xsl:param name="package" />
+ <xsl:param name="self" />
+
+ <xsl:variable name="path" select="concat($package, '.xml')" />
+ <xsl:variable name="pkg" select="document( $path, $self )/lv:package" />
+
+ <ext:package name="{$pkg/@name}">
+ <!-- path, including extension -->
+ <xsl:attribute name="path">
+ <xsl:value-of select="$path" />
+ </xsl:attribute>
+
+ <!-- path, excluding extension (as it appears in @package) -->
+ <xsl:attribute name="import-path">
+ <xsl:value-of select="@package" />
+ </xsl:attribute>
+
+ <xsl:copy-of select="$pkg" />
+ </ext:package>
+</xsl:template>
+
+
+<xsl:template match="lvm:*" mode="util:map-expand" priority="1">
+ <xsl:param name="path" select="'.'" />
+
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+ <xsl:apply-templates mode="util:map-expand">
+ <xsl:with-param name="path" select="$path" />
+ </xsl:apply-templates>
+ </xsl:copy>
+</xsl:template>
+
+<!-- recursively inline imports -->
+<xsl:template match="lvm:import" mode="util:map-expand" priority="5">
+ <xsl:param name="path" select="'.'" />
+
+ <xsl:apply-templates
+ select="document( concat( @path, '.xml' ), . )/lvm:*/*"
+ mode="util:map-expand">
+
+ <xsl:with-param name="path" select="concat( $path, '/', @path )" />
+ </xsl:apply-templates>
+</xsl:template>
+
+<!-- must be lower priority than lv:import -->
+<xsl:template match="/lvm:*/lvm:*" mode="util:map-expand" priority="3">
+ <xsl:param name="path" select="'.'" />
+
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+ <xsl:attribute name="__src" select="$path" />
+
+ <xsl:apply-templates mode="util:map-expand">
+ <xsl:with-param name="path" select="$path" />
+ </xsl:apply-templates>
+ </xsl:copy>
+</xsl:template>
+
+
+<!--
+ Converts first character to uppercase
+
+ Functions like ucfirst in PHP
+
+ @param string str string to ucfirst
+
+ @return string provided string with first character converted to uppercase
+-->
+<xsl:template name="util:ucfirst">
+ <xsl:param name="str" />
+
+ <!-- convert first char to uppercase -->
+ <xsl:value-of
+ select="translate( substring( $str, 1, 1 ), $_chrlower, $_chrupper )" />
+
+ <!-- remainder of string as it was provided -->
+ <xsl:value-of select="substring( $str, 2 )" />
+</xsl:template>
+
+
+<!--
+ Converts a string to uppercase
+-->
+<xsl:template name="util:uppercase">
+ <xsl:param name="str" />
+ <xsl:value-of select="translate( $str, $_chrlower, $_chrupper )" />
+</xsl:template>
+
+<!--
+ Converts a string to lowercase
+-->
+<xsl:template name="util:lowercase">
+ <xsl:param name="str" />
+ <xsl:value-of select="translate( $str, $_chrupper, $_chrlower )" />
+</xsl:template>
+
+
+<xsl:template name="util:json">
+ <xsl:param name="id" />
+ <xsl:param name="value" />
+ <xsl:param name="obj" />
+ <xsl:param name="array" />
+
+ <xsl:if test="$id">
+ <xsl:text>"</xsl:text>
+ <xsl:call-template name="util:json-escape">
+ <xsl:with-param name="string" select="$id" />
+ </xsl:call-template>
+ <xsl:text>":</xsl:text>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="$array">
+ <xsl:text>[</xsl:text>
+ <xsl:for-each select="$array/*">
+ <xsl:if test="position() > 1">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="." />
+ </xsl:for-each>
+ <xsl:text>]</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="$obj">
+ <xsl:text>{</xsl:text>
+ <xsl:for-each select="$obj/*">
+ <xsl:if test="position() > 1">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="." />
+ </xsl:for-each>
+ <xsl:text>}</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="$value">
+ <xsl:text>"</xsl:text>
+ <xsl:call-template name="util:json-escape">
+ <xsl:with-param name="string" select="$value" />
+ </xsl:call-template>
+ <xsl:text>"</xsl:text>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:message terminate="yes">[util] !!! invalid util:json</xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template name="util:json-escape">
+ <xsl:param name="string" />
+
+ <xsl:value-of select="$string" />
+</xsl:template>
+
+</xsl:stylesheet>