Liberate current implementation of "Calc DSL"
(Copyright headers will be added in the next commit; these are the original files, unaltered in any way.) The internal project name at LoVullo is simply "Calc DSL". This liberates the entire thing. If anything was missed, I'll be added later. To continue building at LoVullo with this move, symlinks are used for the transition; this is the exact code that is used in production. There is a lot here---over 25,000 lines. Much of it is in disarray from the environment surrounding its development, but it does work well for what it was intended to do. (LoVullo folks: fork point is 65723a0 in calcdsl.git.)master
parent
6c0aa54bd1
commit
ff01f39c1e
|
@ -22,7 +22,9 @@ path_src = src
|
||||||
path_test = test
|
path_test = test
|
||||||
|
|
||||||
# all source files will be run through hoxsl; see `applies' target
|
# all source files will be run through hoxsl; see `applies' target
|
||||||
apply_src := $(shell find "$(path_src)" "$(path_test)" -name '*.xsl')
|
apply_src := $(shell find "$(path_src)" "$(path_test)" \
|
||||||
|
-name '*.xsl' \
|
||||||
|
-a \! -path "$(path_src)"/current/\* )
|
||||||
apply_dest := $(apply_src:%.xsl=%.xsl.apply)
|
apply_dest := $(apply_src:%.xsl=%.xsl.apply)
|
||||||
|
|
||||||
# needed by test runner
|
# needed by test runner
|
||||||
|
|
|
@ -37,6 +37,13 @@ TAME's core library, and [hoxsl](https://github.com/lovullo/hoxsl) was
|
||||||
developed as a supporting library.
|
developed as a supporting library.
|
||||||
|
|
||||||
|
|
||||||
|
## "Current"
|
||||||
|
The current state of the project as used in production is found in
|
||||||
|
`src/current/`. The environment surrounding the development of this
|
||||||
|
project resulted in a bit of a mess, which is being refactored into
|
||||||
|
`src/` as it is touched. Documentation is virtually non-existent.
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
This program is free software: you can redistribute it and/or modify it
|
This program is free software: you can redistribute it and/or modify it
|
||||||
under the terms of the GNU General Public License as published by the Free
|
under the terms of the GNU General Public License as published by the Free
|
||||||
|
|
|
@ -21,7 +21,9 @@
|
||||||
path_src := ../src
|
path_src := ../src
|
||||||
path_tools := ../tools
|
path_tools := ../tools
|
||||||
|
|
||||||
stylesheets := $(shell find "$(path_src)" -name '*.xsl')
|
stylesheets := $(shell find "$(path_src)" \
|
||||||
|
-name '*.xsl' \
|
||||||
|
-a \! -path "$(path_src)"/current/\* )
|
||||||
stexi := $(stylesheets:.xsl=.texi)
|
stexi := $(stylesheets:.xsl=.texi)
|
||||||
|
|
||||||
info_TEXINFOS = tame.texi
|
info_TEXINFOS = tame.texi
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
!Makefile
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
.PHONY: dslc clean
|
||||||
|
|
||||||
|
dslc:
|
||||||
|
$(MAKE) -C src/ dslc
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C src/ clean
|
|
@ -0,0 +1,383 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Generates PHP code that works with the LoVullo ConceptOne import system
|
||||||
|
|
||||||
|
This map expects that the data are available in the bucket provided by the
|
||||||
|
quote and therefore validates against a provided Program UI source file. Data
|
||||||
|
external to the bucket may be provided if it is indicated as such.
|
||||||
|
|
||||||
|
Each map source file is independent; variables and values do not bleed into
|
||||||
|
one-another, unless explicitly passed.
|
||||||
|
-->
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns:c1="http://www.epic-premier.com/XMLSchema"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:lvm="http://www.lovullo.com/rater/map/c1"
|
||||||
|
xmlns:lvmp="http://www.lovullo.com/rater/map/c1/pp">
|
||||||
|
|
||||||
|
<xsl:output
|
||||||
|
indent="yes"
|
||||||
|
omit-xml-declaration="yes"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- newline -->
|
||||||
|
<xsl:variable name="lvmp:nl" select="' '" />
|
||||||
|
|
||||||
|
<xsl:include href="c1map/c1nodes.xsl" />
|
||||||
|
<xsl:include href="c1map/valparse.xsl" />
|
||||||
|
<xsl:include href="c1map/render.xsl" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Represents the root of the source document that processing was initiated upon
|
||||||
|
-->
|
||||||
|
<xsl:variable name="orig-root" select="/" />
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
The root node
|
||||||
|
-->
|
||||||
|
<xsl:template match="lvm:c1-map" priority="5">
|
||||||
|
<!-- populated by includes, if any -->
|
||||||
|
<xsl:param name="args" />
|
||||||
|
|
||||||
|
<xsl:message select="$args" />
|
||||||
|
|
||||||
|
<!-- get the name from the first C1 node -->
|
||||||
|
<xsl:variable name="name" select="
|
||||||
|
if ( @id ) then
|
||||||
|
@id
|
||||||
|
else
|
||||||
|
concat( translate( c1:*[1]/name(), '_', '' ), 'Composer' )
|
||||||
|
" />
|
||||||
|
|
||||||
|
<!-- preprocessed result -->
|
||||||
|
<xsl:variable name="pp-result">
|
||||||
|
<lvmp:root program="{@program}" name="{$name}">
|
||||||
|
<!-- introduce outer scope for variables -->
|
||||||
|
<lvmp:scope id="">
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</lvmp:scope>
|
||||||
|
</lvmp:root>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<!-- final processing -->
|
||||||
|
<xsl:variable name="result">
|
||||||
|
<xsl:apply-templates select="$pp-result/lvmp:root" mode="lvmp:render" />
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<!-- remove escapes -->
|
||||||
|
<xsl:value-of disable-output-escaping="yes" select="$result" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Include another source map file relative to the path of the original source
|
||||||
|
file
|
||||||
|
|
||||||
|
The attributes @name and @for-each are special and cannot be used as
|
||||||
|
arguments to the template. The special @for-each attribute will be copied
|
||||||
|
into each of the children of the root node in the template as @lvm:for-each.
|
||||||
|
For example, if the template consists of
|
||||||
|
|
||||||
|
<c1-map>
|
||||||
|
<Product>
|
||||||
|
</Product>
|
||||||
|
</c1-map>
|
||||||
|
|
||||||
|
then <lvm:include for-each="foo" /> would produce
|
||||||
|
|
||||||
|
<c1-map>
|
||||||
|
<Product lvm:for-each="foo">
|
||||||
|
</Product>
|
||||||
|
</c1-map>
|
||||||
|
-->
|
||||||
|
<xsl:template match="lvm:include" priority="5">
|
||||||
|
<xsl:message>[c1map] +<xsl:value-of select="@name" /></xsl:message>
|
||||||
|
|
||||||
|
<xsl:variable name="src" select="
|
||||||
|
document( concat( @name, '.xml' ), $orig-root )/lvm:c1-map
|
||||||
|
" />
|
||||||
|
|
||||||
|
<xsl:if test="not( $src )">
|
||||||
|
<xsl:message terminate="yes">fatal: c1-map node not found</xsl:message>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!-- process the body of the c1-map; we don't want to process the root node,
|
||||||
|
as that would start processing from scratch, prematurely rendering the result -->
|
||||||
|
<lvmp:scope id="/{@name}">
|
||||||
|
<!-- arguments are included as attributes -->
|
||||||
|
<xsl:variable name="args" select="
|
||||||
|
@*[ not( local-name()='name' or local-name()='for-each' ) ]
|
||||||
|
" />
|
||||||
|
<xsl:variable name="for-each" select="@for-each" />
|
||||||
|
|
||||||
|
<!-- augment the XML with our own mappings -->
|
||||||
|
<xsl:variable name="augmented">
|
||||||
|
<lvm:c1-map>
|
||||||
|
<xsl:copy-of select="$src/@*" />
|
||||||
|
|
||||||
|
<xsl:for-each select="$src/lvm:param">
|
||||||
|
<xsl:call-template name="lvmp:param-to-map">
|
||||||
|
<xsl:with-param name="args" select="$args" />
|
||||||
|
<xsl:with-param name="param" select="." />
|
||||||
|
<xsl:with-param name="context" select="/lvm:c1-map" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:for-each>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<!-- if @for-each was provided, then apply to all first-level
|
||||||
|
children of the included template -->
|
||||||
|
<xsl:when test="$for-each">
|
||||||
|
<!-- we will need to expose the mapping -->
|
||||||
|
<!-- TODO: need to validate that it actually exists -->
|
||||||
|
<lvm:external name="{$for-each}" />
|
||||||
|
|
||||||
|
<xsl:for-each select="$src/*">
|
||||||
|
<xsl:copy>
|
||||||
|
<xsl:copy-of select="@*" />
|
||||||
|
<xsl:attribute name="lvm:for-each" select="$for-each" />
|
||||||
|
<xsl:copy-of select="*|text()" />
|
||||||
|
</xsl:copy>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- no @for-each; just do a quick copy of all the nodes -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:copy-of select="$src/*" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</lvm:c1-map>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:apply-templates select="$augmented/lvm:c1-map/*" />
|
||||||
|
</lvmp:scope>
|
||||||
|
|
||||||
|
<xsl:message>[c1map] -<xsl:value-of select="@name" /></xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Processes a template param into mappings
|
||||||
|
|
||||||
|
This will generate the mappings necessary to process the template as though
|
||||||
|
it was hard-coded with the imported mappings.
|
||||||
|
|
||||||
|
The {} brace syntax denotes a variable, but mixing values and inline
|
||||||
|
variables are not supported.
|
||||||
|
-->
|
||||||
|
<xsl:template name="lvmp:param-to-map">
|
||||||
|
<xsl:param name="args" />
|
||||||
|
<xsl:param name="param" />
|
||||||
|
<xsl:param name="context" />
|
||||||
|
|
||||||
|
<xsl:variable name="name" select="$param/@name" />
|
||||||
|
<xsl:variable name="arg" select="$args[ local-name()=$name ]" />
|
||||||
|
<xsl:variable name="argvar" select="substring-after( $arg, '{' )" />
|
||||||
|
|
||||||
|
<xsl:if test="$argvar and not( $argvar='' )">
|
||||||
|
<xsl:variable name="varname" select="substring-before( $argvar, '}' )" />
|
||||||
|
|
||||||
|
<lvmp:translate name="{$name}" to="{$varname}" />
|
||||||
|
|
||||||
|
<xsl:variable name="predot" select="substring-before( $varname, '.' )" />
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<!-- no dot; output the entire thing -->
|
||||||
|
<xsl:when test="$predot = ''">
|
||||||
|
<lvm:external name="{$varname}" />
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- multi-level var -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<lvm:external name="{$predot}" dict="true" lvmp:no-validate="true" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!-- TODO: no need to do this if the above conditional matches -->
|
||||||
|
<lvm:map to="{$name}" lvmp:allow-default="true">
|
||||||
|
<xsl:copy-of select="$param/@dict" />
|
||||||
|
<xsl:copy-of select="$param/@default" />
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$arg">
|
||||||
|
<!-- determines if we have a variable -->
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$argvar and not( $argvar='' )">
|
||||||
|
<xsl:attribute name="from"
|
||||||
|
select="substring-before( $argvar, '}' )" />
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- static value -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:attribute name="value" select="$arg" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- required param -->
|
||||||
|
<xsl:when test="$param/@required">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>error: missing required template argument `</xsl:text>
|
||||||
|
<xsl:value-of select="$name" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- otherwise, we have no value -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:attribute name="value" select="''" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</lvm:map>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Common actions performed by nearly every mapping
|
||||||
|
-->
|
||||||
|
<xsl:template name="lvmp:map-common">
|
||||||
|
<!-- may or may not be set -->
|
||||||
|
<xsl:copy-of select="@dict" />
|
||||||
|
<xsl:copy-of select="@link" />
|
||||||
|
<xsl:copy-of select="@transform" />
|
||||||
|
|
||||||
|
<xsl:apply-templates select="@default" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvm:param" priority="4">
|
||||||
|
<!-- processed above on import; no longer needed -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lvm:map[@from]" priority="4">
|
||||||
|
<lvmp:var name="{@to}" from="{@from}" src="map">
|
||||||
|
<xsl:call-template name="lvmp:map-common" />
|
||||||
|
</lvmp:var>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lvm:map[lvm:from]" priority="4">
|
||||||
|
<lvmp:var name="{@to}" from="{lvm:from/@name}">
|
||||||
|
<xsl:call-template name="lvmp:map-common" />
|
||||||
|
</lvmp:var>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lvm:map[@value]" priority="4">
|
||||||
|
<!-- it does not make sense to have a string value be a dictionary -->
|
||||||
|
<xsl:if test="@dict">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>error: cannot have @dict on static mapping `</xsl:text>
|
||||||
|
<xsl:value-of select="@to" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!-- nor does a default make sense -->
|
||||||
|
<xsl:if test="@default and not( @lvmp:allow-default='true' )">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>error: cannot have @default on static mapping `</xsl:text>
|
||||||
|
<xsl:value-of select="@to" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<lvmp:var name="{@to}" value="{@value}">
|
||||||
|
<!-- we may use defaults internally -->
|
||||||
|
<xsl:call-template name="lvmp:map-common" />
|
||||||
|
</lvmp:var>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lvm:pass" priority="4">
|
||||||
|
<lvmp:var name="{@name}" from="{@name}" src="map">
|
||||||
|
<xsl:call-template name="lvmp:map-common" />
|
||||||
|
</lvmp:var>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lvm:external" priority="4">
|
||||||
|
<lvmp:var name="{@name}" from="{@name}" src="external">
|
||||||
|
<xsl:call-template name="lvmp:map-common" />
|
||||||
|
</lvmp:var>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lvm:*/@default">
|
||||||
|
<lvmp:default>
|
||||||
|
<xsl:apply-templates select="." mode="lvm:valparse" />
|
||||||
|
</lvmp:default>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvmp:translate" priority="4">
|
||||||
|
<!-- added by pre-processor during include; ignore -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Override default behavior of c1 nodes when iteration is requested
|
||||||
|
-->
|
||||||
|
<xsl:template match="c1:*[ @lvm:for-each ]"
|
||||||
|
mode="lvmp:c1-node-result" priority="5">
|
||||||
|
|
||||||
|
<lvmp:for-each name="{@lvm:for-each}">
|
||||||
|
<!-- proceed with processing as normal -->
|
||||||
|
<xsl:apply-templates select="@*|*" />
|
||||||
|
</lvmp:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvm:if" priority="4">
|
||||||
|
<lvmp:condition>
|
||||||
|
<lvmp:when>
|
||||||
|
<xsl:call-template name="lvmp:gen-val">
|
||||||
|
<xsl:with-param name="name" select="@name" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</lvmp:when>
|
||||||
|
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</lvmp:condition>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Unhandled node character data
|
||||||
|
|
||||||
|
Note that, if a node contains newlines, then there will be text preceding and
|
||||||
|
following its children. For example:
|
||||||
|
|
||||||
|
<foo>
|
||||||
|
<bar>
|
||||||
|
</foo>
|
||||||
|
|
||||||
|
In the above, the `foo' node has the text "\n ", followed by the node `bar',
|
||||||
|
followed by the text "\n" (assuming that `foo' starts in column 1).
|
||||||
|
-->
|
||||||
|
<xsl:template match="text()" priority="1">
|
||||||
|
<!-- do not output whitespace from source files -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Bail out on unhandled nodes.
|
||||||
|
-->
|
||||||
|
<xsl:template match="*" priority="1">
|
||||||
|
<xsl:message>
|
||||||
|
<xsl:text>[c1map] fatal: unexpected node </xsl:text>
|
||||||
|
<xsl:apply-templates select="." mode="lvmp:node-out" />
|
||||||
|
<xsl:text>:</xsl:text>
|
||||||
|
</xsl:message>
|
||||||
|
|
||||||
|
<xsl:message terminate="yes" select="." />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="*" mode="lvmp:node-out">
|
||||||
|
<xsl:variable name="parent" select="parent::*" />
|
||||||
|
<xsl:if test="$parent">
|
||||||
|
<xsl:apply-templates select="$parent" mode="lvmp:node-out" />
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:text>/</xsl:text>
|
||||||
|
<xsl:value-of select="name()" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Describes how ConceptOne nodes are handled in the output.
|
||||||
|
|
||||||
|
Only nodes in the C1 XML namespace will be included in the output; all other
|
||||||
|
nodes will be in error, except for nodes as part of the c1 map namespace,
|
||||||
|
which are processed and will not be included in the output.
|
||||||
|
|
||||||
|
The output is an array format used to generate the final XML at runtime; this
|
||||||
|
format was not developed in conjunction with this project and is separate, so
|
||||||
|
be sure that this compiler is updated if the format changes.
|
||||||
|
-->
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns:c1="http://www.epic-premier.com/XMLSchema"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:lvm="http://www.lovullo.com/rater/map/c1"
|
||||||
|
xmlns:lvmp="http://www.lovullo.com/rater/map/c1/pp">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Nodes with attributes or children are recursively processed and have the
|
||||||
|
form:
|
||||||
|
'>Name' => array( <recurse> )
|
||||||
|
-->
|
||||||
|
<xsl:template match="c1:*[*|@*]" priority="5">
|
||||||
|
<!-- make the output a little bit sane -->
|
||||||
|
<xsl:value-of select="$lvmp:nl" />
|
||||||
|
|
||||||
|
<!-- defer node rendering; allows us to easily determine if there are
|
||||||
|
siblings of the same name within a node boundary -->
|
||||||
|
<lvmp:node name="{name()}" />
|
||||||
|
<xsl:text> => </xsl:text>
|
||||||
|
|
||||||
|
<lvmp:node-boundary>
|
||||||
|
<xsl:apply-templates select="." mode="lvmp:c1-node-result" />
|
||||||
|
</lvmp:node-boundary>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
The default behavior of c1 nodes is to simply output the nodes as-is, with
|
||||||
|
variable substitutions.
|
||||||
|
-->
|
||||||
|
<xsl:template match="c1:*" mode="lvmp:c1-node-result" priority="1">
|
||||||
|
<xsl:text>array( </xsl:text>
|
||||||
|
<xsl:apply-templates select="@*|*" />
|
||||||
|
<xsl:text>) </xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Text-only nodes are of the form:
|
||||||
|
'>Name' => 'value'
|
||||||
|
-->
|
||||||
|
<xsl:template match="c1:*[text()]" priority="4">
|
||||||
|
<!-- defer node rendering; allows us to easily determine if there are
|
||||||
|
siblings of the same name within a node boundary -->
|
||||||
|
<lvmp:node name="{name()}" />
|
||||||
|
<xsl:text> => </xsl:text>
|
||||||
|
|
||||||
|
<xsl:text></xsl:text>
|
||||||
|
<!-- TODO: escape single quotes -->
|
||||||
|
<xsl:apply-templates select="text()" mode="lvm:valparse" />
|
||||||
|
<xsl:text>, </xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Attributes are of the format:
|
||||||
|
'[Name]' => 'value'
|
||||||
|
-->
|
||||||
|
<xsl:template match="c1:*/@*" priority="5">
|
||||||
|
<xsl:text>'[</xsl:text>
|
||||||
|
<xsl:value-of select="name()" />
|
||||||
|
<xsl:text>]' => </xsl:text>
|
||||||
|
<xsl:apply-templates select="." mode="lvm:valparse" />
|
||||||
|
<xsl:text>, </xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- alternative attribute format for special situations -->
|
||||||
|
<xsl:template match="lvm:attribute" priority="5">
|
||||||
|
<xsl:text>'[</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>]' => </xsl:text>
|
||||||
|
<xsl:apply-templates select="@value" mode="lvm:valparse" />
|
||||||
|
<xsl:text>, </xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="c1:*/@lvm:*" priority="6">
|
||||||
|
<!-- discard all system attributes -->
|
||||||
|
<!-- TODO: error once everything is properly implemented -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
|
@ -0,0 +1,339 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Renders the final PHP code
|
||||||
|
-->
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns:c1="http://www.epic-premier.com/XMLSchema"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:lvm="http://www.lovullo.com/rater/map/c1"
|
||||||
|
xmlns:lvmp="http://www.lovullo.com/rater/map/c1/pp">
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:import href="transform.xsl" />
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvmp:root" mode="lvmp:render" priority="5">
|
||||||
|
<xsl:text><?php </xsl:text>
|
||||||
|
<xsl:value-of select="$lvmp:nl" />
|
||||||
|
|
||||||
|
<!-- TODO: add program id to namespace -->
|
||||||
|
<xsl:text>namespace lovullo\c1\interfaces\c1\contract\</xsl:text>
|
||||||
|
<xsl:value-of select="@program" />
|
||||||
|
<xsl:text>;</xsl:text>
|
||||||
|
<xsl:value-of select="$lvmp:nl" />
|
||||||
|
|
||||||
|
<xsl:text>class </xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text> {</xsl:text>
|
||||||
|
<xsl:value-of select="$lvmp:nl" />
|
||||||
|
|
||||||
|
<xsl:text>public function compose( $contract ) {</xsl:text>
|
||||||
|
<xsl:value-of select="$lvmp:nl" />
|
||||||
|
<xsl:text> return array(</xsl:text>
|
||||||
|
<xsl:value-of select="$lvmp:nl" />
|
||||||
|
<!-- render the preprocessed content -->
|
||||||
|
<xsl:apply-templates mode="lvmp:render" />
|
||||||
|
<xsl:value-of select="$lvmp:nl" />
|
||||||
|
<xsl:text> );</xsl:text>
|
||||||
|
<xsl:value-of select="$lvmp:nl" />
|
||||||
|
<xsl:text> }</xsl:text>
|
||||||
|
<xsl:value-of select="$lvmp:nl" />
|
||||||
|
|
||||||
|
<xsl:text>}</xsl:text>
|
||||||
|
<xsl:value-of select="$lvmp:nl" />
|
||||||
|
<xsl:text>?></xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="text()" mode="lvmp:render" priority="5">
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template name="lvmp:value" match="lvmp:value" mode="lvmp:render" priority="5">
|
||||||
|
<xsl:param name="name" select="@ref" />
|
||||||
|
<xsl:param name="scope" select="ancestor::lvmp:scope[1]" />
|
||||||
|
<xsl:param name="var" select="$scope/lvmp:var[ @name=$name ][1]" />
|
||||||
|
<xsl:param name="from" select="$var/@from" />
|
||||||
|
<xsl:param name="value" select="$var/@value" />
|
||||||
|
<xsl:param name="default" select="$var/lvmp:default" />
|
||||||
|
|
||||||
|
<!-- provide error if the variable could not be found in the current scope -->
|
||||||
|
<xsl:call-template name="lvmp:check-var">
|
||||||
|
<xsl:with-param name="name" select="$name" />
|
||||||
|
<xsl:with-param name="scope" select="$scope" />
|
||||||
|
</xsl:call-template>
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<!-- mapping was provided -->
|
||||||
|
<xsl:when test="$from and not( $from='' )">
|
||||||
|
<xsl:apply-templates select="$var" mode="lvmp:transform">
|
||||||
|
<xsl:with-param name="value">
|
||||||
|
<xsl:apply-templates select="." mode="lvmp:render-value">
|
||||||
|
<xsl:with-param name="var" select="$var" />
|
||||||
|
<xsl:with-param name="from" select="$from" />
|
||||||
|
<xsl:with-param name="scope" select="$scope" />
|
||||||
|
<xsl:with-param name="default" select="$default" />
|
||||||
|
</xsl:apply-templates>
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:apply-templates>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- static string mapping -->
|
||||||
|
<xsl:when test="$value and not( $value='' )">
|
||||||
|
<!-- TODO: escape single quote -->
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
<xsl:value-of select="$value" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- if no @from was provided, then it forces the use of the default
|
||||||
|
value -->
|
||||||
|
<xsl:when test="$default">
|
||||||
|
<xsl:text>$contract->checkDefaultValue( '</xsl:text>
|
||||||
|
<xsl:value-of select="$name" />
|
||||||
|
<xsl:text>', </xsl:text>
|
||||||
|
<xsl:apply-templates select="$default" mode="lvmp:render" />
|
||||||
|
<xsl:text> )</xsl:text>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- if no default is available, then this node shall never be set -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:text>null</xsl:text>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template mode="lvmp:render" priority="7"
|
||||||
|
match="lvmp:value[ lvmp:value ]">
|
||||||
|
|
||||||
|
<xsl:param name="name" select="@ref" />
|
||||||
|
<xsl:param name="scope" select="ancestor::lvmp:scope[1]" />
|
||||||
|
<xsl:param name="var" select="$scope/lvmp:var[ @name=$name ][1]" />
|
||||||
|
<xsl:param name="from" select="$var/@from" />
|
||||||
|
<xsl:param name="value" select="$var/@value" />
|
||||||
|
<xsl:param name="default" select="$var/lvmp:default" />
|
||||||
|
|
||||||
|
<xsl:text>$contract->getValueByContext( </xsl:text>
|
||||||
|
<!-- recursive process contexts -->
|
||||||
|
<xsl:apply-templates select="lvmp:value" mode="lvmp:render">
|
||||||
|
<xsl:with-param name="scope" select="$scope" />
|
||||||
|
<xsl:with-param name="default" select="$default" />
|
||||||
|
</xsl:apply-templates>
|
||||||
|
<xsl:text>, '</xsl:text>
|
||||||
|
<!-- TODO: validate existence of key in dict -->
|
||||||
|
<xsl:value-of select="$name" />
|
||||||
|
<xsl:text>' </xsl:text>
|
||||||
|
|
||||||
|
<xsl:text> )</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvmp:value" mode="lvmp:render-value" priority="1">
|
||||||
|
<xsl:param name="var" />
|
||||||
|
<xsl:param name="scope" />
|
||||||
|
<xsl:param name="default" />
|
||||||
|
<xsl:param name="from" />
|
||||||
|
<!-- optional -->
|
||||||
|
<xsl:param name="value-node" select="." />
|
||||||
|
<xsl:param name="context" />
|
||||||
|
|
||||||
|
<!-- the name of the index we reference for our value defaults to our own
|
||||||
|
name, but can be overridden in the mapping -->
|
||||||
|
<xsl:param name="index-name">
|
||||||
|
<xsl:choose>
|
||||||
|
<!-- link provided; override -->
|
||||||
|
<xsl:when test="$var/@link">
|
||||||
|
<!-- parse the link and replace it with the var it maps to -->
|
||||||
|
<xsl:call-template name="lvmp:var-from">
|
||||||
|
<xsl:with-param name="name" select="$var/@link" />
|
||||||
|
<xsl:with-param name="scope" select="$scope" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- default to our own index -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:value-of select="$from" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:param>
|
||||||
|
|
||||||
|
<xsl:text>$contract->getValue( '</xsl:text>
|
||||||
|
<xsl:value-of select="$from" />
|
||||||
|
<xsl:text>', $contract->getValueIndex( '</xsl:text>
|
||||||
|
<xsl:value-of select="$index-name" />
|
||||||
|
<xsl:text>' )</xsl:text>
|
||||||
|
|
||||||
|
<xsl:if test="$default">
|
||||||
|
<xsl:text>, </xsl:text>
|
||||||
|
<xsl:apply-templates select="$default" mode="lvmp:render" />
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:text> )</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Generates an error in the event that the given var name cannot be found in
|
||||||
|
the given scope.
|
||||||
|
-->
|
||||||
|
<xsl:template name="lvmp:check-var">
|
||||||
|
<xsl:param name="name" />
|
||||||
|
<xsl:param name="scope" select="ancestor::lvmp:scope[1]" />
|
||||||
|
|
||||||
|
<!-- look up variable in parent scope -->
|
||||||
|
<xsl:variable name="var" select="$scope/lvmp:var[ @name=$name ][1]" />
|
||||||
|
|
||||||
|
<!-- provide error if the variable could not be found in the current scope -->
|
||||||
|
<xsl:if test="not( $var )">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>error: variable not within scope: </xsl:text>
|
||||||
|
<xsl:value-of select="$scope/@id" />
|
||||||
|
<xsl:text>/</xsl:text>
|
||||||
|
<xsl:value-of select="$name" />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Validates and then returns the source mapping of the given variable within
|
||||||
|
the given (or current) scope
|
||||||
|
-->
|
||||||
|
<xsl:template name="lvmp:var-from">
|
||||||
|
<xsl:param name="name" />
|
||||||
|
<xsl:param name="scope" select="ancestor::lvmp:scope[1]" />
|
||||||
|
|
||||||
|
<!-- undefined/scoping check -->
|
||||||
|
<xsl:call-template name="lvmp:check-var">
|
||||||
|
<xsl:with-param name="name" select="$name" />
|
||||||
|
<xsl:with-param name="scope" select="$scope" />
|
||||||
|
</xsl:call-template>
|
||||||
|
|
||||||
|
<xsl:value-of select="$scope/lvmp:var[ @name=$name ][1]/@from" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvmp:translate" mode="lvmp:render" priority="5">
|
||||||
|
<!-- no longer needed -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lvmp:var" mode="lvmp:render" priority="5">
|
||||||
|
<!-- no longer needed -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lvmp:var/lvmp:default" mode="lvmp:render" priority="5">
|
||||||
|
<!-- render contents -->
|
||||||
|
<xsl:apply-templates mode="lvmp:render" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Scope boundary; no longer needed in output
|
||||||
|
-->
|
||||||
|
<xsl:template match="lvmp:scope" mode="lvmp:render" priority="2">
|
||||||
|
<xsl:apply-templates mode="lvmp:render" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Conditional boundary; not needed in output
|
||||||
|
-->
|
||||||
|
<xsl:template match="lvmp:condition" mode="lvmp:render" priority="2">
|
||||||
|
<xsl:apply-templates mode="lvmp:render" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lvmp:condition/lvmp:when" mode="lvmp:render" priority="2">
|
||||||
|
<!-- will be processed as part of sibling output -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Iteration boundary
|
||||||
|
-->
|
||||||
|
<xsl:template match="lvmp:for-each" mode="lvmp:render" priority="5">
|
||||||
|
<xsl:variable name="from">
|
||||||
|
<xsl:call-template name="lvmp:var-from">
|
||||||
|
<xsl:with-param name="name" select="@name" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:text>$contract->iterateValues( '</xsl:text>
|
||||||
|
<xsl:value-of select="$from" />
|
||||||
|
<xsl:text>', </xsl:text>
|
||||||
|
<xsl:text>function( $contract ) {</xsl:text>
|
||||||
|
<xsl:text> return array(</xsl:text>
|
||||||
|
<xsl:apply-templates mode="lvmp:render" />
|
||||||
|
<xsl:text>);</xsl:text>
|
||||||
|
<xsl:text>}</xsl:text>
|
||||||
|
<xsl:text>)</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
The C1 import system recognizes the following formats:
|
||||||
|
|
||||||
|
'>Node'
|
||||||
|
'N>Node'
|
||||||
|
|
||||||
|
where N is any number; the latter is used for creating unique indexes for
|
||||||
|
multiple siblings of the same name.
|
||||||
|
-->
|
||||||
|
<xsl:template match="lvmp:node" mode="lvmp:render" priority="5">
|
||||||
|
<xsl:variable name="name" select="@name" />
|
||||||
|
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
|
||||||
|
<!-- generate a unique key to avoid conflicts -->
|
||||||
|
<xsl:value-of select="generate-id(.)" />
|
||||||
|
|
||||||
|
<xsl:text>></xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Node boundary; not needed in output
|
||||||
|
|
||||||
|
The boundary dictates the context of a conditional. This template has a lower
|
||||||
|
priority and will be the default if there is no parent conditional.
|
||||||
|
-->
|
||||||
|
<xsl:template match="lvmp:node-boundary" mode="lvmp:render" priority="2">
|
||||||
|
<xsl:apply-templates mode="lvmp:render" />
|
||||||
|
|
||||||
|
<!-- unconditional delimiter; nothing funky going on -->
|
||||||
|
<xsl:text>, </xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template mode="lvmp:render" priority="5" match="
|
||||||
|
lvmp:node-boundary[
|
||||||
|
parent::lvmp:condition
|
||||||
|
or parent::lvmp:scope/parent::lvmp:condition
|
||||||
|
]
|
||||||
|
">
|
||||||
|
<!-- select the nearest condition -->
|
||||||
|
<xsl:variable name="cond" select="ancestor::lvmp:condition[1]" />
|
||||||
|
|
||||||
|
<xsl:text>( ( </xsl:text>
|
||||||
|
<xsl:text>$contract->isTruthy( </xsl:text>
|
||||||
|
<xsl:apply-templates select="$cond/lvmp:when/lvmp:*" mode="lvmp:render" />
|
||||||
|
<xsl:text>)</xsl:text>
|
||||||
|
<xsl:text> ) ? </xsl:text>
|
||||||
|
<xsl:apply-templates mode="lvmp:render">
|
||||||
|
<xsl:with-param name="no-trailing-sep" select="true()" />
|
||||||
|
</xsl:apply-templates>
|
||||||
|
<xsl:text> : null ), </xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="*" mode="lvmp:render" priority="1">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>[c1map] fatal: unexpected node during render: </xsl:text>
|
||||||
|
<xsl:apply-templates select="." mode="lvmp:node-out" />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Transforms values
|
||||||
|
-->
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns:c1="http://www.epic-premier.com/XMLSchema"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:lvm="http://www.lovullo.com/rater/map/c1"
|
||||||
|
xmlns:lvmp="http://www.lovullo.com/rater/map/c1/pp">
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvmp:var[ @transform='proper-case' ]" priority="5"
|
||||||
|
mode="lvmp:transform">
|
||||||
|
|
||||||
|
<xsl:param name="value" />
|
||||||
|
|
||||||
|
<xsl:text>ucwords(strtolower(</xsl:text>
|
||||||
|
<xsl:copy-of select="$value" />
|
||||||
|
<xsl:text>))</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvmp:var[ not( @transform ) or @transform='' ]"
|
||||||
|
mode="lvmp:transform" priority="3">
|
||||||
|
|
||||||
|
<xsl:param name="value" />
|
||||||
|
|
||||||
|
<!-- no transformation; do nothing -->
|
||||||
|
<xsl:copy-of select="$value" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvmp:var" mode="lvmp:transform" priority="2">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>error: unknown transformation `</xsl:text>
|
||||||
|
<xsl:value-of select="@transform" />
|
||||||
|
<xsl:text>' for `</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvmp:*" mode="lvmp:transform" priority="1">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>internal error: unexpected node for transformation: </xsl:text>
|
||||||
|
<xsl:copy-of select="." />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Inline value parser
|
||||||
|
|
||||||
|
Will parse all attributes and text of the form "a{b}c", where `b' is some
|
||||||
|
variable.
|
||||||
|
-->
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns:c1="http://www.epic-premier.com/XMLSchema"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:lvm="http://www.lovullo.com/rater/map/c1"
|
||||||
|
xmlns:lvmp="http://www.lovullo.com/rater/map/c1/pp">
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="@*|text()" mode="lvm:valparse">
|
||||||
|
<xsl:call-template name="lvm:valparse">
|
||||||
|
<xsl:with-param name="str" select="." />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template name="lvm:valparse">
|
||||||
|
<xsl:param name="str" />
|
||||||
|
|
||||||
|
<xsl:variable name="pre" select="substring-before( $str, '{' )" />
|
||||||
|
<xsl:variable name="post" select="substring-after( $str, '}' )" />
|
||||||
|
|
||||||
|
<!-- get stuff between the two -->
|
||||||
|
<xsl:variable name="postpre" select="substring-after( $str, '{' )" />
|
||||||
|
<xsl:variable name="val" select="substring-before( $postpre, '}' )" />
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:if test="$pre">
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
<!-- TODO: escape -->
|
||||||
|
<xsl:value-of select="$pre" />
|
||||||
|
<xsl:text>' . </xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<!-- variable reference -->
|
||||||
|
<xsl:when test="$val">
|
||||||
|
<xsl:call-template name="lvmp:gen-val">
|
||||||
|
<xsl:with-param name="name" select="$val" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- static value; no variable -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
<xsl:value-of select="$str" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
|
||||||
|
<xsl:if test="$post">
|
||||||
|
<xsl:text> . '</xsl:text>
|
||||||
|
<!-- TODO: escape -->
|
||||||
|
<xsl:value-of select="$post" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Generate a variable reference for later rendering
|
||||||
|
|
||||||
|
If a variable of the form x.y is found, it is recursively processed with `y'
|
||||||
|
as the variable and `x' as the context: a dictionary lookup.
|
||||||
|
-->
|
||||||
|
<xsl:template name="lvmp:gen-val">
|
||||||
|
<xsl:param name="name" />
|
||||||
|
|
||||||
|
<xsl:variable name="trans" select="
|
||||||
|
ancestor::lvm:c1-map/lvmp:translate[ @name=$name ]
|
||||||
|
" />
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<!-- name translation requested -->
|
||||||
|
<xsl:when test="$trans">
|
||||||
|
<xsl:call-template name="lvmp:do-gen-val">
|
||||||
|
<xsl:with-param name="name" select="$trans/@to" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- no translation; use name as-is -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:call-template name="lvmp:do-gen-val">
|
||||||
|
<xsl:with-param name="name" select="$name" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template name="lvmp:do-gen-val">
|
||||||
|
<xsl:param name="name" />
|
||||||
|
|
||||||
|
<!-- we may have a variable of the form `x.y', in which case we should
|
||||||
|
process `y' withint he context of `x' -->
|
||||||
|
<xsl:variable name="rightmost" select="
|
||||||
|
substring-after( $name, '.' )
|
||||||
|
" />
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<!-- no more key references -->
|
||||||
|
<xsl:when test="$rightmost = ''">
|
||||||
|
<lvmp:value ref="{$name}" />
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- recursively process key reference -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<!-- determine the key context, which is the entire base sans the
|
||||||
|
rightmost variable name -->
|
||||||
|
<xsl:variable name="context" select="
|
||||||
|
substring( $name, 1, (
|
||||||
|
string-length( $name ) - string-length( $rightmost ) - 1
|
||||||
|
) )
|
||||||
|
" />
|
||||||
|
|
||||||
|
<lvmp:value ref="{$rightmost}" index-key="{$context}">
|
||||||
|
<xsl:call-template name="lvmp:gen-val">
|
||||||
|
<xsl:with-param name="name" select="$context" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</lvmp:value>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
|
@ -0,0 +1,883 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
targetNamespace="http://www.lovullo.com/calc"
|
||||||
|
xmlns="http://www.lovullo.com/calc"
|
||||||
|
elementFormDefault="qualified">
|
||||||
|
|
||||||
|
|
||||||
|
<!--basicTypes-->
|
||||||
|
<xs:simpleType name="nameType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Generic name reference restriction, intended to be generic enough to
|
||||||
|
work with most systems (supporting both C-style and Lisp-style
|
||||||
|
identifiers).
|
||||||
|
|
||||||
|
The systems that implement this schema should perform their own, more
|
||||||
|
strict, type checks.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<!-- we need to allow '@' since that's used in macros -->
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:pattern value="[a-zA-Z_@{-][a-zA-Z0-9_@{}-]*" />
|
||||||
|
<xs:maxLength value="50" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:simpleType name="constValueType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Valid value for constants.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<!-- we need to allow '@' since that's used in macros -->
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:pattern value="-?[0-9]+(.[0-9]+)?[mek]?|\{?@[a-z][a-zA-Z0-9_]*@\}?" />
|
||||||
|
<xs:maxLength value="50" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:simpleType name="descType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Documentation for a specific element.
|
||||||
|
|
||||||
|
The documentation must not be sparse; please provide something
|
||||||
|
descriptive that will be useful to someone completely new to the code.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:minLength value="2" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:simpleType name="indexNameType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Single-character index variable
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:restriction base="xs:NCName">
|
||||||
|
<xs:pattern value="[a-z]" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:simpleType name="symbolType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Symbol used to represent an entity when rendered.
|
||||||
|
|
||||||
|
The string should consist of TeX/LaTeX commands and should produce a
|
||||||
|
single symbol.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:restriction base="xs:string" />
|
||||||
|
</xs:simpleType>
|
||||||
|
<!--/basicTypes-->
|
||||||
|
|
||||||
|
|
||||||
|
<!--calculations-->
|
||||||
|
<!--operators-->
|
||||||
|
<xs:element name="operator" type="operatorBaseType" abstract="true">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Abstract operator type used to classify elements as operators.
|
||||||
|
|
||||||
|
Operators are portions of the calculation that perform a portion of
|
||||||
|
the calculation. For example, a summation would classify as an
|
||||||
|
operation (operator), but value-of would not (as it is only
|
||||||
|
representing a value, but not performing a calculation).
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="operatorBaseType" abstract="true">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Elements/attributes common to all operator types (see the operator
|
||||||
|
element for a description on what qualifies as an operator).
|
||||||
|
|
||||||
|
All operators may include child calculations. Furthermore, they may
|
||||||
|
be labeled and may have an identifier associated with their result.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="when" type="whenType" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
<xs:group ref="calculation" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="yields" type="nameType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Optional identifier with which the result of the calculation may be
|
||||||
|
referenced.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="label" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Optional description of a calculation. @label is used in place of
|
||||||
|
@desc to ensure that it is not confused with the otherwise required
|
||||||
|
@desc attribute.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="desc" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
@desc should be used to describe a value that is generated by a
|
||||||
|
calculation and should not otherwise be used (e.g. with
|
||||||
|
lv:sum/@generate)
|
||||||
|
|
||||||
|
This is different from @label, which provides a high-level
|
||||||
|
description of what the equation is doing. @desc describes what the
|
||||||
|
generated value is.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="index" type="indexNameType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Allows for the definition of an index variable which will be
|
||||||
|
defined for all children of the operation.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="sum" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Represents a summation (addition) of a set of values.
|
||||||
|
|
||||||
|
If @of is used, the equation defined by child elements will be
|
||||||
|
iterated using an index on the set provided by @of. If no equation is
|
||||||
|
given, all elements in the set identified by @of will be summed.
|
||||||
|
|
||||||
|
If @of is omitted, the result of each child element will be summed.
|
||||||
|
|
||||||
|
This operator should also be used for subtraction by summing negative
|
||||||
|
values.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType">
|
||||||
|
<xs:attribute name="of" type="nameType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Iterate over all values of this set. Must be a set.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="generates" type="nameType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Optional name of a set to generate from this expressions.
|
||||||
|
|
||||||
|
Generators are compatible only with @of and a sub-expression.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="sym" type="symbolType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Symbol to use when typesetting the generator
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="precision" type="constValueType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Yield precision
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="product" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Represents the product (multiplication) of a set of values.
|
||||||
|
|
||||||
|
If @of is used, the equation defined by child elements will be
|
||||||
|
iterated using an index on the set provided by @of. If no equation is
|
||||||
|
given, all elements in the set identified by @of will be multiplied.
|
||||||
|
|
||||||
|
If @of is omitted, the result of each child element will be
|
||||||
|
multiplied.
|
||||||
|
|
||||||
|
While this operator may also be used for division by multiplying by
|
||||||
|
the inverse of a number (n^-1), a limited quotient operator is
|
||||||
|
provided for clarity and convenience.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType">
|
||||||
|
<xs:attribute name="of" type="nameType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Iterate over all values of this set. Must be a set.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="generates" type="nameType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Optional name of a set to generate from this expressions.
|
||||||
|
|
||||||
|
Generators are compatible only with @of and a sub-expression.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="sym" type="symbolType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Symbol to use when typesetting the generator
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="dot" type="xs:boolean">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Dot product of any number of vectors
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="precision" type="constValueType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Yield precision
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="quotient" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Represents the quotient (division) of two values.
|
||||||
|
|
||||||
|
This operator is to be thought of as a fraction: the numerator is
|
||||||
|
identified by the first child element and the denominator the second.
|
||||||
|
|
||||||
|
While the summation operator may also be used for division by
|
||||||
|
multiplying by the inverse of a number (n^-1), this limited operator
|
||||||
|
is provided for clarity and convenience.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType" />
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- named after Scheme's expt; same arg order -->
|
||||||
|
<xs:element name="expt" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Exponent; the first child node is the base, the second is the order.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType" />
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="cons" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Construct a list using the given element and an existing list
|
||||||
|
|
||||||
|
This is analogous to lisp's cons; the first argument is the car and
|
||||||
|
the second is the cdr.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType">
|
||||||
|
<xs:sequence>
|
||||||
|
<!-- both car and cdr required -->
|
||||||
|
<xs:group ref="calculation" minOccurs="2" maxOccurs="2" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="car" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Retrieve the first element of a list
|
||||||
|
|
||||||
|
Analogous to lisp's car.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType">
|
||||||
|
<xs:sequence>
|
||||||
|
<!-- we accept only a set -->
|
||||||
|
<xs:group ref="calculation" minOccurs="1" maxOccurs="1" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="cdr" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Return the list without its first element
|
||||||
|
|
||||||
|
If the list contains only one element, then an empty list will be
|
||||||
|
returned. Analogous to lisp's cdr.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType">
|
||||||
|
<xs:sequence>
|
||||||
|
<!-- we accept only a set -->
|
||||||
|
<xs:group ref="calculation" minOccurs="1" maxOccurs="1" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="length-of" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Retrieves the length of a vector
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType">
|
||||||
|
<xs:sequence>
|
||||||
|
<!-- we accept only a set -->
|
||||||
|
<xs:group ref="calculation" minOccurs="1" maxOccurs="1" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<!--apply-->
|
||||||
|
<xs:element name="apply" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Denotes a function application.
|
||||||
|
|
||||||
|
The result of the function identified by @name will be used in
|
||||||
|
place of the call. The application may optionally accept an
|
||||||
|
argument list (if the function accepts arguments).
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType">
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="arg" type="applyArgumentType" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="name" type="nameType" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Name of the function to apply
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<!-- argument shorthand -->
|
||||||
|
<xs:anyAttribute namespace="##any" processContents="lax" />
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="applyArgumentType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Represents an argument to be applied to a function.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:group ref="calculation" minOccurs="1" maxOccurs="1" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="name" type="nameType" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Name of the parameter to apply to the function
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="recurse" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Recursively applies the current function.
|
||||||
|
|
||||||
|
All arguments are copied to the argument list of the function application unless overridden.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType">
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="arg" type="applyArgumentType" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<!-- argument shorthand -->
|
||||||
|
<xs:anyAttribute namespace="##any" processContents="lax" />
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<!--/apply-->
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="ceil" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Converts the given value to an integer, rounding up if necessary (e.g. 0.1 => 1)
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType">
|
||||||
|
<xs:attribute name="precision" type="constValueType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Value precision to consider for rounding.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="floor" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Converts the given value to an integer, rounding down if necessary (e.g. 0.9 => 0)
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType">
|
||||||
|
<xs:attribute name="precision" type="constValueType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Value precision to consider for rounding.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
<xs:element name="set" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Creates a set out of its siblings
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType" />
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Debug
|
||||||
|
-->
|
||||||
|
<xs:element name="debug-to-console" substitutionGroup="operator">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Outputs the result of the contained expression to the console and
|
||||||
|
returns its value.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="operatorBaseType" />
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<!--/operators-->
|
||||||
|
|
||||||
|
|
||||||
|
<!--when-->
|
||||||
|
<xs:complexType name="whenType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Defines a condition under which the expression will yield one if
|
||||||
|
true, otherwise will be <em>strongly</em> zero (zero even if
|
||||||
|
undefined)
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:group ref="conditions" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="name" type="nameType" use="required" />
|
||||||
|
<xs:attribute name="index" type="nameType" />
|
||||||
|
<xs:attribute name="label" type="xs:string" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:group name="conditions">
|
||||||
|
<xs:choice>
|
||||||
|
<xs:element name="eq" type="conditionType" />
|
||||||
|
<xs:element name="ne" type="conditionType" />
|
||||||
|
<xs:element name="lt" type="conditionType" />
|
||||||
|
<xs:element name="gt" type="conditionType" />
|
||||||
|
<xs:element name="lte" type="conditionType" />
|
||||||
|
<xs:element name="gte" type="conditionType" />
|
||||||
|
|
||||||
|
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xs:choice>
|
||||||
|
</xs:group>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="conditionType">
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:group ref="calculation" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
<!--/when-->
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="indexType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
More flexible alternative to the @index attribute on elements; supports
|
||||||
|
calculations for determining the index
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:group ref="calculation" minOccurs="1" maxOccurs="1" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="valueType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Returns the value associated with the given identifier.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="when" type="whenType" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
<xs:element name="index" type="indexType" minOccurs="0" maxOccurs="2" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="name" type="nameType" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
An identifier for which the value should be retrieved
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="index" type="nameType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Allows for the definition of an index variable which will be
|
||||||
|
defined for all children of the operation.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="label" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Optional description of a calculation. @label is used in place of
|
||||||
|
@desc to ensure that it is not confused with the otherwise required
|
||||||
|
@desc attribute.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="constType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Returns @value. This element simply enforces documentation and prevents
|
||||||
|
the use of magic values.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="when" type="whenType" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
<xs:element name="index" type="indexType" minOccurs="0" maxOccurs="2" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="value" type="constValueType" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Value of constant (must be within the domain of its @type)
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="type" type="nameType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Type (domain) of the constant (inferred when not provided)
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="desc" type="descType" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Description of the value explaining its intent
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="label" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Optional description of a calculation. @label is used in place of
|
||||||
|
@desc to ensure that it is not confused with the otherwise required
|
||||||
|
@desc attribute.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="casesType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Represents a list of cases for a calculation.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="case" minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
|
||||||
|
<xs:element name="when" type="whenType" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
<xs:group ref="calculation" minOccurs="1" maxOccurs="1" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="label" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Optional description of the case
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
|
||||||
|
<xs:element name="otherwise" minOccurs="0" maxOccurs="1">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:group ref="calculation" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="label" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Optional description of the case
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="label" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Optional description of the case set
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="letType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Declares variables visible within the let block.
|
||||||
|
|
||||||
|
This exists as a means of assignment for re-using values.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="values" minOccurs="1" maxOccurs="1">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Declares a list of values to define for this block
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||||
|
<xs:element name="value" minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Declares a value that will remain in scope for the let block
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:group ref="calculation" minOccurs="1" maxOccurs="1" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="name" type="nameType" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Variable name
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="type" type="nameType" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Variable datatype
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<!-- TODO: enum -->
|
||||||
|
<xs:attribute name="set" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Vector/matrix; if omitted, implicitly scalar.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="desc" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Describe the purpose of the value
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
<xs:group ref="calculation" minOccurs="1" maxOccurs="1" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:group name="calculation">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Represents every element that can be used to perform a calculation.
|
||||||
|
Implementors may use this group to accept any type of calculation.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:choice>
|
||||||
|
<xs:element ref="operator" />
|
||||||
|
<xs:element name="value-of" type="valueType" />
|
||||||
|
<xs:element name="const" type="constType" />
|
||||||
|
<xs:element name="cases" type="casesType" />
|
||||||
|
<xs:element name="let" type="letType" />
|
||||||
|
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||||
|
</xs:choice>
|
||||||
|
</xs:group>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:group name="calculationRoot">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Root calculation node; this should be the entry point for any type of
|
||||||
|
calculation. This helps to ensure that certain nodes are only used at
|
||||||
|
the beginning of a calculation (such as cases).
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:choice>
|
||||||
|
<xs:group ref="calculation" />
|
||||||
|
</xs:choice>
|
||||||
|
</xs:group>
|
||||||
|
<!--/calculations-->
|
||||||
|
|
||||||
|
</xs:schema>
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Writes preprocessor output to disk to eliminate the overhead of reprocessing
|
||||||
|
for each task that requires such output.
|
||||||
|
|
||||||
|
Also performs validation.
|
||||||
|
|
||||||
|
N.B.: Requires XSLT >=2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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:lvm="http://www.lovullo.com/rater/map"
|
||||||
|
xmlns:lvmc="http://www.lovullo.com/rater/map/compiler"
|
||||||
|
xmlns:c="http://www.lovullo.com/calc"
|
||||||
|
xmlns:w="http://www.lovullo.com/rater/worksheet"
|
||||||
|
xmlns:util="http://www.lovullo.com/util"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc"
|
||||||
|
xmlns:compiler="http://www.lovullo.com/rater/compiler"
|
||||||
|
xmlns:calc-compiler="http://www.lovullo.com/calc/compiler"
|
||||||
|
xmlns:ext="http://www.lovullo.com/ext">
|
||||||
|
|
||||||
|
<xsl:output
|
||||||
|
indent="yes"
|
||||||
|
omit-xml-declaration="yes"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- processing utilities -->
|
||||||
|
<xsl:include href="include/util.xsl" />
|
||||||
|
|
||||||
|
<!-- compiler -> JS -->
|
||||||
|
<xsl:include href="include/preprocess.xsl" />
|
||||||
|
<xsl:include href="compiler/validate.xsl" />
|
||||||
|
<xsl:include href="compiler/js.xsl" />
|
||||||
|
<xsl:include href="compiler/map.xsl" />
|
||||||
|
|
||||||
|
<!-- contains get-symbol-map -->
|
||||||
|
<xsl:include href="include/display.xsl" />
|
||||||
|
|
||||||
|
<!-- allows disabling of time-consuming validation -->
|
||||||
|
<xsl:param name="preproc-cache-validate" select="'true'" />
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Simply copy the preprocessor output; the caller is responsible for outputting
|
||||||
|
this to a document.
|
||||||
|
-->
|
||||||
|
<xsl:template match="/lv:rater|/lv:package" priority="5">
|
||||||
|
<!-- XXX: Duplicate code; see summary -->
|
||||||
|
<xsl:variable name="processed">
|
||||||
|
<xsl:apply-templates select="." mode="preproc:compile" />
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<!-- fail on preprocessor errors -->
|
||||||
|
<xsl:call-template name="preproc:err-chk">
|
||||||
|
<xsl:with-param name="processed" select="$processed" />
|
||||||
|
</xsl:call-template>
|
||||||
|
|
||||||
|
<!-- validation must have passed; output the nodes -->
|
||||||
|
<xsl:copy-of select="$processed" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template name="preproc:err-chk">
|
||||||
|
<xsl:param name="processed" />
|
||||||
|
|
||||||
|
<xsl:for-each select="$processed//preproc:error">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>!!! preprocessor error: </xsl:text>
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="*" mode="preproc:handle-errors" priority="1">
|
||||||
|
<!-- do nothing -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvm:program-map|lvm:return-map" priority="5">
|
||||||
|
<xsl:apply-templates select="." mode="lvmc:compile" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="w:worksheet" priority="5">
|
||||||
|
<xsl:apply-templates select="." mode="w:compile" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- any unhandled nodes should be an error -->
|
||||||
|
<xsl:template match="*" priority="1">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>fatal: source file is invalid: unexpected node </xsl:text>
|
||||||
|
<xsl:value-of select="name()" />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
|
@ -0,0 +1,137 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Compiles rater XML into JavaScript
|
||||||
|
|
||||||
|
This stylesheet should be included by whatever is doing the processing and is
|
||||||
|
responsible for outputting the generated code in whatever manner is
|
||||||
|
appropriate (inline JS, a file, etc).
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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:c="http://www.lovullo.com/calc"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lv:package" mode="preproc:compile-fragments">
|
||||||
|
<xsl:copy>
|
||||||
|
<xsl:sequence select="@*, *" />
|
||||||
|
|
||||||
|
<!-- compile each fragment in the symbol table -->
|
||||||
|
<preproc:fragments>
|
||||||
|
<xsl:for-each select="preproc:symtable/preproc:sym">
|
||||||
|
<xsl:variable name="result">
|
||||||
|
<xsl:apply-templates select="." mode="preproc:compile-fragments" />
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:if test="$result != ''">
|
||||||
|
<preproc:fragment id="{@name}">
|
||||||
|
<xsl:value-of select="$result" />
|
||||||
|
</preproc:fragment>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:for-each>
|
||||||
|
</preproc:fragments>
|
||||||
|
</xsl:copy>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="preproc:sym[ @src ]" mode="preproc:compile-fragments" priority="9">
|
||||||
|
<!-- do not compile external symbols -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="preproc:sym" mode="preproc:compile-fragments" priority="1">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>[jsc] fatal: unknown symbol type for `</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>': </xsl:text>
|
||||||
|
<xsl:value-of select="@type" />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="preproc:sym[ @type='rate' ]" mode="preproc:compile-fragments" priority="5">
|
||||||
|
<xsl:variable name="name" select="@name" />
|
||||||
|
<xsl:variable name="pkg" as="element( lv:package )"
|
||||||
|
select="root(.)" />
|
||||||
|
|
||||||
|
<!-- could be one of two places -->
|
||||||
|
<xsl:apply-templates mode="compile" select="
|
||||||
|
$pkg/lv:rate[ @yields=$name ]
|
||||||
|
, $pkg/lv:rate-group/lv:rate[ @yields=$name ]
|
||||||
|
" />
|
||||||
|
</xsl:template>
|
||||||
|
<xsl:template match="preproc:sym[ @type='gen' ]" mode="preproc:compile-fragments" priority="5">
|
||||||
|
<!-- compiled by above -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="preproc:sym[ @type='class' ]" mode="preproc:compile-fragments" priority="5">
|
||||||
|
<!-- name is 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="compile" />
|
||||||
|
</xsl:template>
|
||||||
|
<xsl:template match="preproc:sym[ @type='cgen' ]" mode="preproc:compile-fragments" priority="5">
|
||||||
|
<!-- compiled by above -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="preproc:sym[ @type='func' ]" mode="preproc:compile-fragments" 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="compile" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="preproc:sym[ @type='param' ]" mode="preproc:compile-fragments" priority="5">
|
||||||
|
<xsl:variable name="name" select="@name" />
|
||||||
|
<xsl:variable name="pkg" as="element( lv:package )"
|
||||||
|
select="root(.)" />
|
||||||
|
|
||||||
|
<xsl:apply-templates select="$pkg/lv:param[ @name=$name ]" mode="compile" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="preproc:sym[ @type='type' ]" mode="preproc:compile-fragments" priority="5">
|
||||||
|
<xsl:variable name="name" select="@name" />
|
||||||
|
<xsl:variable name="pkg" as="element( lv:package )"
|
||||||
|
select="root(.)" />
|
||||||
|
|
||||||
|
<!-- a typedef can stand on its own or exist within another typedef -->
|
||||||
|
<xsl:apply-templates mode="compile" select="
|
||||||
|
$pkg/lv:typedef[ @name=$name ]
|
||||||
|
, $pkg//lv:typedef//lv:typedef[ @name=$name ]
|
||||||
|
" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="preproc:sym[ @type='const' ]" mode="preproc:compile-fragments" priority="5">
|
||||||
|
<xsl:variable name="name" select="@name" />
|
||||||
|
<xsl:variable name="pkg" as="element( lv:package )"
|
||||||
|
select="root(.)" />
|
||||||
|
|
||||||
|
<xsl:apply-templates select="$pkg/lv:const[ @name=$name ]" mode="compile" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="preproc:sym[ @type='tpl' ]" mode="preproc:compile-fragments" priority="5">
|
||||||
|
<!-- templates are for the preprocessor only -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="preproc:sym[ @type='lparam' ]" mode="preproc:compile-fragments" priority="5">
|
||||||
|
<!-- they're local and therefore compiled as part of the containing block -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="preproc:sym[ @type='meta' ]"
|
||||||
|
mode="preproc:compile-fragments" priority="5">
|
||||||
|
<xsl:variable name="name" select="substring-after( @name, ':meta:' )" />
|
||||||
|
<xsl:variable name="pkg" as="element( lv:package )"
|
||||||
|
select="root(.)" />
|
||||||
|
|
||||||
|
<xsl:variable name="node" as="element( lv:prop )"
|
||||||
|
select="$pkg/lv:meta/lv:prop[ @name=$name ]" />
|
||||||
|
<xsl:apply-templates mode="compile"
|
||||||
|
select="$node" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,95 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Compiles rater XML into JavaScript
|
||||||
|
|
||||||
|
This stylesheet should be included by whatever is doing the processing and is
|
||||||
|
responsible for outputting the generated code in whatever manner is
|
||||||
|
appropriate (inline JS, a file, etc).
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:stylesheet version="1.0"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:log="http://www.lovullo.com/logger">
|
||||||
|
|
||||||
|
<xsl:template name="log:info">
|
||||||
|
<xsl:param name="name" />
|
||||||
|
<xsl:param name="msg" />
|
||||||
|
|
||||||
|
<xsl:message>
|
||||||
|
<xsl:if test="$name">
|
||||||
|
<xsl:text>[</xsl:text>
|
||||||
|
<xsl:value-of select="$name" />
|
||||||
|
<xsl:text>] </xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:value-of select="$msg" />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="log:debug">
|
||||||
|
<xsl:param name="name" />
|
||||||
|
<xsl:param name="msg" />
|
||||||
|
|
||||||
|
<xsl:message>
|
||||||
|
<xsl:if test="$name">
|
||||||
|
<xsl:text>[</xsl:text>
|
||||||
|
<xsl:value-of select="$name" />
|
||||||
|
<xsl:text>] </xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:value-of select="$msg" />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="log:warn">
|
||||||
|
<xsl:param name="name" />
|
||||||
|
<xsl:param name="msg" />
|
||||||
|
|
||||||
|
<xsl:message>
|
||||||
|
<xsl:if test="$name">
|
||||||
|
<xsl:text>[</xsl:text>
|
||||||
|
<xsl:value-of select="$name" />
|
||||||
|
<xsl:text>] warning: </xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:value-of select="$msg" />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="log:error">
|
||||||
|
<xsl:param name="name" />
|
||||||
|
<xsl:param name="msg" />
|
||||||
|
<xsl:param name="terminate" select="'yes'" />
|
||||||
|
|
||||||
|
<xsl:message terminate="{$terminate}">
|
||||||
|
<xsl:if test="$msg">
|
||||||
|
<xsl:if test="$name">
|
||||||
|
<xsl:text>[</xsl:text>
|
||||||
|
<xsl:value-of select="$name" />
|
||||||
|
<xsl:text>] error: </xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:value-of select="$msg" />
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="log:internal-error">
|
||||||
|
<xsl:param name="name" />
|
||||||
|
<xsl:param name="msg" />
|
||||||
|
<xsl:param name="terminate" select="'yes'" />
|
||||||
|
|
||||||
|
<xsl:message terminate="{$terminate}">
|
||||||
|
<xsl:if test="$name">
|
||||||
|
<xsl:text>[</xsl:text>
|
||||||
|
<xsl:value-of select="$name" />
|
||||||
|
<xsl:text>] internal error: </xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:value-of select="$msg" />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,997 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Compiles map fragments to produce a map from source data to a destination.
|
||||||
|
|
||||||
|
The source fields will be validated at compile-time to ensure that they exist;
|
||||||
|
destination fields should be checked by the compiler and/or linker. The linker
|
||||||
|
is responsible for assembling the fragments into a working map function.
|
||||||
|
|
||||||
|
When linking, the special head and tail fragments of the topmost map should be
|
||||||
|
used (that is, if A includes B and C, use A).
|
||||||
|
|
||||||
|
XXX: This is tightly coupled with the Program UI; refactor to support any type
|
||||||
|
of source.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns:lvm="http://www.lovullo.com/rater/map"
|
||||||
|
xmlns:lvmc="http://www.lovullo.com/rater/map/compiler"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc"
|
||||||
|
|
||||||
|
xmlns:lv="http://www.lovullo.com/rater"
|
||||||
|
xmlns:c="http://www.lovullo.com/calc"
|
||||||
|
xmlns:lvp="http://www.lovullo.com">
|
||||||
|
|
||||||
|
|
||||||
|
<param name="map-noterminate" select="'no'" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Turn on/off unused param checks
|
||||||
|
|
||||||
|
This is useful for, say, the global classifier, where a param may end up not
|
||||||
|
being used if it's used in external classifications.
|
||||||
|
-->
|
||||||
|
<param name="unused-param-check" select="'true'" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Generate a function that maps a set of inputs to a set of outputs
|
||||||
|
-->
|
||||||
|
<template match="lvm:program-map" mode="lvmc:compile" priority="8">
|
||||||
|
<param name="rater" />
|
||||||
|
|
||||||
|
<variable name="program-ui" select="
|
||||||
|
document( concat( @src, '.xml' ), . )/lvp:program
|
||||||
|
" />
|
||||||
|
|
||||||
|
<variable name="map" select="." />
|
||||||
|
|
||||||
|
<variable name="vresult">
|
||||||
|
<choose>
|
||||||
|
<when test="$program-ui">
|
||||||
|
<apply-templates select="." mode="lvmc:validate-ui">
|
||||||
|
<with-param name="ui" select="$program-ui" />
|
||||||
|
</apply-templates>
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<otherwise>
|
||||||
|
<message terminate="yes">
|
||||||
|
<text>fatal: program UI source XML not found</text>
|
||||||
|
</message>
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</variable>
|
||||||
|
|
||||||
|
<if test="
|
||||||
|
$vresult/lvmc:terminate
|
||||||
|
and $map-noterminate = 'no'
|
||||||
|
">
|
||||||
|
<message terminate="yes">!!! Terminating due to errors.</message>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<!-- we need to use an lv-namespaced node so that we are recognized
|
||||||
|
consistently with the rest of the system -->
|
||||||
|
<variable name="pkg">
|
||||||
|
<lv:package name="{$__srcpkg}" lvmc:type="map">
|
||||||
|
<!-- initial symbol table; full table will be generated below -->
|
||||||
|
<call-template name="lvmc:stub-symtable">
|
||||||
|
<with-param name="type-prefix" select="'map'" />
|
||||||
|
</call-template>
|
||||||
|
|
||||||
|
<!-- copy all source nodes -->
|
||||||
|
<copy-of select="*" />
|
||||||
|
|
||||||
|
<preproc:fragments>
|
||||||
|
<!-- special fragment to be output as the head -->
|
||||||
|
<preproc:fragment id=":map:___head">
|
||||||
|
<!-- use a callback just in case we need to make portions of this async in the
|
||||||
|
future -->
|
||||||
|
<text>function( input, callback ) {</text>
|
||||||
|
<text>var output = {};</text>
|
||||||
|
</preproc:fragment>
|
||||||
|
|
||||||
|
<!-- compile mapped -->
|
||||||
|
<apply-templates select="./lvm:*" mode="lvmc:compile">
|
||||||
|
<with-param name="rater" select="$rater" />
|
||||||
|
<with-param name="type" select="'map'" />
|
||||||
|
</apply-templates>
|
||||||
|
|
||||||
|
<!-- special fragment to be output as the foot -->
|
||||||
|
<preproc:fragment id=":map:___tail">
|
||||||
|
<text>callback(output);</text>
|
||||||
|
<text>};</text>
|
||||||
|
</preproc:fragment>
|
||||||
|
</preproc:fragments>
|
||||||
|
</lv:package>
|
||||||
|
</variable>
|
||||||
|
|
||||||
|
<!-- output the result after symbol processing -->
|
||||||
|
<call-template name="preproc:gen-deps">
|
||||||
|
<with-param name="pkg" as="element( lv:package )">
|
||||||
|
<apply-templates select="$pkg" mode="preproc:sym-discover">
|
||||||
|
<with-param name="orig-root" select="." />
|
||||||
|
</apply-templates>
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Generate a function that maps a set of rater outputs
|
||||||
|
-->
|
||||||
|
<template match="lvm:return-map" mode="lvmc:compile" priority="8">
|
||||||
|
<param name="rater" />
|
||||||
|
|
||||||
|
<variable name="pkg">
|
||||||
|
<lv:package name="{$__srcpkg}" lvmc:type="retmap">
|
||||||
|
<!-- initial symbol table; full table will be generated below -->
|
||||||
|
<call-template name="lvmc:stub-symtable">
|
||||||
|
<with-param name="type-prefix" select="'retmap'" />
|
||||||
|
</call-template>
|
||||||
|
|
||||||
|
<!-- copy source data -->
|
||||||
|
<copy-of select="*" />
|
||||||
|
|
||||||
|
<preproc:fragments>
|
||||||
|
<!-- special fragment to be output as the head -->
|
||||||
|
<preproc:fragment id=":retmap:___head">
|
||||||
|
<!-- use a callback just in case we need to make portions of this async in the
|
||||||
|
future -->
|
||||||
|
<text>function ( input, callback ) {</text>
|
||||||
|
<text>var output = {};</text>
|
||||||
|
</preproc:fragment>
|
||||||
|
|
||||||
|
<apply-templates select="./lvm:*" mode="lvmc:compile">
|
||||||
|
<with-param name="rater" select="$rater" />
|
||||||
|
<with-param name="type" select="'retmap'" />
|
||||||
|
</apply-templates>
|
||||||
|
|
||||||
|
<!-- special fragment to be output as the foot -->
|
||||||
|
<preproc:fragment id=":retmap:___tail">
|
||||||
|
<text>callback(output);</text>
|
||||||
|
<text>}</text>
|
||||||
|
</preproc:fragment>
|
||||||
|
</preproc:fragments>
|
||||||
|
</lv:package>
|
||||||
|
</variable>
|
||||||
|
|
||||||
|
<!-- output the result after symbol processing -->
|
||||||
|
<call-template name="preproc:gen-deps">
|
||||||
|
<with-param name="pkg" as="element( lv:package )">
|
||||||
|
<apply-templates select="$pkg" mode="preproc:sym-discover">
|
||||||
|
<with-param name="orig-root" select="." />
|
||||||
|
</apply-templates>
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template name="lvmc:stub-symtable">
|
||||||
|
<param name="type-prefix" select="'map'" />
|
||||||
|
|
||||||
|
<preproc:symtable>
|
||||||
|
<!-- purposely non-polluting. @ignore-dup is intended to be
|
||||||
|
temporary until static generation of these names is resolved;
|
||||||
|
this will not cause problems, since the code is always the
|
||||||
|
same (future bug pending!) -->
|
||||||
|
<preproc:sym name=":{$type-prefix}:___head"
|
||||||
|
type="{$type-prefix}:head"
|
||||||
|
ignore-dup="true" />
|
||||||
|
<preproc:sym name=":{$type-prefix}:___tail"
|
||||||
|
type="{$type-prefix}:tail"
|
||||||
|
ignore-dup="true" />
|
||||||
|
</preproc:symtable>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template name="lvmc:mapsym">
|
||||||
|
<param name="name" />
|
||||||
|
<param name="from" />
|
||||||
|
<param name="type-prefix" select="/lv:package/@lvmc:type" />
|
||||||
|
|
||||||
|
<!-- allow mappings to be overridden after import, which allows defaults
|
||||||
|
to be set and then overridden -->
|
||||||
|
<preproc:sym name=":{$type-prefix}:{$name}" virtual="true"
|
||||||
|
type="{$type-prefix}" pollute="true">
|
||||||
|
|
||||||
|
<!-- for consistency and cleanliness, only copy over if set -->
|
||||||
|
<if test="@override='true'">
|
||||||
|
<copy-of select="@override" />
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<copy-of select="@affects-eligibility" />
|
||||||
|
|
||||||
|
<!-- only copy from data if present -->
|
||||||
|
<if test="$from">
|
||||||
|
<copy-of select="$from" />
|
||||||
|
</if>
|
||||||
|
</preproc:sym>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Directly map an input to the output
|
||||||
|
-->
|
||||||
|
<template match="lvm:pass" mode="lvmc:compile" priority="5">
|
||||||
|
<param name="rater" />
|
||||||
|
<param name="type" />
|
||||||
|
|
||||||
|
<preproc:fragment id=":{$type}:{@name}">
|
||||||
|
<text>output['</text>
|
||||||
|
<value-of select="@name" />
|
||||||
|
<text>']=</text>
|
||||||
|
<call-template name="lvmc:gen-input-default">
|
||||||
|
<with-param name="rater" select="$rater" />
|
||||||
|
<with-param name="to" select="@name" />
|
||||||
|
<with-param name="from" select="@name" />
|
||||||
|
</call-template>
|
||||||
|
<text>;</text>
|
||||||
|
|
||||||
|
<!-- newline to make output reading and debugging easier -->
|
||||||
|
<text> </text>
|
||||||
|
</preproc:fragment>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:pass" mode="preproc:symtable" priority="5">
|
||||||
|
<call-template name="lvmc:mapsym">
|
||||||
|
<with-param name="name" select="@name" />
|
||||||
|
<with-param name="from">
|
||||||
|
<preproc:from name="{@name}" />
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:pass" mode="preproc:depgen" priority="5">
|
||||||
|
<preproc:sym-ref name="{@name}" lax="true" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Maps an input to an output of a different name
|
||||||
|
-->
|
||||||
|
<template match="lvm:map[ @from ]" mode="lvmc:compile" priority="5">
|
||||||
|
<param name="rater" />
|
||||||
|
<param name="type" />
|
||||||
|
|
||||||
|
<!-- if src and dest are identical, then it may as well be lvm:pass -->
|
||||||
|
<if test="@to = @from">
|
||||||
|
<message>
|
||||||
|
<text>[map] notice: `</text>
|
||||||
|
<value-of select="@to" />
|
||||||
|
<!-- TODO: get namespace prefix from name() -->
|
||||||
|
<text>' has a destination of the same name; use lvm:pass instead</text>
|
||||||
|
</message>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<preproc:fragment id=":{$type}:{@to}">
|
||||||
|
<text>output['</text>
|
||||||
|
<value-of select="@to" />
|
||||||
|
<text>']=</text>
|
||||||
|
<call-template name="lvmc:gen-input-default">
|
||||||
|
<with-param name="rater" select="$rater" />
|
||||||
|
<with-param name="to" select="@to" />
|
||||||
|
<with-param name="from" select="@from" />
|
||||||
|
</call-template>
|
||||||
|
<text>;</text>
|
||||||
|
|
||||||
|
<!-- newline to make output reading and debugging easier -->
|
||||||
|
<text> </text>
|
||||||
|
</preproc:fragment>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="lvmc:sym-from" match="lvm:map[ @from ]" mode="preproc:symtable" priority="5">
|
||||||
|
<call-template name="lvmc:mapsym">
|
||||||
|
<with-param name="name" select="@to" />
|
||||||
|
<with-param name="from">
|
||||||
|
<preproc:from name="{@from}" />
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map[ @from
|
||||||
|
and root(.)/@lvmc:type = 'map' ]"
|
||||||
|
mode="preproc:depgen" priority="5">
|
||||||
|
<!-- to the DSL -->
|
||||||
|
<preproc:sym-ref name="{@to}" lax="true" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map[ @from
|
||||||
|
and root(.)/@lvmc:type = 'retmap' ]"
|
||||||
|
mode="preproc:depgen" priority="5">
|
||||||
|
<!-- from the DSL -->
|
||||||
|
<preproc:sym-ref name="{@from}" lax="true" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map[ @from ]" mode="preproc:depgen" priority="4">
|
||||||
|
<message terminate="yes"
|
||||||
|
select="'internal error: unhandled lvm:map: ', ." />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="/*[ @lvmc:type='retmap' ]//lvm:map[ @from ]" mode="preproc:depgen" priority="6">
|
||||||
|
<preproc:sym-ref name="{@from}" lax="true" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Triggers dependency generation on the source document, which contains far more
|
||||||
|
information than our symbol table
|
||||||
|
-->
|
||||||
|
<template match="preproc:sym[ @type='map' ]" mode="preproc:depgen" priority="6">
|
||||||
|
<variable name="name" select="substring-after( @name, ':map:' )" />
|
||||||
|
<variable name="pkg" as="element( lv:package )"
|
||||||
|
select="root(.)" />
|
||||||
|
|
||||||
|
<apply-templates mode="preproc:depgen"
|
||||||
|
select="$pkg/lvm:*[ @name=$name or @to=$name ]" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- FIXME: this is a cluster -->
|
||||||
|
<template match="preproc:sym[ @type='retmap' ]" mode="preproc:depgen" priority="6">
|
||||||
|
<variable name="from" as="element( preproc:from )*"
|
||||||
|
select="preproc:from" />
|
||||||
|
|
||||||
|
<if test="$from">
|
||||||
|
<variable name="src-name" as="xs:string"
|
||||||
|
select="substring-after( @name, ':retmap:' )" />
|
||||||
|
|
||||||
|
<variable name="name" as="xs:string+"
|
||||||
|
select="$from/@name" />
|
||||||
|
|
||||||
|
<variable name="pkg" as="element( lv:package )"
|
||||||
|
select="root(.)" />
|
||||||
|
|
||||||
|
<variable name="src-node" as="element()+"
|
||||||
|
select="$pkg/lvm:*[ @name = $src-name
|
||||||
|
or @to = $src-name ]" />
|
||||||
|
|
||||||
|
<if test="count( $src-node ) gt count( $from )">
|
||||||
|
<message terminate="yes"
|
||||||
|
select="'error: duplicate source identifier: ',
|
||||||
|
$src-name" />
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<apply-templates mode="preproc:depgen"
|
||||||
|
select="$src-node" />
|
||||||
|
</if>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
These guys have no dependencies; handle them to prevent depgen errors
|
||||||
|
-->
|
||||||
|
<template match="preproc:sym[ @type='map:head' or @type='map:tail' ]" mode="preproc:depgen" priority="2">
|
||||||
|
<!-- do nothing -->
|
||||||
|
</template>
|
||||||
|
<template match="preproc:sym[ @type='retmap:head' or @type='retmap:tail' ]" mode="preproc:depgen" priority="2">
|
||||||
|
<!-- do nothing -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Generate a direct input mapping or, if a default exists for the field, use the
|
||||||
|
default if the input is an empty string
|
||||||
|
|
||||||
|
XXX: This is broken; $rater is not provided at the entry point, and
|
||||||
|
if it were, this needs to reference its symbol table.
|
||||||
|
-->
|
||||||
|
<template name="lvmc:gen-input-default">
|
||||||
|
<param name="rater" />
|
||||||
|
<param name="to" />
|
||||||
|
<!-- use one or the other; latter takes precedence -->
|
||||||
|
<param name="from" />
|
||||||
|
<param name="from-str" />
|
||||||
|
|
||||||
|
<variable name="default">
|
||||||
|
<if test="$rater">
|
||||||
|
<value-of select="concat( '''',
|
||||||
|
lvmc:escape-string(
|
||||||
|
$rater/lv:param[ @name=$to ]/@default ),
|
||||||
|
'''' )" />
|
||||||
|
</if>
|
||||||
|
</variable>
|
||||||
|
|
||||||
|
<variable name="from-var">
|
||||||
|
<choose>
|
||||||
|
<when test="$from-str">
|
||||||
|
<value-of select="$from-str" />
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<otherwise>
|
||||||
|
<text>input['</text>
|
||||||
|
<value-of select="$from" />
|
||||||
|
<text>']</text>
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</variable>
|
||||||
|
|
||||||
|
<choose>
|
||||||
|
<when test="$default and not( $default = '' )">
|
||||||
|
<text>set_defaults(</text>
|
||||||
|
<value-of select="$from-var" />
|
||||||
|
<text>,'</text>
|
||||||
|
<value-of select="$default" />
|
||||||
|
<text>')</text>
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<otherwise>
|
||||||
|
<value-of select="$from-var" />
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Maps a static value to the output
|
||||||
|
-->
|
||||||
|
<template match="lvm:map[ @value ]" mode="lvmc:compile" priority="5">
|
||||||
|
<param name="type" />
|
||||||
|
|
||||||
|
<preproc:fragment id=":{$type}:{@to}">
|
||||||
|
<text>output['</text>
|
||||||
|
<value-of select="@to" />
|
||||||
|
<text>']='</text>
|
||||||
|
<value-of select="normalize-space( @value )" />
|
||||||
|
<text>';</text>
|
||||||
|
|
||||||
|
<!-- newline to make output reading and debugging easier -->
|
||||||
|
<text> </text>
|
||||||
|
</preproc:fragment>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map[ @value ]" mode="preproc:symtable" priority="5">
|
||||||
|
<call-template name="lvmc:mapsym">
|
||||||
|
<with-param name="name" select="@to" />
|
||||||
|
</call-template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="lvm:map[*]" mode="lvmc:compile" priority="5">
|
||||||
|
<param name="rater" />
|
||||||
|
<param name="type" />
|
||||||
|
|
||||||
|
<preproc:fragment id=":{$type}:{@to}">
|
||||||
|
<text>output['</text>
|
||||||
|
<value-of select="@to" />
|
||||||
|
<text>']=</text>
|
||||||
|
|
||||||
|
<apply-templates select="./lvm:*" mode="lvmc:compile">
|
||||||
|
<with-param name="rater" select="$rater" />
|
||||||
|
</apply-templates>
|
||||||
|
|
||||||
|
<text>;</text>
|
||||||
|
|
||||||
|
<!-- newline to make output reading and debugging easier -->
|
||||||
|
<text> </text>
|
||||||
|
</preproc:fragment>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map[ * ]" mode="preproc:symtable" priority="5">
|
||||||
|
<param name="to" select="@to" />
|
||||||
|
|
||||||
|
<call-template name="lvmc:mapsym">
|
||||||
|
<with-param name="name" select="$to" />
|
||||||
|
<with-param name="from">
|
||||||
|
<for-each select=".//lvm:from">
|
||||||
|
<preproc:from name="{@name}" />
|
||||||
|
</for-each>
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="/*[ @lvmc:type='retmap' ]/lvm:map[ * ]" mode="preproc:symtable" priority="6">
|
||||||
|
<variable name="to" select="@to" />
|
||||||
|
|
||||||
|
<call-template name="lvmc:mapsym">
|
||||||
|
<with-param name="name" select="$to" />
|
||||||
|
<with-param name="from">
|
||||||
|
<for-each select=".//lvm:from">
|
||||||
|
<preproc:from name="{@name}" />
|
||||||
|
</for-each>
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map[ * ]" mode="preproc:depgen" priority="5">
|
||||||
|
<preproc:sym-ref name="{@to}" lax="true" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map[ *
|
||||||
|
and root(.)/@lvmc:type = 'retmap' ]"
|
||||||
|
mode="preproc:depgen" priority="6">
|
||||||
|
<for-each select=".//lvm:from">
|
||||||
|
<preproc:sym-ref name="{@name}" lax="true" />
|
||||||
|
</for-each>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<template match="lvm:const" mode="lvmc:compile" priority="5">
|
||||||
|
<text>'</text>
|
||||||
|
<value-of select="@value" />
|
||||||
|
<text>'</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map//lvm:set[@each]" mode="lvmc:compile" priority="5">
|
||||||
|
<text>(function(){</text>
|
||||||
|
<text>var ret=[];</text>
|
||||||
|
<text>var len=input['</text>
|
||||||
|
<value-of select="@each" />
|
||||||
|
<text>'].length;</text>
|
||||||
|
|
||||||
|
<text>for(var _i=0;_i<len;_i++){</text>
|
||||||
|
<text>var </text>
|
||||||
|
<value-of select="@index" />
|
||||||
|
<text>=_i;</text>
|
||||||
|
|
||||||
|
<text>ret[_i]=</text>
|
||||||
|
<apply-templates select="./lvm:*" mode="lvmc:compile" />
|
||||||
|
<text>;</text>
|
||||||
|
<text>}</text>
|
||||||
|
|
||||||
|
<text>return ret;</text>
|
||||||
|
<text>})()</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map//lvm:set[@ignore-empty='true']" mode="lvmc:compile" priority="3">
|
||||||
|
<text>(function(){</text>
|
||||||
|
<text>var ret=[]; var tmp;</text>
|
||||||
|
|
||||||
|
<for-each select="./lvm:*">
|
||||||
|
<text>tmp=</text>
|
||||||
|
<apply-templates select="." mode="lvmc:compile" />
|
||||||
|
<text>;</text>
|
||||||
|
|
||||||
|
<text>if(tmp&&tmp!=='0')ret.push(tmp);</text>
|
||||||
|
</for-each>
|
||||||
|
|
||||||
|
<text>return ret;</text>
|
||||||
|
<text>})()</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map//lvm:set" mode="lvmc:compile" priority="2">
|
||||||
|
<text>[</text>
|
||||||
|
<for-each select="./lvm:*">
|
||||||
|
<if test="position() > 1">
|
||||||
|
<text>,</text>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<apply-templates select="." mode="lvmc:compile" />
|
||||||
|
</for-each>
|
||||||
|
<text>]</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map//lvm:static" mode="lvmc:compile" priority="5">
|
||||||
|
<text>'</text>
|
||||||
|
<value-of select="@value" />
|
||||||
|
<text>'</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="lvm:map//lvm:from[*]" mode="lvmc:compile" priority="5">
|
||||||
|
<param name="rater" />
|
||||||
|
|
||||||
|
<variable name="to" select="ancestor::lvm:map/@to" />
|
||||||
|
|
||||||
|
<variable name="nested" as="xs:boolean"
|
||||||
|
select="exists( ancestor::lvm:from )" />
|
||||||
|
|
||||||
|
<!-- oval = orig val -->
|
||||||
|
<text>(function(oval){</text>
|
||||||
|
<text>var val = ( (oval||'').length ) ? oval : [oval]; </text>
|
||||||
|
<text>var ret = []; </text>
|
||||||
|
|
||||||
|
<if test="not( $nested )">
|
||||||
|
<text>var curindex;</text>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<text>for ( var i = 0, l = val.length; i<l; i++ ){</text>
|
||||||
|
<if test="not( $nested )">
|
||||||
|
<text>curindex = i;</text>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<!-- note that we're casting the value to a string; this is important,
|
||||||
|
since case comparisons are strict (===) -->
|
||||||
|
<text>switch(''+val[i]){</text>
|
||||||
|
<apply-templates mode="lvmc:compile" />
|
||||||
|
|
||||||
|
<if test="not( lvm:default )">
|
||||||
|
<text>default: ret.push(</text>
|
||||||
|
<choose>
|
||||||
|
<!-- give precedence to explicit default -->
|
||||||
|
<when test="@default">
|
||||||
|
<sequence select="concat( '''',
|
||||||
|
lvmc:escape-string( @default ),
|
||||||
|
'''' )" />
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<!-- otherwise, generate one -->
|
||||||
|
<otherwise>
|
||||||
|
<call-template name="lvmc:gen-input-default">
|
||||||
|
<with-param name="rater" select="$rater" />
|
||||||
|
<with-param name="to" select="$to" />
|
||||||
|
<with-param name="from-str">
|
||||||
|
<text>''+val[i]</text>
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
<text>);</text>
|
||||||
|
</if>
|
||||||
|
<text>}</text>
|
||||||
|
<text>}</text>
|
||||||
|
|
||||||
|
<choose>
|
||||||
|
<when test="@scalar='true'">
|
||||||
|
<text>return ret[0]; </text>
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<otherwise>
|
||||||
|
<text>return ret; </text>
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
|
||||||
|
<text>})(input['</text>
|
||||||
|
<value-of select="@name" />
|
||||||
|
<text>']</text>
|
||||||
|
|
||||||
|
<if test="$nested">
|
||||||
|
<text>[curindex]</text>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<text>)</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="lvm:map//lvm:from" mode="lvmc:compile" priority="2">
|
||||||
|
<variable name="nested" as="xs:boolean"
|
||||||
|
select="exists( ancestor::lvm:from )" />
|
||||||
|
|
||||||
|
<text>input['</text>
|
||||||
|
<value-of select="@name" />
|
||||||
|
<text>']</text>
|
||||||
|
|
||||||
|
<choose>
|
||||||
|
<when test="@index">
|
||||||
|
<text>[</text>
|
||||||
|
<value-of select="@index" />
|
||||||
|
<text>]</text>
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<when test="$nested">
|
||||||
|
<text>[curindex]</text>
|
||||||
|
</when>
|
||||||
|
</choose>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="lvm:from/lvm:default"
|
||||||
|
mode="lvmc:compile" priority="5">
|
||||||
|
<sequence select="concat(
|
||||||
|
'default:ret.push(',
|
||||||
|
string-join(
|
||||||
|
lvmc:concat-compile( element(), () ),
|
||||||
|
'' ),
|
||||||
|
');' )" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="lvm:map//lvm:value"
|
||||||
|
mode="lvmc:compile" priority="5">
|
||||||
|
<sequence select="concat( '''', text(), '''' )" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="lvm:map//lvm:from/lvm:translate" mode="lvmc:compile" priority="5">
|
||||||
|
<text>case '</text>
|
||||||
|
<value-of select="@key" />
|
||||||
|
<text>':</text>
|
||||||
|
<apply-templates select="." mode="lvmc:compile-translate" />
|
||||||
|
<text> break;</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="lvm:translate[ element() ]"
|
||||||
|
mode="lvmc:compile-translate" priority="5">
|
||||||
|
<sequence select="concat(
|
||||||
|
'ret.push(',
|
||||||
|
string-join(
|
||||||
|
lvmc:concat-compile( element(), @empty ),
|
||||||
|
'' ),
|
||||||
|
');' )" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<function name="lvmc:concat-compile" as="xs:string+">
|
||||||
|
<param name="children" as="element()+" />
|
||||||
|
<param name="default" as="xs:string?" />
|
||||||
|
|
||||||
|
<text>(function(){</text>
|
||||||
|
<!-- end result should compile into a (dynamic) string -->
|
||||||
|
<text>var result=</text>
|
||||||
|
<for-each select="$children">
|
||||||
|
<if test="position() > 1">
|
||||||
|
<text> + </text>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<apply-templates mode="lvmc:compile"
|
||||||
|
select="." />
|
||||||
|
</for-each>
|
||||||
|
<text>;</text>
|
||||||
|
|
||||||
|
<text>return (result === "") ? '</text>
|
||||||
|
<sequence select="lvmc:escape-string( $default )" />
|
||||||
|
<text>' : result;</text>
|
||||||
|
<text>})()</text>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
<function name="lvmc:escape-string" as="xs:string">
|
||||||
|
<param name="str" as="xs:string?" />
|
||||||
|
|
||||||
|
<sequence select="replace( $str, '''', '\\''' )" />
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="lvm:translate"
|
||||||
|
mode="lvmc:compile-translate" priority="1">
|
||||||
|
<text>ret.push('</text>
|
||||||
|
<value-of select="normalize-space( @value )" />
|
||||||
|
<text>');</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="text()|comment()" mode="lvmc:compile" priority="1">
|
||||||
|
<!-- strip all text and comments -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="*" mode="lvmc:compile" priority="1">
|
||||||
|
<message terminate="yes">
|
||||||
|
<text>fatal: invalid map: unexpected node </text>
|
||||||
|
<apply-templates select="." mode="lvmc:pathout" />
|
||||||
|
</message>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="lvm:import|lvm:class" mode="lvmc:compile" priority="2">
|
||||||
|
<!-- ignore -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- import symbols -->
|
||||||
|
<template match="lvm:import" mode="preproc:symtable" priority="5">
|
||||||
|
<!-- original root passed to sym-discover -->
|
||||||
|
<param name="orig-root" />
|
||||||
|
|
||||||
|
<!-- perform symbol import -->
|
||||||
|
<call-template name="preproc:symimport">
|
||||||
|
<with-param name="orig-root" select="$orig-root" />
|
||||||
|
<with-param name="package" select="@path" />
|
||||||
|
<with-param name="export" select="'true'" />
|
||||||
|
</call-template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="*" mode="lvmc:pathout">
|
||||||
|
<if test="parent::*">
|
||||||
|
<apply-templates select="parent::*" mode="lvmc:pathout" />
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<text>/</text>
|
||||||
|
<value-of select="name()" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Outputs a simple pass-through map that may be used if no map is present
|
||||||
|
|
||||||
|
This simply calls the callback with the given input after creating a new
|
||||||
|
object with it as the prototype, ensuring that altered data does not impact
|
||||||
|
the original data.
|
||||||
|
-->
|
||||||
|
<template name="lvmc:dummy-map">
|
||||||
|
<param name="name" select="'map'" />
|
||||||
|
|
||||||
|
<text>function </text>
|
||||||
|
<value-of select="$name" />
|
||||||
|
<text>( input, callback ) { </text>
|
||||||
|
<!-- protect input against potential mutilation from classifier -->
|
||||||
|
<text>var prot = function() {}; </text>
|
||||||
|
<text>prot.prototype = input; </text>
|
||||||
|
<text>callback( new prot() );</text>
|
||||||
|
<text> }</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Validates map between program and the rater, checking for errors that would
|
||||||
|
cause significant problems.
|
||||||
|
-->
|
||||||
|
<template match="lvm:program-map" mode="lvmc:validate-rater">
|
||||||
|
<param name="rater" />
|
||||||
|
|
||||||
|
<variable name="map" select="." />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Get a list of all fields that have not been mapped
|
||||||
|
-->
|
||||||
|
<variable name="nomap" select="
|
||||||
|
$rater/lv:param[
|
||||||
|
not(
|
||||||
|
@name=$map//lvm:pass/@name
|
||||||
|
or @name=$map//lvm:map/@to
|
||||||
|
)
|
||||||
|
]
|
||||||
|
" />
|
||||||
|
|
||||||
|
<!-- required and unmapped -->
|
||||||
|
<variable name="req-nomap" select="
|
||||||
|
$nomap[ not( @default ) or @default='' ]
|
||||||
|
" />
|
||||||
|
|
||||||
|
<!-- warning on non-mapped, but not required -->
|
||||||
|
<for-each select="$nomap[ @default ]">
|
||||||
|
<message>
|
||||||
|
<text>! [map warning] unmapped optional field: </text>
|
||||||
|
<value-of select="@name" />
|
||||||
|
</message>
|
||||||
|
</for-each>
|
||||||
|
|
||||||
|
<!-- error on required non-mapped -->
|
||||||
|
<for-each select="$req-nomap">
|
||||||
|
<message>
|
||||||
|
<text>!!! [map error] unmapped required field: </text>
|
||||||
|
<value-of select="@name" />
|
||||||
|
</message>
|
||||||
|
</for-each>
|
||||||
|
|
||||||
|
|
||||||
|
<if test="$unused-param-check = 'true'">
|
||||||
|
<variable name="unknown" select="
|
||||||
|
//lvm:pass[
|
||||||
|
not( @name=$rater/lv:param/@name )
|
||||||
|
]
|
||||||
|
|
|
||||||
|
//lvm:map[
|
||||||
|
not( @to=$rater/lv:param/@name )
|
||||||
|
]
|
||||||
|
|
|
||||||
|
//lvm:class[
|
||||||
|
not( @name=$rater/lv:classify/@as )
|
||||||
|
]
|
||||||
|
" />
|
||||||
|
|
||||||
|
<!-- error on unknown -->
|
||||||
|
<for-each select="$unknown">
|
||||||
|
<message>
|
||||||
|
<text>!!! [map error] unknown/unused destination identifier: </text>
|
||||||
|
<value-of select="@name|@to" />
|
||||||
|
</message>
|
||||||
|
</for-each>
|
||||||
|
|
||||||
|
<if test="count( $unknown )">
|
||||||
|
<lvmc:terminate />
|
||||||
|
</if>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- fail. -->
|
||||||
|
<if test="count( $req-nomap )">
|
||||||
|
<lvmc:terminate />
|
||||||
|
</if>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="lvm:program-map" mode="lvmc:validate-ui">
|
||||||
|
<param name="ui" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- get a list of unknown source mappings -->
|
||||||
|
<!-- TODO: this is a mess -->
|
||||||
|
<variable name="unknown-pre" select="
|
||||||
|
.//lvm:pass[
|
||||||
|
not( @name=($ui//lvp:question/@id|$ui//lvp:external/@id) )
|
||||||
|
and not( @name=$ui//lvp:calc/@id )
|
||||||
|
]
|
||||||
|
|
|
||||||
|
.//lvm:map[
|
||||||
|
@from
|
||||||
|
and not( @from=($ui//lvp:question/@id|$ui//lvp:external/@id) )
|
||||||
|
and not( @from=$ui//lvp:calc/@id )
|
||||||
|
]
|
||||||
|
|
|
||||||
|
.//lvm:from[
|
||||||
|
not( @name=($ui//lvp:question/@id|$ui//lvp:external/@id) )
|
||||||
|
and not( @name=$ui//lvp:calc/@id )
|
||||||
|
]
|
||||||
|
|
|
||||||
|
.//lvm:set[
|
||||||
|
@each
|
||||||
|
and not( @each=($ui//lvp:question/@id|$ui//lvp:external/@id) )
|
||||||
|
and not( @each=$ui//lvp:calc/@id )
|
||||||
|
]
|
||||||
|
" />
|
||||||
|
|
||||||
|
<variable name="unknown"
|
||||||
|
select="$unknown-pre[ not( @novalidate='true' ) ]" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- error on unknown -->
|
||||||
|
<for-each select="$unknown">
|
||||||
|
<message>
|
||||||
|
<text>!!! [map error] unknown source field: </text>
|
||||||
|
<value-of select="@name|@from" />
|
||||||
|
</message>
|
||||||
|
</for-each>
|
||||||
|
|
||||||
|
<if test="count( $unknown )">
|
||||||
|
<lvmc:terminate />
|
||||||
|
</if>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Outputs source and dest mappings in a common, easily-referenced format useful
|
||||||
|
for parsing
|
||||||
|
-->
|
||||||
|
<template match="lvm:program-map" mode="lvmc:source-dest-map" priority="5">
|
||||||
|
<lvmc:map>
|
||||||
|
<apply-templates select="./lvm:*" mode="lvmc:source-dest-map" />
|
||||||
|
</lvmc:map>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:pass" mode="lvmc:source-dest-map" priority="5">
|
||||||
|
<lvmc:map from="{@name}" to="{@name}" elig="{@affects-eligibility}" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map[ @from ]" mode="lvmc:source-dest-map" priority="5">
|
||||||
|
<lvmc:map from="{@from}" to="{@to}" elig="{@affects-eligibility}" />
|
||||||
|
</template>
|
||||||
|
<template match="lvm:map/lvm:from" mode="lvmc:source-dest-map" priority="5">
|
||||||
|
<lvmc:map from="{@name}" to="{ancestor::lvm:map/@to}"
|
||||||
|
elig="{@affects-eligibility}" />
|
||||||
|
</template>
|
||||||
|
<template match="lvm:map//lvm:set/lvm:from" mode="lvmc:source-dest-map" priority="4">
|
||||||
|
<!-- not included; not a one-to-one mapping -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map[*]" mode="lvmc:source-dest-map" priority="5">
|
||||||
|
<apply-templates select=".//lvm:*" mode="lvmc:source-dest-map" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:map//lvm:set" mode="lvmc:source-dest-map" priority="2">
|
||||||
|
<!-- do nothing -->
|
||||||
|
</template>
|
||||||
|
<template match="lvm:map//lvm:static" mode="lvmc:source-dest-map" priority="2">
|
||||||
|
<!-- do nothing -->
|
||||||
|
</template>
|
||||||
|
<template match="lvm:map//lvm:value" mode="lvmc:source-dest-map" priority="2">
|
||||||
|
<!-- do nothing -->
|
||||||
|
</template>
|
||||||
|
<template match="lvm:map//lvm:translate" mode="lvmc:source-dest-map" priority="2">
|
||||||
|
<!-- do nothing -->
|
||||||
|
</template>
|
||||||
|
<template match="lvm:map[ @value ]" mode="lvmc:source-dest-map" priority="2">
|
||||||
|
<!-- no source -->
|
||||||
|
</template>
|
||||||
|
<template match="lvm:const" mode="lvmc:source-dest-map" priority="2">
|
||||||
|
<!-- no source -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="lvm:class" mode="lvmc:source-dest-map" priority="2">
|
||||||
|
<!-- not applicable -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="*" mode="lvmc:source-dest-map" priority="1">
|
||||||
|
<message terminate="yes">
|
||||||
|
<text>Unknown node: </text>
|
||||||
|
<value-of select="name()" />
|
||||||
|
</message>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</stylesheet>
|
|
@ -0,0 +1,771 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Validates a document for correctness in a manner that is beyond XSD.
|
||||||
|
|
||||||
|
Schematron is not used for this due to certain complexieis. Furthermore, we
|
||||||
|
already have the data in a package structure that is easy to use and query
|
||||||
|
against.
|
||||||
|
|
||||||
|
Validations that can be expressed in the XSD will not be included here, unless
|
||||||
|
there is significant overlap that would make the XSD representation
|
||||||
|
pointlessly incomplete.
|
||||||
|
|
||||||
|
FIXME: Needs aggresive refactoring after introduction of symbol table, for
|
||||||
|
both performance and maintinance.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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:ext="http://www.lovullo.com/ext"
|
||||||
|
xmlns:c="http://www.lovullo.com/calc"
|
||||||
|
xmlns:lvv="http://www.lovullo.com/rater/validate"
|
||||||
|
xmlns:sym="http://www.lovullo.com/rater/symbol-map"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
<xsl:import href="validate/domain.xsl" />
|
||||||
|
|
||||||
|
<xsl:include href="validate/param.xsl" />
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:param name="prohibit-validation" select="'false'" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- FOR PERFORMANCE: constants may be used for large tables of data -->
|
||||||
|
<xsl:template match="lv:const" mode="lvv:validate" priority="9">
|
||||||
|
<!-- nothing to be done; constants are merely data declarations -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Perform validations on a given rater/package
|
||||||
|
|
||||||
|
Validations will be returned as an RTF (result tree fragment), which can be
|
||||||
|
converted to a NodeSet using exsl:node-set(). All errors are returned in the
|
||||||
|
following format:
|
||||||
|
|
||||||
|
<lvv:error desc="Description of error type>Error details</lvv:error>
|
||||||
|
|
||||||
|
@return error RTF
|
||||||
|
-->
|
||||||
|
<xsl:template match="lv:package" mode="lvv:validate" priority="9">
|
||||||
|
<xsl:param name="symbol-map" />
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$prohibit-validation = 'true'">
|
||||||
|
<xsl:message>
|
||||||
|
<xsl:text>[validate] prohibited; skipping </xsl:text>
|
||||||
|
<xsl:value-of select="local-name()" />
|
||||||
|
<xsl:text> </xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>...</xsl:text>
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:message>
|
||||||
|
<xsl:text>[validate] validating </xsl:text>
|
||||||
|
<xsl:value-of select="local-name()" />
|
||||||
|
<xsl:text> </xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>...</xsl:text>
|
||||||
|
</xsl:message>
|
||||||
|
|
||||||
|
<!-- validate -->
|
||||||
|
<xsl:apply-templates mode="lvv:validate" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="preproc:*" mode="lvv:validate" priority="9">
|
||||||
|
<!-- well that would just be silly -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lv:package[ not( @program='true' ) ]/lv:yield" mode="lvv:validate" priority="5">
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'lv:yield cannot appear within a non-program package'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content" select="." />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="*" mode="lvv:validate" priority="1">
|
||||||
|
<xsl:apply-templates mode="lvv:validate" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lv:template" mode="lvv:validate" priority="9">
|
||||||
|
<!-- do not validate templates; we'll only validate expansions -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template name="lvv:symbol-chk">
|
||||||
|
<xsl:param name="root" />
|
||||||
|
<xsl:param name="symbol-map" />
|
||||||
|
|
||||||
|
<!-- build a symbol list of all used and default symbols -->
|
||||||
|
<xsl:variable name="symlist">
|
||||||
|
<!-- @sym attributes -->
|
||||||
|
<xsl:for-each select="$root//lv:*[@sym]">
|
||||||
|
<lvv:sym value="{@sym}" />
|
||||||
|
</xsl:for-each>
|
||||||
|
|
||||||
|
<!-- defaults from mapping document -->
|
||||||
|
<xsl:for-each select="$symbol-map/sym:symbol[ not( ./* ) ]">
|
||||||
|
<lvv:sym value="{.}" />
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<!-- error for each restricted node -->
|
||||||
|
<xsl:for-each select="
|
||||||
|
$root//lv:*[
|
||||||
|
@sym = $symbol-map/sym:reserved/sym:reserve/@sym
|
||||||
|
]
|
||||||
|
">
|
||||||
|
|
||||||
|
<xsl:variable name="symbol" select="@sym" />
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Symbol is reserved and cannot be used'" />
|
||||||
|
<xsl:with-param name="refnode" select="$root//lv:*[@sym=$symbol]" />
|
||||||
|
<xsl:with-param name="content" select="$symbol" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:for-each>
|
||||||
|
|
||||||
|
<!-- error for each duplicate node -->
|
||||||
|
<xsl:for-each select="
|
||||||
|
$symlist/*[
|
||||||
|
@value = following-sibling::*/@value
|
||||||
|
]
|
||||||
|
">
|
||||||
|
|
||||||
|
<xsl:variable name="symbol" select="@value" />
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Symbol is not unique'" />
|
||||||
|
<xsl:with-param name="refnode" select="$root//lv:*[@sym=$symbol]" />
|
||||||
|
<xsl:with-param name="content" select="$symbol" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="c:apply[@name]" mode="lvv:validate" priority="5">
|
||||||
|
<xsl:variable name="name" select="@name" />
|
||||||
|
<xsl:variable name="self" select="." />
|
||||||
|
<xsl:variable name="fsym" select="
|
||||||
|
root(.)/preproc:symtable/preproc:sym[
|
||||||
|
@type='func'
|
||||||
|
and @name=$name
|
||||||
|
]
|
||||||
|
" />
|
||||||
|
|
||||||
|
<!-- ensure that a function is being applied -->
|
||||||
|
<xsl:if test="not( $fsym )">
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Applying non-function'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content" select="@name" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!-- check that all required arguments are provided -->
|
||||||
|
<xsl:for-each select="
|
||||||
|
$fsym/preproc:sym-ref[
|
||||||
|
concat( ':', $name, ':', @name ) = ancestor::preproc:symtable/preproc:sym[
|
||||||
|
@type='lparam'
|
||||||
|
and not( @default )
|
||||||
|
]
|
||||||
|
]
|
||||||
|
">
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Missing required argument'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text> for application of </xsl:text>
|
||||||
|
<xsl:value-of select="$name" />
|
||||||
|
<xsl:text>()</xsl:text>
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:for-each>
|
||||||
|
|
||||||
|
<xsl:apply-templates mode="lvv:validate" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="c:*[ @index ]/c:index" mode="lvv:validate" priority="9">
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Ambiguous index specification'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content" select="../@name" />
|
||||||
|
</xsl:call-template>
|
||||||
|
|
||||||
|
<xsl:apply-templates mode="lvv:validate" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Validate that match @on's exist
|
||||||
|
-->
|
||||||
|
<xsl:template match="lv:classify[ @as ]//lv:match" mode="lvv:validate" priority="9">
|
||||||
|
<xsl:if test="not( @on=root(.)/preproc:symtable/preproc:sym[ @type ]/@name )">
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Unknown match @on'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:text>`</xsl:text>
|
||||||
|
<xsl:value-of select="@on" />
|
||||||
|
<xsl:text>' is unknown for classification </xsl:text>
|
||||||
|
|
||||||
|
<xsl:variable name="class"
|
||||||
|
select="ancestor::lv:classify" />
|
||||||
|
<xsl:value-of select="if ( $class/@preproc:generated-from ) then
|
||||||
|
$class/@preproc:generated-from
|
||||||
|
else
|
||||||
|
$class/@as" />
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:apply-templates select="." mode="lvv:validate-match" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Validate that non-numeric value matches actually exist and are constants
|
||||||
|
-->
|
||||||
|
<xsl:template match="lv:match[@value]" mode="lvv:validate-match" priority="5">
|
||||||
|
<xsl:if test="
|
||||||
|
not( number( @value ) = @value )
|
||||||
|
and not(
|
||||||
|
@value=root(.)/preproc:symtable/preproc:sym[
|
||||||
|
@type='const'
|
||||||
|
]/@name
|
||||||
|
)
|
||||||
|
">
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Unknown match value'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:text>`</xsl:text>
|
||||||
|
<xsl:value-of select="@value" />
|
||||||
|
<xsl:text>' is unknown for classification </xsl:text>
|
||||||
|
|
||||||
|
<xsl:variable name="class"
|
||||||
|
select="ancestor::lv:classify" />
|
||||||
|
<xsl:value-of select="if ( $class/@preproc:generated-from ) then
|
||||||
|
$class/@preproc:generated-from
|
||||||
|
else
|
||||||
|
$class/@as" />
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:apply-templates mode="lvv:validate-match" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lv:match" mode="lvv:validate-match" priority="2">
|
||||||
|
<xsl:apply-templates mode="lvv:validate-match" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Classification match assumptions must operate only on other classifiers and
|
||||||
|
must assume values that the referenced classifier actually matches on
|
||||||
|
-->
|
||||||
|
<xsl:template match="lv:match/lv:assuming" mode="lvv:validate-match" priority="5">
|
||||||
|
<xsl:variable name="on" select="../@on" />
|
||||||
|
<xsl:variable name="ref" select="root(.)//lv:classify[ @yields=$on ]" />
|
||||||
|
|
||||||
|
<!-- assumptions must only operate on variables mentioned in the referenced
|
||||||
|
classification -->
|
||||||
|
<xsl:for-each select="
|
||||||
|
.//lv:that[
|
||||||
|
not( @name=$ref//lv:match/@on )
|
||||||
|
]
|
||||||
|
">
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Invalid classification assumption'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text> is not used to classify </xsl:text>
|
||||||
|
<xsl:value-of select="$on" />
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="c:*" mode="lvv:validate-match" priority="2">
|
||||||
|
<xsl:apply-templates select="." mode="lvv:validate" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="*" mode="lvv:validate-match" priority="1">
|
||||||
|
<!-- do nothing -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="c:value" mode="lvv:validate" priority="5">
|
||||||
|
<!-- do nothing; just prevent the below validation from occurring -->
|
||||||
|
<xsl:apply-templates mode="lvv:validate" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="c:let" mode="lvv:validate" priority="5">
|
||||||
|
<!-- do not validate this node itself -->
|
||||||
|
<xsl:apply-templates mode="lvv:validate" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="c:*[@name or @of]" mode="lvv:validate" priority="2">
|
||||||
|
<xsl:variable name="name">
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="@of">
|
||||||
|
<xsl:value-of select="@of" />
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<!-- XXX: have to maintain this list! -->
|
||||||
|
<xsl:variable name="nodes" select="
|
||||||
|
root(.)//lv:*[
|
||||||
|
@name=$name
|
||||||
|
or @yields=$name
|
||||||
|
or @as=$name
|
||||||
|
]
|
||||||
|
, root(.)//c:*[
|
||||||
|
@generates=$name
|
||||||
|
]
|
||||||
|
, root(.)//c:values/c:value[ @name=$name ]
|
||||||
|
" />
|
||||||
|
|
||||||
|
<!-- locate function params/let vars -->
|
||||||
|
<xsl:variable name="fname" select="
|
||||||
|
ancestor::lv:function[
|
||||||
|
lv:param[
|
||||||
|
@name=$name
|
||||||
|
]
|
||||||
|
]/@name
|
||||||
|
|ancestor::c:apply[
|
||||||
|
c:arg[
|
||||||
|
@name=$name
|
||||||
|
]
|
||||||
|
]/@name
|
||||||
|
|ancestor::c:let[
|
||||||
|
c:values/c:value[
|
||||||
|
@name=$name
|
||||||
|
]
|
||||||
|
]/@name
|
||||||
|
" />
|
||||||
|
|
||||||
|
<!-- if this name references a function parameter, then it takes
|
||||||
|
precedence (note that this consequently means that it masks any other
|
||||||
|
names that may be globally defined) -->
|
||||||
|
<xsl:variable name="sym" select="
|
||||||
|
if ( $fname ) then
|
||||||
|
root(.)/preproc:symtable/preproc:sym[
|
||||||
|
@name=concat( ':', $fname, ':', $name )
|
||||||
|
]
|
||||||
|
else
|
||||||
|
root(.)/preproc:symtable/preproc:sym[
|
||||||
|
@name=$name
|
||||||
|
]
|
||||||
|
" />
|
||||||
|
|
||||||
|
<xsl:variable name="type" select="$sym/@dtype" />
|
||||||
|
|
||||||
|
<!-- all calculations must make use of numeric types -->
|
||||||
|
<xsl:if test="
|
||||||
|
not(
|
||||||
|
( $type = 'integer' )
|
||||||
|
or ( $type = 'float' )
|
||||||
|
or ( $type = 'boolean' )
|
||||||
|
or ( ancestor::c:*[ @of and @index=$name ] )
|
||||||
|
)
|
||||||
|
">
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Non-numeric type in calculation'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:value-of select="$name" />
|
||||||
|
<xsl:text> is </xsl:text>
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="not( $type ) or $type = ''">
|
||||||
|
<xsl:text>undefined</xsl:text>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:text>of type '</xsl:text>
|
||||||
|
<xsl:value-of select="$type" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:variable name="is-set" select="$sym/@dim" />
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<!-- furthermore, if @of is provided, then it must be a set -->
|
||||||
|
<xsl:when test="@of">
|
||||||
|
<xsl:if test="$is-set = 0">
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'@of must reference a set'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content" select="$name" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- otherwise, an index is required to reference an item in the set unless
|
||||||
|
the value is being passed as an argument of the same set type, or is
|
||||||
|
the return value of a function (we assume it to be a return value if it
|
||||||
|
is in a tail position) -->
|
||||||
|
<!-- TODO: re-add argument param check for sets -->
|
||||||
|
<!-- TODO: c:values/c:value/@set check; should also only be allowed in tail -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="
|
||||||
|
( ( not( @index ) or ( @index = '' ) ) and not( ./c:index ) )
|
||||||
|
and not( ancestor::lv:match )
|
||||||
|
and (
|
||||||
|
$is-set != '0'
|
||||||
|
and not(
|
||||||
|
ancestor::c:arg
|
||||||
|
or (
|
||||||
|
ancestor::lv:function
|
||||||
|
and not( ./* )
|
||||||
|
)
|
||||||
|
or parent::c:length-of
|
||||||
|
or ancestor::c:value[ @set ]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
and not( parent::c:length-of )
|
||||||
|
">
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$sym/@dim = '?'">
|
||||||
|
<xsl:message>
|
||||||
|
<xsl:text>internal warning: unresolved param </xsl:text>
|
||||||
|
<xsl:text>dimension: `</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc">
|
||||||
|
<xsl:text>Unexpected vector/matrix reference</xsl:text>
|
||||||
|
</xsl:with-param>
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text> (did you forget @index?)</xsl:text>
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- matrices require two indexes, unless being used as an argument to a
|
||||||
|
function or as part of a dot product (it is also acceptable as the
|
||||||
|
return value of a function, which must be in a tail position) -->
|
||||||
|
<xsl:when test="
|
||||||
|
( number( $is-set ) gt 1 )
|
||||||
|
and not( ./c:index[ $is-set ] )
|
||||||
|
and not( ancestor::c:arg )
|
||||||
|
and not( ancestor::c:let )
|
||||||
|
and not( ancestor::c:product[ @dot ] )
|
||||||
|
and not( ancestor::c:cons )
|
||||||
|
and not( ancestor::c:cons )
|
||||||
|
and not(
|
||||||
|
ancestor::lv:function
|
||||||
|
and not( ./* )
|
||||||
|
)
|
||||||
|
">
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Invalid matrix specification'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text> requires </xsl:text>
|
||||||
|
<xsl:value-of select="$is-set" />
|
||||||
|
<xsl:text> indexes (use c:index) unless being</xsl:text>
|
||||||
|
<xsl:text> passed as a function argument</xsl:text>
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- ensure that we do not have too many indexes -->
|
||||||
|
<xsl:when test="( number( $is-set ) gt 0 ) and ./c:index[ number( $is-set ) + 1 ]">
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Invalid vector/matrix specification'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text> may only have </xsl:text>
|
||||||
|
<xsl:value-of select="$is-set" />
|
||||||
|
<xsl:text> index(s)</xsl:text>
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- if we have an index, but we're not dealing with a set, then that is
|
||||||
|
also an issue -->
|
||||||
|
<xsl:when test="@index and ( $is-set = '' )">
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Using index with non-set'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content" select="@name" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
|
||||||
|
<!-- index references should be defined -->
|
||||||
|
<xsl:if test="
|
||||||
|
@index and not( local-name() = 'sum' or local-name() = 'product' )
|
||||||
|
">
|
||||||
|
|
||||||
|
<xsl:variable name="index" select="@index" />
|
||||||
|
|
||||||
|
<!-- search for index definition -->
|
||||||
|
<!-- XXX: This also requires knowledge of match and require-param -->
|
||||||
|
<xsl:if test="
|
||||||
|
not(
|
||||||
|
ancestor::c:*[ @index = $index ]
|
||||||
|
or ( root(.)//lv:*[ @name = $index ]
|
||||||
|
and (
|
||||||
|
local-name() != 'match'
|
||||||
|
and local-name() != 'require-param'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
">
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Undefined index'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content" select="@index" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!-- recursively validate any nested calculations -->
|
||||||
|
<xsl:apply-templates mode="lvv:validate" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="c:apply/c:arg[@name]" mode="lvv:validate" priority="5">
|
||||||
|
<!-- merely validate its existence -->
|
||||||
|
<xsl:variable name="fname" select="parent::c:apply/@name" />
|
||||||
|
<xsl:if test="not(
|
||||||
|
concat( ':', $fname, ':', @name ) = root(.)/preproc:symtable/preproc:sym[
|
||||||
|
@type='lparam'
|
||||||
|
and @parent=$fname
|
||||||
|
]/@name
|
||||||
|
)">
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Unknown argument'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:text>Argument `</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>' is unknown for function `</xsl:text>
|
||||||
|
<xsl:value-of select="$fname" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!-- recursively validate any nested calculations -->
|
||||||
|
<xsl:apply-templates mode="lvv:validate" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="c:product[@dot]" mode="lvv:validate" priority="5">
|
||||||
|
<!-- TODO -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template mode="lvv:validate" priority="2" match="
|
||||||
|
lv:union/lv:typedef[
|
||||||
|
./lv:*[1]/@type != preceding-sibling::lv:typedef[1]/lv:*[1]/@type
|
||||||
|
]
|
||||||
|
">
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Union type mismatch'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:text>Expected type '</xsl:text>
|
||||||
|
<xsl:value-of select="preceding-sibling::lv:typedef[1]/lv:*[1]/@type" />
|
||||||
|
<xsl:text>' for </xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>, but found '</xsl:text>
|
||||||
|
<xsl:value-of select="./lv:*[1]/@type" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
|
||||||
|
<xsl:apply-templates mode="lvv:validate" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Checks for use of undefined classifications
|
||||||
|
-->
|
||||||
|
<xsl:template mode="lvv:validate" priority="2"
|
||||||
|
match="lv:rate/lv:class[
|
||||||
|
not( concat( ':class:', @ref ) = root(.)/preproc:symtable/preproc:sym[ @type='class' ]/@name )
|
||||||
|
]">
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Unknown classification'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:text>unknown classification '</xsl:text>
|
||||||
|
<xsl:value-of select="@ref" />
|
||||||
|
<xsl:text>' referenced by </xsl:text>
|
||||||
|
<xsl:value-of select="ancestor::lv:rate/@yields" />
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
All rate blocks must have non-empty yields
|
||||||
|
|
||||||
|
This is an awkward error, because it's not possible to identify the
|
||||||
|
rate block by name...there is none.
|
||||||
|
-->
|
||||||
|
<xsl:template mode="lvv:validate" priority="9"
|
||||||
|
match="lv:rate[ not( @yields ) or @yields = '' ]">
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Unidentifiable rate block'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:text>missing or empty @yields; see document dump</xsl:text>
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Throws an error if a generator is requested using unsupported data
|
||||||
|
|
||||||
|
Specifically, a generator is intended to generate a set from an expression
|
||||||
|
while looping over another set. If we're not looping, then we're not
|
||||||
|
generating a set. Furthermore, if a child expression was not provided, then
|
||||||
|
the set produced would be equivalent to @of, which is useless.
|
||||||
|
-->
|
||||||
|
<xsl:template mode="lvv:validate"
|
||||||
|
match="c:*[ @generates and not( @of and ./c:* ) ]" priority="9">
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Invalid generator'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:text>Cannot create generator '</xsl:text>
|
||||||
|
<xsl:value-of select="@generates" />
|
||||||
|
<xsl:text>'; generating expressions must contain both @of </xsl:text>
|
||||||
|
<xsl:text>and a sub-expression.</xsl:text>
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
|
||||||
|
<xsl:apply-templates mode="lvv:validate" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Since @generates creates a new variable that can be referenced, it needs
|
||||||
|
documentation! Refuse to compile if documentation is not provided. Yeah, we're
|
||||||
|
assholes.
|
||||||
|
-->
|
||||||
|
<xsl:template mode="lvv:validate"
|
||||||
|
match="c:*[ @generates and not( @desc ) ]" priority="9">
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'No generator description'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:text>@desc required when creating generator </xsl:text>
|
||||||
|
<xsl:value-of select="@generates" />
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
|
||||||
|
<xsl:apply-templates mode="lvv:validate" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="ext:*" mode="lvv:get-path">
|
||||||
|
<!-- omit from path output -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="*" mode="lvv:get-path">
|
||||||
|
<xsl:apply-templates select="parent::*" mode="lvv:get-path" />
|
||||||
|
<xsl:text>/</xsl:text>
|
||||||
|
<xsl:value-of select="name()" />
|
||||||
|
|
||||||
|
<!-- certain nodes may support path descriptions to aid in determining which
|
||||||
|
node is being referenced -->
|
||||||
|
<xsl:variable name="desc">
|
||||||
|
<xsl:apply-templates select="." mode="lvv:get-path-desc" />
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:if test="$desc != ''">
|
||||||
|
<xsl:text>[</xsl:text>
|
||||||
|
<xsl:value-of select="$desc" />
|
||||||
|
<xsl:text>]</xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lv:rate[ @yields ]" mode="lvv:get-path-desc">
|
||||||
|
<xsl:text>@yields=</xsl:text>
|
||||||
|
<xsl:value-of select="@yields" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="c:*[ @name ]" mode="lvv:get-path-desc" priority="5">
|
||||||
|
<xsl:text>@name=</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
</xsl:template>
|
||||||
|
<xsl:template match="c:*[ @label ]" mode="lvv:get-path-desc" priority="1">
|
||||||
|
<xsl:text>@label=</xsl:text>
|
||||||
|
<xsl:value-of select="@label" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="*" mode="lvv:get-path-desc">
|
||||||
|
<!-- no desc by default -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template name="lvv:error">
|
||||||
|
<xsl:param name="desc" />
|
||||||
|
<xsl:param name="refnode" />
|
||||||
|
<xsl:param name="content" />
|
||||||
|
|
||||||
|
<xsl:variable name="path">
|
||||||
|
<xsl:if test="$refnode">
|
||||||
|
<xsl:apply-templates select="$refnode" mode="lvv:get-path" />
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<lvv:error desc="{$desc}" path="{$path}">
|
||||||
|
<xsl:value-of select="$content" />
|
||||||
|
</lvv:error>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
|
@ -0,0 +1,193 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Domain validations
|
||||||
|
|
||||||
|
TODO: For core domains, validate src package path as well. (Right now,
|
||||||
|
param types are polluting, and so this is not a problem.)
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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:lvv="http://www.lovullo.com/rater/validate"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Assert that VALUE falls within the provided domain
|
||||||
|
|
||||||
|
SYM-DOMAIN should be a symbol resolving to the domain definition.
|
||||||
|
-->
|
||||||
|
<xsl:template name="lvv:domain-check">
|
||||||
|
<xsl:param name="value" />
|
||||||
|
<xsl:param name="sym-domain" />
|
||||||
|
|
||||||
|
<xsl:if test="not( $sym-domain )">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>internal error: no domain symbol provided; </xsl:text>
|
||||||
|
<xsl:text>caller: </xsl:text>
|
||||||
|
<xsl:copy-of select="." />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!-- generate node to simplify xpath expressions -->
|
||||||
|
<xsl:variable name="sym-validate">
|
||||||
|
<lvv:chk value="{$value}">
|
||||||
|
<xsl:copy-of select="$sym-domain" />
|
||||||
|
</lvv:chk>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:apply-templates mode="lvv:domain-check"
|
||||||
|
select="$sym-validate/lvv:chk">
|
||||||
|
|
||||||
|
<xsl:with-param name="self-pkg" select="
|
||||||
|
$sym-domain/ancestor::lv:package" />
|
||||||
|
</xsl:apply-templates>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Core type checks
|
||||||
|
|
||||||
|
- Integers must simply match when rounded;
|
||||||
|
- Floats must be any type of number; and
|
||||||
|
- Booleans may be only 1 or 0.
|
||||||
|
-->
|
||||||
|
<xsl:template match="
|
||||||
|
lvv:chk[
|
||||||
|
preproc:sym/@type = 'type'
|
||||||
|
and (
|
||||||
|
(
|
||||||
|
preproc:sym/@name = 'integer'
|
||||||
|
and not(
|
||||||
|
@value = floor( @value )
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or (
|
||||||
|
preproc:sym/@name = 'float'
|
||||||
|
and not(
|
||||||
|
@value = number( @value )
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or (
|
||||||
|
preproc:sym/@name = 'boolean'
|
||||||
|
and not(
|
||||||
|
number( @value ) = 0
|
||||||
|
or number( @value ) = 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]"
|
||||||
|
mode="lvv:domain-check" priority="5">
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:domain-fail" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Domain assertions on user-defined types
|
||||||
|
-->
|
||||||
|
<xsl:template match="
|
||||||
|
lvv:chk[
|
||||||
|
preproc:sym/@type='type'
|
||||||
|
and not (
|
||||||
|
preproc:sym/@name = 'integer'
|
||||||
|
or preproc:sym/@name = 'float'
|
||||||
|
or preproc:sym/@name = 'boolean'
|
||||||
|
)
|
||||||
|
]
|
||||||
|
"
|
||||||
|
mode="lvv:domain-check" priority="5">
|
||||||
|
|
||||||
|
<xsl:param name="self-pkg" />
|
||||||
|
|
||||||
|
<xsl:variable name="chkval" select="@value" />
|
||||||
|
|
||||||
|
<xsl:variable name="domain">
|
||||||
|
<xsl:call-template name="lvv:get-domain-by-sym">
|
||||||
|
<xsl:with-param name="sym" select="preproc:sym" />
|
||||||
|
<xsl:with-param name="self-pkg" select="$self-pkg" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$domain/lv:domain/lv:element[ @value = $chkval ]">
|
||||||
|
<lvv:ok type="domain-check" />
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:call-template name="lvv:domain-fail" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
No validation failure
|
||||||
|
-->
|
||||||
|
<xsl:template match="lvv:chk"
|
||||||
|
mode="lvv:domain-check" priority="2">
|
||||||
|
|
||||||
|
<lvv:ok type="domain-check" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
We passed ourselves something unexpected
|
||||||
|
-->
|
||||||
|
<xsl:template match="*"
|
||||||
|
mode="lvv:domain-chk" priority="1">
|
||||||
|
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>internal error: unexpected node for lvv:domain-chk: </xsl:text>
|
||||||
|
<xsl:copy-of select="." />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Mark validation as a failure, outputting the assertion
|
||||||
|
|
||||||
|
TODO: Once domains are used as the primary source instead of typedefs,
|
||||||
|
check to ensure that the symbol is an actual domain symbol.
|
||||||
|
-->
|
||||||
|
<xsl:template name="lvv:domain-fail">
|
||||||
|
<lvv:fail type="domain-check">
|
||||||
|
<xsl:copy-of select="." />
|
||||||
|
</lvv:fail>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template name="lvv:get-domain-by-sym">
|
||||||
|
<xsl:param name="sym" />
|
||||||
|
<xsl:param name="self-pkg" select="ancestor::lv:package" />
|
||||||
|
|
||||||
|
<!-- package containing symbol -->
|
||||||
|
<xsl:variable name="pkg" select="
|
||||||
|
if ( $sym/@src and not( $sym/@src='' ) ) then
|
||||||
|
document( concat( $sym/@src, '.xmlo' ), $__entry-root )
|
||||||
|
/lv:package
|
||||||
|
else
|
||||||
|
$self-pkg
|
||||||
|
" />
|
||||||
|
|
||||||
|
<!-- attempt to locate domain of the given name -->
|
||||||
|
<xsl:variable name="domain" select="
|
||||||
|
$pkg/lv:domain[ @name = $sym/@name ]" />
|
||||||
|
|
||||||
|
<xsl:if test="not( $domain )">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>error: no domain found for </xsl:text>
|
||||||
|
<xsl:value-of select="$sym/@src" />
|
||||||
|
<xsl:text>/</xsl:text>
|
||||||
|
<xsl:value-of select="$sym/@name" />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:copy-of select="$domain" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Parameter validations
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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:lvv="http://www.lovullo.com/rater/validate"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Param type must be known
|
||||||
|
|
||||||
|
TODO: Doesn't the symbol table lookup process handle this?
|
||||||
|
-->
|
||||||
|
<xsl:template match="
|
||||||
|
lv:param[
|
||||||
|
not(
|
||||||
|
@type=root(.)/preproc:symtable/preproc:sym[
|
||||||
|
@type
|
||||||
|
]/@name
|
||||||
|
)
|
||||||
|
]"
|
||||||
|
mode="lvv:validate" priority="5">
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'Unknown param type'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
<xsl:value-of select="@type" />
|
||||||
|
<xsl:text>' is undefined for param </xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Default must be within the domain of the param
|
||||||
|
|
||||||
|
Note that this template priority is less than the template that checks to
|
||||||
|
ensure that the param type exists in the first place.
|
||||||
|
-->
|
||||||
|
<xsl:template match="lv:param[ @default ]"
|
||||||
|
mode="lvv:validate" priority="4">
|
||||||
|
|
||||||
|
<xsl:variable name="type" select="@type" />
|
||||||
|
|
||||||
|
<!-- default must be within its domain -->
|
||||||
|
<xsl:variable name="result">
|
||||||
|
<xsl:call-template name="lvv:domain-check">
|
||||||
|
<xsl:with-param name="value" select="@default" />
|
||||||
|
<xsl:with-param name="sym-domain" select="
|
||||||
|
root(.)/preproc:symtable/preproc:sym[
|
||||||
|
@name = $type
|
||||||
|
]" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:if test="not( $result/lvv:ok )">
|
||||||
|
<xsl:variable name="fail" select="$result/lvv:fail/lvv:chk" />
|
||||||
|
|
||||||
|
<!-- if we didn't succeed, but we didn't fail, then we did something we
|
||||||
|
weren't supposed to -->
|
||||||
|
<xsl:if test="not( $fail )">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>internal error: in limbo processing param `</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>' @default</xsl:text>
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:call-template name="lvv:error">
|
||||||
|
<xsl:with-param name="desc" select="'param @default domain violation'" />
|
||||||
|
<xsl:with-param name="refnode" select="." />
|
||||||
|
<xsl:with-param name="content">
|
||||||
|
<xsl:text>param `</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>' @default of `</xsl:text>
|
||||||
|
<xsl:value-of select="$fail/@value" />
|
||||||
|
<xsl:text>' is not within its domain of </xsl:text>
|
||||||
|
<xsl:value-of select="$fail/preproc:sym/@src" />
|
||||||
|
<xsl:text>/</xsl:text>
|
||||||
|
<xsl:value-of select="$fail/preproc:sym/@name" />
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Fallback for no validation issues
|
||||||
|
-->
|
||||||
|
<xsl:template match="lv:param" mode="lvv:validate" priority="2">
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,543 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Compiles rater XML into JavaScript
|
||||||
|
|
||||||
|
This stylesheet should be included by whatever is doing the processing and is
|
||||||
|
responsible for outputting the generated code in whatever manner is
|
||||||
|
appropriate (inline JS, a file, etc).
|
||||||
|
-->
|
||||||
|
|
||||||
|
<stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns:lv="http://www.lovullo.com/rater"
|
||||||
|
xmlns:w="http://www.lovullo.com/rater/worksheet"
|
||||||
|
xmlns:_w="http://www.lovullo.com/rater/worksheet/_priv"
|
||||||
|
xmlns:c="http://www.lovullo.com/calc"
|
||||||
|
xmlns:lvmc="http://www.lovullo.com/rater/map/compiler"
|
||||||
|
xmlns:wc="http://www.lovullo.com/rater/worksheet/compiler"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc"
|
||||||
|
xmlns:util="http://www.lovullo.com/util">
|
||||||
|
|
||||||
|
<variable name="wc:lc" select="'abcdefghijklmnopqrstuvwxyz'" />
|
||||||
|
<variable name="wc:uc" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
|
||||||
|
|
||||||
|
<!-- lexemes to be converted to a human-readable format -->
|
||||||
|
<!-- TODO: move this into an external file so it may be easily configurable -->
|
||||||
|
<variable name="wc:hlex">
|
||||||
|
<!-- prefix to suffix -->
|
||||||
|
<wc:lex prefix="prem" to="Premium" />
|
||||||
|
<wc:lex prefix="rate" to="Rate" />
|
||||||
|
<wc:lex prefix="credit" to="Credit" />
|
||||||
|
<wc:lex prefix="surcharge" to="Surcharge" />
|
||||||
|
|
||||||
|
<wc:lex str="gl" to="GL" />
|
||||||
|
<wc:lex str="prop" to="Property" />
|
||||||
|
<wc:lex str="equip" to="Equipment" />
|
||||||
|
<wc:lex str="adjust" to="Adjustment" />
|
||||||
|
<wc:lex str="adj" to="Adjustment" />
|
||||||
|
<wc:lex str="ded" to="Deductible" />
|
||||||
|
<wc:lex str="dw" to="Dwelling" />
|
||||||
|
<wc:lex str="fam" to="Family" />
|
||||||
|
<wc:lex str="tiv" to="TIV" />
|
||||||
|
|
||||||
|
<!-- *Each is used for generators -->
|
||||||
|
<wc:lex str="each" to="" />
|
||||||
|
</variable>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- we expect that the worksheet will have been preprocessed into the rater
|
||||||
|
document -->
|
||||||
|
<template match="w:worksheet" mode="w:compile" priority="10">
|
||||||
|
<param name="corder" />
|
||||||
|
|
||||||
|
<variable name="displays" as="element( w:display )*"
|
||||||
|
select="w:display" />
|
||||||
|
|
||||||
|
<variable name="package" as="element( lv:package )"
|
||||||
|
select="_w:load-package( @package, . )" />
|
||||||
|
|
||||||
|
<variable name="syms" as="element( preproc:sym )*"
|
||||||
|
select="_w:filter-needed-symbols(
|
||||||
|
_w:load-symbols( $package ),
|
||||||
|
$displays )" />
|
||||||
|
|
||||||
|
<lv:package name="{@name}"
|
||||||
|
lvmc:type="worksheet">
|
||||||
|
<!-- we provide one special symbol -->
|
||||||
|
<preproc:symtable>
|
||||||
|
<preproc:sym name="___worksheet"
|
||||||
|
type="worksheet" />
|
||||||
|
</preproc:symtable>
|
||||||
|
|
||||||
|
<!-- TODO -->
|
||||||
|
<preproc:sym-deps>
|
||||||
|
<preproc:sym-dep name="___worksheet" />
|
||||||
|
</preproc:sym-deps>
|
||||||
|
|
||||||
|
<copy-of select="node()" />
|
||||||
|
|
||||||
|
<preproc:fragments>
|
||||||
|
<preproc:fragment id="___worksheet">
|
||||||
|
<text>rater.worksheet = </text>
|
||||||
|
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="obj">
|
||||||
|
<for-each select="$displays">
|
||||||
|
<sequence select="_w:compile-display( ., $syms )" />
|
||||||
|
</for-each>
|
||||||
|
|
||||||
|
<variable name="yield" as="element( lv:rate )?"
|
||||||
|
select="$package/lv:rate[ @yields = '___yield' ]" />
|
||||||
|
|
||||||
|
<!-- always include yield -->
|
||||||
|
<if test="$yield">
|
||||||
|
<util:value>
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="id" select="'yield'" />
|
||||||
|
<with-param name="array">
|
||||||
|
<util:value>
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="value" select="'Yields'" />
|
||||||
|
</call-template>
|
||||||
|
</util:value>
|
||||||
|
|
||||||
|
<util:value>
|
||||||
|
<apply-templates mode="wc:compile"
|
||||||
|
select="$yield/c:*" />
|
||||||
|
</util:value>
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</util:value>
|
||||||
|
</if>
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
|
||||||
|
<text>;</text>
|
||||||
|
</preproc:fragment>
|
||||||
|
</preproc:fragments>
|
||||||
|
</lv:package>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<function name="_w:compile-display" as="element( util:value )">
|
||||||
|
<param name="display" as="element( w:display )" />
|
||||||
|
<param name="syms" as="element( preproc:sym )*" />
|
||||||
|
|
||||||
|
<variable name="name" as="xs:string"
|
||||||
|
select="$display/@name" />
|
||||||
|
|
||||||
|
<variable name="sym" as="element( preproc:sym )?"
|
||||||
|
select="$syms[ @name = $name ]" />
|
||||||
|
|
||||||
|
<!-- terminate on unknown references -->
|
||||||
|
<if test="empty( $sym )">
|
||||||
|
<message terminate="yes"
|
||||||
|
select="'Reference to unknown symbol:', $name" />
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<util:value>
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="id" select="$name" />
|
||||||
|
|
||||||
|
<with-param name="array">
|
||||||
|
<util:value>
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="value">
|
||||||
|
<call-template name="wc:var-to-hstr">
|
||||||
|
<with-param name="var" select="$name" />
|
||||||
|
</call-template>
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</util:value>
|
||||||
|
|
||||||
|
<util:value>
|
||||||
|
<choose>
|
||||||
|
<when test="$display/@collapse = 'true'">
|
||||||
|
<sequence select="''" />
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<otherwise>
|
||||||
|
<variable name="rate-block" as="element( lv:rate )"
|
||||||
|
select="_w:get-src-node( $sym )" />
|
||||||
|
|
||||||
|
<apply-templates mode="wc:compile"
|
||||||
|
select="$rate-block/c:*">
|
||||||
|
<with-param name="display" select="$display"
|
||||||
|
tunnel="yes" />
|
||||||
|
</apply-templates>
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</util:value>
|
||||||
|
|
||||||
|
<util:value>
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="value">
|
||||||
|
<value-of select="$display/@always" />
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</util:value>
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</util:value>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
<function name="_w:load-package" as="element( lv:package )">
|
||||||
|
<param name="path" as="xs:string" />
|
||||||
|
<param name="context" as="node()" />
|
||||||
|
|
||||||
|
<!-- TODO: function to provide xmlo extension -->
|
||||||
|
<variable name="package-uri" as="xs:anyURI"
|
||||||
|
select="resolve-uri(
|
||||||
|
concat( $path, '.xmlo' ),
|
||||||
|
base-uri( $context ) )" />
|
||||||
|
|
||||||
|
<if test="not( doc-available( $package-uri ) )">
|
||||||
|
<message terminate="yes"
|
||||||
|
select="concat( 'fatal: package ',
|
||||||
|
$path,
|
||||||
|
' not found' )" />
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<sequence select="doc( $package-uri )/lv:package" />
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- TODO: some of this logic can be factored out into a common
|
||||||
|
library -->
|
||||||
|
<function name="_w:load-symbols" as="element( preproc:sym )+">
|
||||||
|
<param name="package" as="element( lv:package )" />
|
||||||
|
|
||||||
|
<sequence select="$package/preproc:symtable/preproc:sym" />
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<function name="_w:filter-needed-symbols" as="element( preproc:sym )*">
|
||||||
|
<param name="syms" as="element( preproc:sym )*" />
|
||||||
|
<param name="displays" as="element( w:display )*" />
|
||||||
|
|
||||||
|
<sequence select="$syms[ @name = $displays/@name ]" />
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
<function name="_w:get-src-package" as="element( lv:package )">
|
||||||
|
<param name="sym" as="element( preproc:sym )" />
|
||||||
|
|
||||||
|
<variable name="sym-path" as="xs:string?"
|
||||||
|
select="$sym/@src" />
|
||||||
|
|
||||||
|
<variable name="context-uri" as="xs:anyURI"
|
||||||
|
select="base-uri( $sym )" />
|
||||||
|
|
||||||
|
<!-- TODO: function to provide xmlo extension -->
|
||||||
|
<variable name="src-uri" as="xs:anyURI"
|
||||||
|
select="if ( $sym-path and not( $sym-path = '' ) ) then
|
||||||
|
resolve-uri(
|
||||||
|
concat( $sym-path, '.xmlo' ),
|
||||||
|
$context-uri )
|
||||||
|
else
|
||||||
|
$context-uri" />
|
||||||
|
|
||||||
|
<if test="not( doc-available( $src-uri ) )">
|
||||||
|
<message terminate="yes"
|
||||||
|
select="concat( 'fatal: package ',
|
||||||
|
$sym-path,
|
||||||
|
' not found; required by symbol ',
|
||||||
|
$sym/@name )" />
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<sequence select="doc( $src-uri )/lv:package" />
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<function name="_w:get-src-node" as="element( lv:rate )">
|
||||||
|
<param name="sym" as="element( preproc:sym )" />
|
||||||
|
|
||||||
|
<variable name="package" as="element( lv:package )"
|
||||||
|
select="_w:get-src-package( $sym )" />
|
||||||
|
|
||||||
|
<variable name="rate-name" as="xs:string"
|
||||||
|
select="if ( $sym/@parent ) then
|
||||||
|
$sym/@parent
|
||||||
|
else
|
||||||
|
$sym/@name" />
|
||||||
|
|
||||||
|
<sequence select="$package/lv:rate[ @yields = $rate-name ]" />
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="c:sum[@of='_CMATCH_']" mode="wc:compile" priority="9">
|
||||||
|
<apply-templates select="./c:*" mode="wc:compile" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template match="c:sum[@of='_CMATCH_']/c:product[c:value-of[@name='_CMATCH_']]"
|
||||||
|
mode="wc:compile" priority="9">
|
||||||
|
|
||||||
|
<!-- ignore the product and continue with the 2nd node -->
|
||||||
|
<apply-templates select="./c:*[2]" mode="wc:compile" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="c:apply" priority="7" mode="wc:compile">
|
||||||
|
<param name="display" as="element( w:display )"
|
||||||
|
tunnel="yes" />
|
||||||
|
|
||||||
|
<choose>
|
||||||
|
<!-- do not expand -->
|
||||||
|
<when test="
|
||||||
|
not(
|
||||||
|
@name = $display/ancestor::w:worksheet
|
||||||
|
/w:expand-function/@name
|
||||||
|
or (
|
||||||
|
@name = $display/w:expand-function/@name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
">
|
||||||
|
|
||||||
|
<call-template name="wc:compile-calc">
|
||||||
|
<with-param name="nochildren" select="true()" />
|
||||||
|
<with-param name="runtime" select="true()" />
|
||||||
|
</call-template>
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<!-- expand -->
|
||||||
|
<otherwise>
|
||||||
|
<call-template name="wc:compile-calc" />
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template match="c:value-of[c:index]" mode="wc:compile" priority="5">
|
||||||
|
<call-template name="wc:compile-calc">
|
||||||
|
<with-param name="nochildren" select="true()" />
|
||||||
|
<with-param name="runtime" select="true()" />
|
||||||
|
</call-template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- we need to take into account constants that are compiled in place (so we
|
||||||
|
cannot determine their value by name at runtime) -->
|
||||||
|
<template match="c:value-of[ @name=//lv:const[ not( * ) ]/@name ]" mode="wc:compile" priority="5">
|
||||||
|
<variable name="name" select="@name" />
|
||||||
|
|
||||||
|
<call-template name="wc:compile-calc">
|
||||||
|
<with-param name="include-value">
|
||||||
|
<value-of select="//lv:const[ @name=$name ]/@value" />
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Will output JSON of the following structure:
|
||||||
|
|
||||||
|
[ "type", {desc}, [subnodes] ]
|
||||||
|
|
||||||
|
The subnodes are recursively generated in the same format as above.
|
||||||
|
-->
|
||||||
|
<template name="wc:compile-calc" match="c:*" mode="wc:compile" priority="4">
|
||||||
|
<param name="nochildren" as="xs:boolean" select="false()" />
|
||||||
|
<param name="runtime" select="false()" />
|
||||||
|
<param name="include-value" />
|
||||||
|
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="array">
|
||||||
|
<!-- output node type -->
|
||||||
|
<util:value>
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="value" select="local-name()" />
|
||||||
|
</call-template>
|
||||||
|
</util:value>
|
||||||
|
|
||||||
|
<!-- description -->
|
||||||
|
<util:value>
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="obj">
|
||||||
|
|
||||||
|
<!-- build each attribute into the description -->
|
||||||
|
<for-each select="@*">
|
||||||
|
<util:value>
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="id" select="local-name()" />
|
||||||
|
<with-param name="value" select="." />
|
||||||
|
</call-template>
|
||||||
|
</util:value>
|
||||||
|
</for-each>
|
||||||
|
|
||||||
|
<!-- certain values should be calculated at runtime -->
|
||||||
|
<if test="$runtime = true()">
|
||||||
|
<util:value>
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="id" select="'runtime'" />
|
||||||
|
<with-param name="value" select="'true'" />
|
||||||
|
</call-template>
|
||||||
|
</util:value>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</util:value>
|
||||||
|
|
||||||
|
<!-- children -->
|
||||||
|
<util:value>
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="array">
|
||||||
|
|
||||||
|
<if test="not( $nochildren = true() )">
|
||||||
|
<!-- sub-nodes (recursive) -->
|
||||||
|
<for-each select="c:*">
|
||||||
|
<util:value>
|
||||||
|
<apply-templates select="." mode="wc:compile" />
|
||||||
|
</util:value>
|
||||||
|
</for-each>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</util:value>
|
||||||
|
|
||||||
|
<!-- optional value (if we can determine compile-time) -->
|
||||||
|
<if test="$include-value">
|
||||||
|
<util:value>
|
||||||
|
<call-template name="util:json">
|
||||||
|
<with-param name="value" select="$include-value" />
|
||||||
|
</call-template>
|
||||||
|
</util:value>
|
||||||
|
</if>
|
||||||
|
</with-param>
|
||||||
|
</call-template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template name="wc:var-to-hstr">
|
||||||
|
<param name="var" />
|
||||||
|
|
||||||
|
<!-- string separators (TODO: make configurable) -->
|
||||||
|
<variable name="pre" select="substring-before( $var, '4' )" />
|
||||||
|
|
||||||
|
<choose>
|
||||||
|
<when test="not( $pre = '' )">
|
||||||
|
<!-- before separator -->
|
||||||
|
<call-template name="wc:var-to-hstr">
|
||||||
|
<with-param name="var" select="$pre" />
|
||||||
|
</call-template>
|
||||||
|
|
||||||
|
<text> for </text>
|
||||||
|
|
||||||
|
<!-- after -->
|
||||||
|
<call-template name="wc:var-to-hstr">
|
||||||
|
<with-param name="var" select="substring-after( $var, '4' )" />
|
||||||
|
</call-template>
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<!-- no separator; continue -->
|
||||||
|
<otherwise>
|
||||||
|
<call-template name="wc:_var-to-hstr">
|
||||||
|
<with-param name="var" select="$var" />
|
||||||
|
</call-template>
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- var to human-readable string -->
|
||||||
|
<template name="wc:_var-to-hstr">
|
||||||
|
<param name="var" />
|
||||||
|
|
||||||
|
<!-- start by grabbing the prefix -->
|
||||||
|
<variable name="prefix">
|
||||||
|
<call-template name="wc:str-until-uc">
|
||||||
|
<with-param name="str" select="$var" />
|
||||||
|
</call-template>
|
||||||
|
</variable>
|
||||||
|
|
||||||
|
<!-- and grab the rest of the string after the prefix -->
|
||||||
|
<variable name="remain" select="substring-after( $var, $prefix )" />
|
||||||
|
|
||||||
|
<!-- convert the first char to lowercase so that we do not screw up the uc
|
||||||
|
prefix substr on the next call -->
|
||||||
|
<variable name="remain-recurse" select="
|
||||||
|
concat(
|
||||||
|
translate( substring( $remain, 1, 1 ), $wc:uc, $wc:lc ),
|
||||||
|
substring( $remain, 2 )
|
||||||
|
)
|
||||||
|
" />
|
||||||
|
|
||||||
|
<variable name="prelex" select="$wc:hlex//wc:lex[ @prefix=$prefix ]" />
|
||||||
|
|
||||||
|
<choose>
|
||||||
|
<when test="$prelex">
|
||||||
|
<if test="not( $remain-recurse = '' )">
|
||||||
|
<call-template name="wc:var-to-hstr">
|
||||||
|
<with-param name="var" select="$remain-recurse" />
|
||||||
|
</call-template>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<text> </text>
|
||||||
|
<value-of select="$prelex/@to" />
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<!-- no knowledge of prefix; output it and then recurse -->
|
||||||
|
<otherwise>
|
||||||
|
<variable name="strlex" select="$wc:hlex//wc:lex[ @str=$prefix ]" />
|
||||||
|
|
||||||
|
<choose>
|
||||||
|
<!-- if we recognize this text as a lexeme to be replaced, then do so
|
||||||
|
-->
|
||||||
|
<when test="$strlex">
|
||||||
|
<value-of select="$strlex/@to" />
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<!-- just output the text as-is -->
|
||||||
|
<otherwise>
|
||||||
|
<!-- ucfirst -->
|
||||||
|
<value-of select="
|
||||||
|
concat(
|
||||||
|
translate( substring( $prefix, 1, 1 ), $wc:lc, $wc:uc ),
|
||||||
|
substring( $prefix, 2 )
|
||||||
|
)
|
||||||
|
" />
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
|
||||||
|
<if test="not( $remain-recurse = '' )">
|
||||||
|
<text> </text>
|
||||||
|
|
||||||
|
<call-template name="wc:var-to-hstr">
|
||||||
|
<with-param name="var" select="$remain-recurse" />
|
||||||
|
</call-template>
|
||||||
|
</if>
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- get string prefix until reaching a upper-case char -->
|
||||||
|
<template name="wc:str-until-uc">
|
||||||
|
<param name="str" />
|
||||||
|
|
||||||
|
<variable name="char" select="substring( $str, 1, 1 )" />
|
||||||
|
|
||||||
|
<choose>
|
||||||
|
<when test="$str = ''">
|
||||||
|
<!-- done; nothing else to do -->
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<!-- did we find an upper-case char? -->
|
||||||
|
<when test="translate( $char, $wc:uc, '' ) = ''">
|
||||||
|
<!-- we're done; do nothing and do not output -->
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<otherwise>
|
||||||
|
<!-- output the char and recurse -->
|
||||||
|
<value-of select="$char" />
|
||||||
|
|
||||||
|
<call-template name="wc:str-until-uc">
|
||||||
|
<with-param name="str" select="substring( $str, 2 )" />
|
||||||
|
</call-template>
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</stylesheet>
|
|
@ -0,0 +1,4 @@
|
||||||
|
*.aux
|
||||||
|
*.pdf
|
||||||
|
*.log
|
||||||
|
*.toc
|
|
@ -0,0 +1,372 @@
|
||||||
|
\chapter{Classification System}
|
||||||
|
The classification system is one of the most powerful features of \lang,
|
||||||
|
allowing precise control over the classification and conditional processing of
|
||||||
|
large sets of data, whether it be external input or values generated from within
|
||||||
|
\lang\ itself. Virtually every conditional calculation is best represented
|
||||||
|
through use of the classification system.
|
||||||
|
|
||||||
|
|
||||||
|
\section{Classification Matcher}
|
||||||
|
Data classification is performed by the classification matcher (sometimes
|
||||||
|
referred to simply as the ``matcher''). Put simply, it is a function (defined by
|
||||||
|
\aref{cmatch}) that, given a vector of inputs, produces a boolean vector (which
|
||||||
|
may itself contain boolean vectors) determining if the given input conforms to a
|
||||||
|
set of stated rules. A set of rules operating on a set input vectors is
|
||||||
|
collectively known as a \term{classification}. The system that performs matching
|
||||||
|
based on classifications is referred to as a \term{classifier}.
|
||||||
|
|
||||||
|
A single classification can be separated into a set of rules, often referred to
|
||||||
|
as \term{matches} within the context of \lang. A single rule attempts to match
|
||||||
|
on a vector of inputs.\footnote{Scalar inputs are a special condition defined in
|
||||||
|
\sref{cmatch-scalar}.} A simple example of such a match is shown in
|
||||||
|
\fref{cmatch-ex-single}.
|
||||||
|
|
||||||
|
\begin{figure}[h]
|
||||||
|
$$
|
||||||
|
I = \left[
|
||||||
|
\begin{array}{c}
|
||||||
|
1 \\ 3 \\ 4 \\ 1
|
||||||
|
\end{array}
|
||||||
|
\right]
|
||||||
|
\qquad
|
||||||
|
M = \left[
|
||||||
|
\begin{array}{c}
|
||||||
|
1 \\ 4
|
||||||
|
\end{array}
|
||||||
|
\right]
|
||||||
|
\quad
|
||||||
|
\to
|
||||||
|
\quad
|
||||||
|
R = \left[
|
||||||
|
\begin{array}{c}
|
||||||
|
\top \\ \bot \\ \top \\ \top
|
||||||
|
\end{array}
|
||||||
|
\right].
|
||||||
|
$$
|
||||||
|
|
||||||
|
\caption{A simple classification match $M$ on input $I$ and its result vector
|
||||||
|
$R$.}
|
||||||
|
\label{f:cmatch-ex-single}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
In \fref{cmatch-ex-single}, the input vector $I$ is \term{matched} against the
|
||||||
|
rule $M$. The output is a boolean result vector $R$ which can be summarized with
|
||||||
|
the following rule:
|
||||||
|
|
||||||
|
$$
|
||||||
|
R_n = \exists m\in M(m = I_n).
|
||||||
|
$$
|
||||||
|
\noindent
|
||||||
|
In other words, $R_n$ is $\top$ if $I_n\in M$ and is $\bot$ if $I_n\notin M$.
|
||||||
|
Under this definition, $M$ can be considered to be the \term{domain} under which
|
||||||
|
a given input $I_n$ is considered to be valid (a \term{match}).
|
||||||
|
|
||||||
|
We say that a classification rule \term{matches} if \emph{any} input matches.
|
||||||
|
That is:
|
||||||
|
|
||||||
|
$$
|
||||||
|
\left[\textrm{The rule $M$ matches input $I$}\right]
|
||||||
|
\iff
|
||||||
|
\top\in R
|
||||||
|
$$
|
||||||
|
\noindent
|
||||||
|
Another way to think of this concept is the reduction of the result vector $R$
|
||||||
|
using a logical OR. Alternatively, one could assert that:
|
||||||
|
|
||||||
|
$$
|
||||||
|
\left[\textrm{The rule $M$ matches input $I$}\right]
|
||||||
|
\iff
|
||||||
|
\sum\limits_n R_n \geq 1, \qquad R \in \set{0,1},
|
||||||
|
$$
|
||||||
|
\noindent
|
||||||
|
if an implementation were willing to use the sets \boolset and \set{1,0}
|
||||||
|
interchangeably.\footnote{See \sref{cmatch-int}.}
|
||||||
|
|
||||||
|
The following sections, however, serve to demonstrate that such a simple view of
|
||||||
|
the classification system, while useful for an introductory demonstration, is
|
||||||
|
not sufficient when considering the level of flexibility that is necessary to
|
||||||
|
handle more complicated data (in particular, when $I$ is a
|
||||||
|
matrix).\footnote{See $\Omega$-reductions, introduced in
|
||||||
|
\asref{cmatch}{omega-reduce}.}
|
||||||
|
|
||||||
|
%TODO: More example sections
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{Classification Match (cmatch) Algorithm}
|
||||||
|
\label{a:cmatch}
|
||||||
|
|
||||||
|
The classification match (``cmatch'') algorithm is used to determine if a given
|
||||||
|
set of data matches a given set of classification criteria.
|
||||||
|
|
||||||
|
Let $I$ be the vector of input values.\footnote{$I$ may be a matrix (a vector
|
||||||
|
of vectors).} Let $M$ be the vector of predicates to match against $I$ such
|
||||||
|
that a match will be considered successful if \emph{any} predicate is true.
|
||||||
|
Since $I$ shall always be a vector of values---even if the vector contains only
|
||||||
|
one element (see algorithm below for comments on scalar values)---$M$ should be
|
||||||
|
a vector of one element if the desire is to match against a scalar value (rather
|
||||||
|
than a vector of values). Let $c$ (clear) be a boolean value\footnote{$1$ or $0$
|
||||||
|
when used within an integer context within the algorithm.} representing whether
|
||||||
|
the results of this operation should be logically AND'd together with the
|
||||||
|
prior cmatch result ($R'$ in the algorithm below); otherwise, the results will
|
||||||
|
be OR'd (see step \ref{a:cmatch-c} below).
|
||||||
|
|
||||||
|
Let $A\!\left(M,I,c,R'\right)$ (the ``algorithm'') be defined as:
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\item
|
||||||
|
Let $R$ be the result vector.
|
||||||
|
|
||||||
|
\item\label{a:cmatch-scalar}
|
||||||
|
If the given input vector $I$ is a scalar, it should be converted to a vector
|
||||||
|
of length 1 with the value of the single element being the original scalar
|
||||||
|
value of $I$---that is, let $s$ be the original scalar value of $I$; then: $I
|
||||||
|
= \left[ s \right]$. If $s$ is undefined, then an empty result vector should
|
||||||
|
be returned.
|
||||||
|
|
||||||
|
\item\label{a:cmatch:input-vectorize}
|
||||||
|
Step \ref{a:cmatch-scalar} should also be done to the match vector $M$,
|
||||||
|
yielding $M = \left[ s \right]$ where $s$ is the original scalar $M$. If $s$
|
||||||
|
is undefined, then it should be treated as if it were the integer
|
||||||
|
$0$.\footnote{Consistent with the behavior of the remainder of the DSL.}
|
||||||
|
|
||||||
|
\item
|
||||||
|
Step \ref{a:cmatch-scalar} should also be done to the prior result vector
|
||||||
|
$R'$, yielding $R = \left[ s \right]$ where $s$ is the original scalar $R'$.
|
||||||
|
This situation may result from recursing at step \ref{a:cmatch-mrecurse} when
|
||||||
|
$R'_k$ is a scalar. If $s$ is undefined, then $R'$ should be initialized to an
|
||||||
|
empty vector, implying a fresh match (no prior results).
|
||||||
|
\goodbreak
|
||||||
|
|
||||||
|
\item\label{a:cmatch-iter}
|
||||||
|
The length of the result vector $R$~($\#R$) shall be the larger of the length
|
||||||
|
of the input vector $I$~($\#I$) or the prior result vector $R'$~($\#R'$).
|
||||||
|
For each $I_k \in I$:
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\item\label{a:cmatch-mrecurse}
|
||||||
|
If $I_k$ is a vector, recurse, beginning at step 1. Let $r =
|
||||||
|
A(M_k,I_k,c,R'_k)$.
|
||||||
|
|
||||||
|
\begin{align*}
|
||||||
|
u &= \left\{
|
||||||
|
\begin{array}{ll}
|
||||||
|
\bot & \textrm{if }\#R' > 0, \\
|
||||||
|
c & \textrm{otherwise.}
|
||||||
|
\end{array}
|
||||||
|
\right. \\
|
||||||
|
%
|
||||||
|
R_k &= \left\{
|
||||||
|
\begin{array}{ll}
|
||||||
|
r & \textrm{if $R'_k$ is a vector or undefined}, \\
|
||||||
|
\Omega(r,u) & \textrm{otherwise}.\footnotemark
|
||||||
|
\end{array}
|
||||||
|
\right.
|
||||||
|
\end{align*}
|
||||||
|
|
||||||
|
\footnotetext{\label{a:cmatch-order} If $R'_k$ is a scalar, we must ensure
|
||||||
|
consistency with step \ref{a:cmatch-c} to ensure that the algorithm is not
|
||||||
|
dependent on input or execution order. Note the use of $u$ in place of
|
||||||
|
$c$---this ensures that, if there are any $R'$, we are consistent with the
|
||||||
|
effects of step \ref{a:cmatch:fill} (but in reverse).}
|
||||||
|
|
||||||
|
Continue with the next $I$ at step \ref{a:cmatch-iter}.
|
||||||
|
|
||||||
|
\item
|
||||||
|
\label{a:cmatch:omega-reduce}
|
||||||
|
Otherwise, $I_k$ is a scalar. Let $t$ be a temporary (intermediate) scalar
|
||||||
|
such that $t = \exists m \in M m(I_k)$.
|
||||||
|
|
||||||
|
\item\label{a:cmatch-c}
|
||||||
|
Let $v = \Omega\left(R'_k,c\right)$ and let
|
||||||
|
$$
|
||||||
|
R_k = \left\{
|
||||||
|
\begin{array}{ll}
|
||||||
|
v \wedge t & c = \top, \\
|
||||||
|
v \vee t & c = \bot.
|
||||||
|
\end{array}
|
||||||
|
\right.,
|
||||||
|
$$
|
||||||
|
|
||||||
|
where\footnote{$\Omega$ is simply the recursive reduction of a vector using
|
||||||
|
a logical OR. This function exists to resolve the situation where $R'_k$ is
|
||||||
|
a vector of values when $I_k$ is a scalar, which will occur when $M_k$ is
|
||||||
|
scalar for any $k$ during one application of the cmatch algorithm and $M_k$
|
||||||
|
is a vector for another iteration, where $R'$ is the previous match using
|
||||||
|
scalars. Note also that $X$, according to the recursion rule, may only be
|
||||||
|
undefined on the first iteration (in effect initializing the value).}
|
||||||
|
|
||||||
|
$$
|
||||||
|
\Omega\left(X,u\right) = \left\{
|
||||||
|
\begin{array}{ll}
|
||||||
|
u & \textrm{if X is undefined,} \\
|
||||||
|
X & \textrm{if X is a scalar,} \\
|
||||||
|
\exists x\in X \Omega(x,u) & \textrm{otherwise.}
|
||||||
|
\end{array}
|
||||||
|
\right. \>
|
||||||
|
\mbox{
|
||||||
|
$X \in \left\{\textrm{undefined},\top,\bot\right\}$
|
||||||
|
or a vector.
|
||||||
|
}
|
||||||
|
$$
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\item\label{a:cmatch:fill}
|
||||||
|
Let $v = \Omega\left(R'_k,c\right) \wedge \neg c$. If $\#R' > \#I$,
|
||||||
|
$$
|
||||||
|
R_k = \left\{
|
||||||
|
\begin{array}{ll}
|
||||||
|
v & \exists n\in I(n\textrm{ is a scalar}), \\
|
||||||
|
\left[v\right] & \textrm{otherwise.}\footnotemark
|
||||||
|
\end{array}
|
||||||
|
\right.
|
||||||
|
k \in \left\{j : \#I \leq j < \#R' \right\}.
|
||||||
|
$$
|
||||||
|
|
||||||
|
\footnotetext{Note that step \ref{a:cmatch:fill} will produce results
|
||||||
|
inconsistent with the recursive step \ref{a:cmatch-mrecurse} if there exists
|
||||||
|
an $I_n$ that is a matrix; this algorithm is not designed to handle such
|
||||||
|
scenarios.}
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Given a set of classification criteria $C$ such that $C_k = M$ for some integer
|
||||||
|
$k$ and some application of $A$, and a vectorized clear flag $c$ such that $c_k$
|
||||||
|
is associated with $C_k$, the final result $F(\#C-1)$ shall be defined as
|
||||||
|
|
||||||
|
$$
|
||||||
|
F(k) = \left\{
|
||||||
|
\begin{array}{ll}
|
||||||
|
A\left(C_k,I_k,c_k\right) & \textrm{k = 0,} \\
|
||||||
|
A\bigl(C_k,I_k,c_k,F\!\left(k-1\right)\bigr) & \textrm{otherwise.}
|
||||||
|
\end{array}
|
||||||
|
\right.
|
||||||
|
$$
|
||||||
|
|
||||||
|
The order of recursion on $F$ need not be right-to-left; $A$ is defined such
|
||||||
|
that it will produce the same result when applied in any order. This is
|
||||||
|
necessary since the input may be provided in any order.\footnote{Ibid,
|
||||||
|
\ref{a:cmatch-order}.}
|
||||||
|
|
||||||
|
\subsubsection{Boolean Classification Match}
|
||||||
|
\label{s:cmatch-boolean}
|
||||||
|
A scalar boolean classification match $b$ may be obtained simply as $b =
|
||||||
|
\Omega\left(F,\bot\right)$, where $F$ and $\Omega$ are defined in the algorithm
|
||||||
|
above. Consequently, note that an empty result set $F$ will be treated as
|
||||||
|
$\bot$, since index $0$ will be undefined.
|
||||||
|
|
||||||
|
\subsubsection{Match Vector}
|
||||||
|
$M$ is defined to be a vector of predicates which serve to {\sl match} against a
|
||||||
|
vector of input values. Most frequently, predicates will likely be against scalar
|
||||||
|
values. In such a case, an implementation may choose to forego function
|
||||||
|
application for performance reasons and instead match directly against the
|
||||||
|
scalar value. However, this document will consider scalar matches in the context
|
||||||
|
of predicates as functions. As such, if $M$ is a matrix, then the results are
|
||||||
|
implementation-defined (since the value does not make sense within the algorithm
|
||||||
|
as defined).
|
||||||
|
|
||||||
|
\subsubsection{Integer Results}
|
||||||
|
\label{s:cmatch-int}
|
||||||
|
$A$ defines $R$ to be a vector/matrix of boolean values. However, it may be
|
||||||
|
useful to use the cmatch results in calculations; as such, implementations that
|
||||||
|
make use of or produce cmatch results are required to do one or both of the
|
||||||
|
following where $b$ is a boolean scalar:
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\item
|
||||||
|
Implicitly consider $b$ to be $\textrm{int}\!\left(b\right)$ when used in
|
||||||
|
calculations, and/or
|
||||||
|
|
||||||
|
\item
|
||||||
|
Perform the implicit conversion before $R$ is returned from $A$,
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
where the function {\sl int} is defined as
|
||||||
|
|
||||||
|
$$
|
||||||
|
\textrm{int}(b) = \left\{
|
||||||
|
\begin{array}{ll}
|
||||||
|
1 & \textrm{if }b = \top, \\
|
||||||
|
0 & \textrm{if }b = \bot.
|
||||||
|
\end{array}
|
||||||
|
\right.\qquad
|
||||||
|
b \in \left\{\top,\bot\right\}.
|
||||||
|
$$
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{Scalar Classification Matches}
|
||||||
|
\label{s:cmatch-scalar}
|
||||||
|
Implementations may find it convenient to support scalar inputs and scalar
|
||||||
|
classification matches to represent matching ``all'' indexes of a vector.
|
||||||
|
\aref{cmatch} defines both a classification match ($R$, and consequently $F$)
|
||||||
|
and an input ($I$) to be a vector, which is generally sufficient. However, in
|
||||||
|
the case where the number of indexes of the inputs and results of other matches
|
||||||
|
may be arbitrary, it may be useful to apply a certain classification across all
|
||||||
|
indexes, which cannot be done when $c = \top$ using \aref{cmatch}.
|
||||||
|
|
||||||
|
The onus of such a feature is on the implementation---it should flag such input
|
||||||
|
($I$) as a scalar, which is necessary since $I$ is unconditionally converted to
|
||||||
|
a vector by step \asref{cmatch}{input-vectorize}. If an implementation decides
|
||||||
|
to support scalar classification matches, \emph{it must conform to this
|
||||||
|
section}. Let such a scalar flag be denoted $s_k \inbool$ respective to input
|
||||||
|
$I_k$. Handling of both $F$ and $I$ is discussed in the sections that follow.
|
||||||
|
|
||||||
|
\subsubsection{Mixing Scalar And Vectorized Inputs}
|
||||||
|
\label{s:cmatch-scalar-mixed}
|
||||||
|
Under the condition that $\exists v\in s(v=\top)$, the compiler must:
|
||||||
|
|
||||||
|
\begingroup
|
||||||
|
% this definition is local to this group
|
||||||
|
\def\siset{k \in\set{j : s_j = \top}}
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\item
|
||||||
|
Reorder inputs $I$ such that each scalar input $I_k, \siset$ be applied
|
||||||
|
after all non-scalar inputs have been matched using \aref{cmatch}.
|
||||||
|
\begin{enumerate}
|
||||||
|
\item
|
||||||
|
Consequently (and contrary to what was mentioned in \aref{cmatch}),
|
||||||
|
application order of $A$ with respect to inputs $I$ \emph{does} in fact
|
||||||
|
matter and implementations should ensure that this restriction holds
|
||||||
|
during runtime.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\item
|
||||||
|
Before application of a scalar input, the scalar $I_k$ should be vectorized
|
||||||
|
according to the following rule:
|
||||||
|
|
||||||
|
$$
|
||||||
|
I'_{k,l} = I_k,
|
||||||
|
\qquad \siset,
|
||||||
|
\; 0 \leq l < \#R',
|
||||||
|
$$
|
||||||
|
|
||||||
|
where $R'$ is the value immediately before the application of $I_k$ as
|
||||||
|
defined in \aref{cmatch}.
|
||||||
|
|
||||||
|
\item
|
||||||
|
Application of \aref{cmatch} should then proceed as normal, using $I'$ in
|
||||||
|
place of $I$.
|
||||||
|
\end{enumerate}
|
||||||
|
\endgroup
|
||||||
|
|
||||||
|
\subsubsection{Converting Vectorized Match To Scalar}
|
||||||
|
As defined by \aref{cmatch}, the result $R$ will always be a vector. An
|
||||||
|
implementation may \emph{only} convert a vectorized match to a scalar using the
|
||||||
|
method defined in this section under the condition that $\forall v\in
|
||||||
|
s(v=\top)$; otherwise, there will be a loss of data (due to the expansion rules
|
||||||
|
defined in \sref{cmatch-scalar-mixed}). The implementation also \emph{must not}
|
||||||
|
reduce the vectorized match to a scalar using $\Omega$. An implementation
|
||||||
|
\emph{may}, however, $\Omega$-reduce the match result $R$ into an
|
||||||
|
\emph{separate} value as mentioned in \sref{cmatch-boolean}.
|
||||||
|
|
||||||
|
Under the condition that $\forall v\in s(v=\top)$, the system may post-process
|
||||||
|
$F$ (as defined in \aref{cmatch}) such that
|
||||||
|
|
||||||
|
$$
|
||||||
|
F' = F_0,
|
||||||
|
$$
|
||||||
|
|
||||||
|
and return $F'$ in place of $F$.
|
||||||
|
|
||||||
|
Note also that $F'$ may be fed back into \aref{cmatch} as an input and that the
|
||||||
|
results will be consistent and well-defined according to
|
||||||
|
\sref{cmatch-scalar-mixed} (and, consequently, this section).
|
|
@ -0,0 +1,30 @@
|
||||||
|
% manual style package
|
||||||
|
|
||||||
|
% these margins ensure that the PDF can be easily scrolled vertically without
|
||||||
|
% worrying about alternating margins (good for viewing on screen, but not on
|
||||||
|
% paper)
|
||||||
|
\usepackage[margin=1.25in]{geometry}
|
||||||
|
\usepackage{amsmath}
|
||||||
|
|
||||||
|
\setcounter{secnumdepth}{3}
|
||||||
|
\setcounter{tocdepth}{3}
|
||||||
|
|
||||||
|
% no name yet
|
||||||
|
\def\lang{the DSL}
|
||||||
|
|
||||||
|
\def\sref#1{Section \ref{s:#1}}
|
||||||
|
\def\fref#1{Figure \ref{f:#1}}
|
||||||
|
\def\aref#1{Algorithm \ref{a:#1}}
|
||||||
|
\def\asref#1#2{A\ref{a:#1}(\ref{a:#1:#2})}
|
||||||
|
|
||||||
|
\def\set#1{%
|
||||||
|
\ifmmode%
|
||||||
|
\left\{#1\right\}%
|
||||||
|
\else
|
||||||
|
$\left\{#1\right\}$%
|
||||||
|
\fi%
|
||||||
|
}
|
||||||
|
\def\boolset{\set{\top,\bot}}
|
||||||
|
\def\inbool{\in\boolset}
|
||||||
|
|
||||||
|
\def\term#1{{\sl #1}}
|
|
@ -0,0 +1,19 @@
|
||||||
|
\documentclass[10pt]{book}
|
||||||
|
|
||||||
|
%%begin preamble
|
||||||
|
\usepackage{manual}
|
||||||
|
|
||||||
|
\author{Mike Gerwitz\\LoVullo Associates}
|
||||||
|
\date{\today}
|
||||||
|
%%end preamble
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\title{Calc DSL: Design Specification and Programmer's Manual}
|
||||||
|
\maketitle
|
||||||
|
|
||||||
|
\tableofcontents
|
||||||
|
|
||||||
|
\include{chapters/class}
|
||||||
|
|
||||||
|
\end{document}
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Outputs graph visualization of dependencies in DOT format
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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:dot="http://www.lovullo.com/calc/dot">
|
||||||
|
|
||||||
|
<xsl:import href="dot/depout.xsl" />
|
||||||
|
<xsl:import href="dot/defnode.xsl" />
|
||||||
|
|
||||||
|
<!-- supported sources (entry points) -->
|
||||||
|
<xsl:include href="dot/pkg-obj.xsl" />
|
||||||
|
<xsl:include href="dot/pkg-exec.xsl" />
|
||||||
|
|
||||||
|
<xsl:output method="text" />
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Newline character
|
||||||
|
-->
|
||||||
|
<xsl:variable name="dot:nl" select="' '" />
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Immediately fails on unrecognized source type
|
||||||
|
-->
|
||||||
|
<xsl:template match="lv:package" priority="1">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>[dot] fatal: this is not an object/executable file: </xsl:text>
|
||||||
|
<xsl:text>no symbol dependencies found</xsl:text>
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Beginning of a DOT document
|
||||||
|
-->
|
||||||
|
<xsl:template match="lv:package" mode="dot:head">
|
||||||
|
<xsl:text>/* dependency graph of </xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text> */</xsl:text>
|
||||||
|
|
||||||
|
<xsl:text>digraph "</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>" { </xsl:text>
|
||||||
|
|
||||||
|
<xsl:text>graph [rankdir="LR", ranksep="2"]; </xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
End of a DOT document
|
||||||
|
-->
|
||||||
|
<xsl:template match="lv:package" mode="dot:tail">
|
||||||
|
<xsl:text>}</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Styles node color based on symbol type
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
|
||||||
|
xmlns:dot="http://www.lovullo.com/calc/dot"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Parameter
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:attr-color" priority="5"
|
||||||
|
match="*[ @type='param' ]">
|
||||||
|
|
||||||
|
<dot:attr name="color">#204a87</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Param type
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:attr-color" priority="5"
|
||||||
|
match="*[ @type='type' ]">
|
||||||
|
|
||||||
|
<dot:attr name="color">#729fcf</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Classification
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:attr-color" priority="5"
|
||||||
|
match="*[ @type='class' or @type='cgen' ]">
|
||||||
|
|
||||||
|
<dot:attr name="color">#4e9a06</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Function
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:attr-color" priority="5"
|
||||||
|
match="*[ @type='func' ]">
|
||||||
|
|
||||||
|
<dot:attr name="color">#c4a000</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Map
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:attr-color" priority="5"
|
||||||
|
match="*[ @type='map' or @type='retmap' ]">
|
||||||
|
|
||||||
|
<dot:attr name="color">#888a85</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Default
|
||||||
|
-->
|
||||||
|
<xsl:template match="*" mode="dot:attr-color" priority="1">
|
||||||
|
<!-- no color -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Styles node based on locality
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
|
||||||
|
xmlns:dot="http://www.lovullo.com/calc/dot"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
External nodes should be styled as such
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:attr-extern" priority="5" match="
|
||||||
|
*[ @src and not( @src='' ) ]
|
||||||
|
">
|
||||||
|
|
||||||
|
<dot:attr name="style">dashed</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Default node attributes
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym" mode="dot:defnode-attr" priority="1">
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Styles node based on keep flag
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
|
||||||
|
xmlns:dot="http://www.lovullo.com/calc/dot"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
External nodes should be styled as such
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:attr-keep" priority="5" match="
|
||||||
|
*[ @keep='true' ]
|
||||||
|
">
|
||||||
|
|
||||||
|
<dot:attr name="fontcolor">red</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Default node attributes
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym" mode="dot:defnode-keep" priority="1">
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Styles node shape based on symbol type
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
|
||||||
|
xmlns:dot="http://www.lovullo.com/calc/dot"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Parameter
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:attr-shape" priority="5"
|
||||||
|
match="*[ @type='param' ]">
|
||||||
|
|
||||||
|
<dot:attr name="shape">box</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Classification
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:attr-shape" priority="5"
|
||||||
|
match="*[ @type='class' or @type='cgen' ]">
|
||||||
|
|
||||||
|
<dot:attr name="shape">octagon</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Function
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:attr-shape" priority="5"
|
||||||
|
match="*[ @type='func' ]">
|
||||||
|
|
||||||
|
<dot:attr name="shape">component</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Map
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:attr-shape" priority="5"
|
||||||
|
match="*[ @type='map' or @type='retmap' ]">
|
||||||
|
|
||||||
|
<dot:attr name="shape">note</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Default
|
||||||
|
-->
|
||||||
|
<xsl:template match="*" mode="dot:attr-shape" priority="1">
|
||||||
|
<!-- default shape -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Outputs graph visualization of dependencies in DOT format
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
|
||||||
|
xmlns:dot="http://www.lovullo.com/calc/dot"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
<xsl:import href="./attr-color.xsl" />
|
||||||
|
<xsl:import href="./attr-shape.xsl" />
|
||||||
|
<xsl:import href="./attr-extern.xsl" />
|
||||||
|
<xsl:import href="./attr-keep.xsl" />
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
External nodes should be styled as such
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:defnode-attr" priority="5" match="
|
||||||
|
preproc:sym[ @src and not( @src='' ) ]
|
||||||
|
">
|
||||||
|
|
||||||
|
<dot:attr name="label">
|
||||||
|
<xsl:value-of select="@src" />
|
||||||
|
<xsl:text>/\n</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
</dot:attr>
|
||||||
|
|
||||||
|
<dot:attr name="tooltip">
|
||||||
|
<xsl:value-of select="@src" />
|
||||||
|
<xsl:text>/</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
</dot:attr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Default node attributes
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym" mode="dot:defnode-attr" priority="1">
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Render an attribute list as a comma-delimited string
|
||||||
|
|
||||||
|
Expects a tree of dot:attr nodes where @name is the name of the attribute, and
|
||||||
|
its normalized text is the value. The value will be quoted; double quotes must
|
||||||
|
be manually escaped prior to calling this template.
|
||||||
|
-->
|
||||||
|
<xsl:template name="dot:render-attr-list">
|
||||||
|
<xsl:param name="attr-list" />
|
||||||
|
|
||||||
|
<xsl:for-each select="$attr-list/dot:attr">
|
||||||
|
<xsl:if test="position() > 1">
|
||||||
|
<xsl:text>, </xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>="</xsl:text>
|
||||||
|
<xsl:value-of select="normalize-space( text() )" />
|
||||||
|
<xsl:text>"</xsl:text>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
|
@ -0,0 +1,107 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Graph node definitions
|
||||||
|
|
||||||
|
Nodes do not need to be defined (DOT will generate them upon first reference);
|
||||||
|
this defines nodes that require additional data associated with them.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
|
||||||
|
xmlns:dot="http://www.lovullo.com/calc/dot"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
<xsl:import href="./defnode-attr.xsl" />
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Do not declare constants or generated symbols
|
||||||
|
|
||||||
|
XXX: Duplicated logic from smy-ref!
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:defnode" priority="9" match="
|
||||||
|
preproc:sym[
|
||||||
|
@type='const'
|
||||||
|
or @type='map' or @type='retmap'
|
||||||
|
or @type='map:head' or @type='map:tail'
|
||||||
|
or @type='retmap:head' or @type='retmap:tail'
|
||||||
|
or (
|
||||||
|
@type='type'
|
||||||
|
and (
|
||||||
|
@name='integer'
|
||||||
|
or @name='float'
|
||||||
|
or @name='boolean'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or @parent
|
||||||
|
or @preproc:generated='true'
|
||||||
|
]
|
||||||
|
">
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Process parent symbol in place of current symbol
|
||||||
|
|
||||||
|
Symbols with defined parents are generated as part of that parent and will
|
||||||
|
therefore be treated as a single unit.
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym[ @parent ]" mode="dot:defnode" priority="7">
|
||||||
|
<xsl:variable name="parent" select="@parent" />
|
||||||
|
|
||||||
|
<xsl:apply-templates select="
|
||||||
|
parent::preproc:symtable/preproc:sym[ @name=$parent ]
|
||||||
|
" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Default node definition
|
||||||
|
|
||||||
|
If no attributes are generated, then the node will be entirely omitted (it'll
|
||||||
|
be created automatically by DOT when referenced).
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym" mode="dot:defnode" priority="1">
|
||||||
|
<xsl:variable name="attr">
|
||||||
|
<xsl:call-template name="dot:render-attr-list">
|
||||||
|
<xsl:with-param name="attr-list">
|
||||||
|
<!-- this kluge exists because of XSLT limitiations and the confusion
|
||||||
|
that would result (in this particular situation) from
|
||||||
|
xsl:apply-imports
|
||||||
|
-->
|
||||||
|
<xsl:apply-templates select="." mode="dot:defnode-attr" />
|
||||||
|
<xsl:apply-templates select="." mode="dot:attr-extern" />
|
||||||
|
<xsl:apply-templates select="." mode="dot:attr-color" />
|
||||||
|
<xsl:apply-templates select="." mode="dot:attr-shape" />
|
||||||
|
<xsl:apply-templates select="." mode="dot:attr-keep" />
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:if test="not( $attr = '' )">
|
||||||
|
<xsl:text>"</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>" [</xsl:text>
|
||||||
|
<xsl:value-of select="$attr" />
|
||||||
|
|
||||||
|
<xsl:if test="@src and not( @src='' )">
|
||||||
|
<xsl:if test="$attr">
|
||||||
|
<xsl:text>,</xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!-- link to other packages in the graph for navigation -->
|
||||||
|
<xsl:text>href="</xsl:text>
|
||||||
|
<xsl:value-of select="concat( @src, '.svg' )" />
|
||||||
|
<xsl:text>"</xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:text>];</xsl:text>
|
||||||
|
|
||||||
|
<xsl:value-of select="$dot:nl" />
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Outputs dependency relationship to a directed graph
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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:dot="http://www.lovullo.com/calc/dot"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Container for all the dependencies
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym-deps" mode="dot:depout" priority="5">
|
||||||
|
<xsl:apply-templates mode="dot:depout" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Treat the entry point (lv:yield) as the root node
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym-dep[ @name='___yield' ]" mode="dot:depout" priority="6">
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text> [root=ctr,fontsize=24,style=bold,label="Yield"]; </xsl:text>
|
||||||
|
|
||||||
|
<xsl:apply-templates mode="dot:depout" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Constant and generated symbols will not be rendered
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:depout" priority="5" match="
|
||||||
|
preproc:sym-dep[
|
||||||
|
@name=ancestor::lv:package/preproc:symtable/preproc:sym[
|
||||||
|
@type='const'
|
||||||
|
or @preproc:generated='true'
|
||||||
|
]/@name
|
||||||
|
]
|
||||||
|
">
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Container for symbol dependencies
|
||||||
|
|
||||||
|
That is: this node represents a symbol, and its children are its dependencies.
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym-dep" mode="dot:depout" priority="3">
|
||||||
|
<xsl:apply-templates mode="dot:depout" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Do not output relationships to primitives or constants; or generated
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:depout" priority="5" match="
|
||||||
|
preproc:sym-ref[
|
||||||
|
@type='type'
|
||||||
|
and (
|
||||||
|
@name='integer'
|
||||||
|
or @name='float'
|
||||||
|
or @name='boolean'
|
||||||
|
)
|
||||||
|
or @type='const'
|
||||||
|
or @type='lparam'
|
||||||
|
or @type='map' or @type='retmap'
|
||||||
|
or @type='map:head' or @type='map:tail'
|
||||||
|
or @type='retmap:head' or @type='retmap:tail'
|
||||||
|
]
|
||||||
|
">
|
||||||
|
|
||||||
|
<!-- skip -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Process generated symbol deps as our own
|
||||||
|
|
||||||
|
Generated symbols are not known by the user, so they should be treated as part
|
||||||
|
of the unit from which they are generated.
|
||||||
|
-->
|
||||||
|
<xsl:template mode="dot:depout" priority="4" match="
|
||||||
|
preproc:sym-ref[
|
||||||
|
@name=ancestor::lv:package/preproc:symtable/preproc:sym[
|
||||||
|
@preproc:generated='true'
|
||||||
|
]/@name
|
||||||
|
]
|
||||||
|
">
|
||||||
|
|
||||||
|
<xsl:param name="usedby" select="parent::preproc:sym-dep/@name" />
|
||||||
|
|
||||||
|
<xsl:variable name="name" select="@name" />
|
||||||
|
|
||||||
|
<!-- process the generated symbol's deps as our own -->
|
||||||
|
<xsl:apply-templates mode="dot:depout" select="
|
||||||
|
ancestor::preproc:sym-deps/preproc:sym-dep[
|
||||||
|
@name=$name
|
||||||
|
]/preproc:sym-ref
|
||||||
|
">
|
||||||
|
<xsl:with-param name="usedby" select="$usedby" />
|
||||||
|
</xsl:apply-templates>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Process references with parents as if they were their parent symbol
|
||||||
|
|
||||||
|
Symbols with defined parents are generated as part of that parent and will
|
||||||
|
therefore be treated as a single unit.
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym-ref[ @parent ]" mode="dot:depout" priority="3">
|
||||||
|
<xsl:param name="usedby" select="parent::preproc:sym-dep/@name" />
|
||||||
|
|
||||||
|
<xsl:variable name="parent" select="@parent" />
|
||||||
|
|
||||||
|
<xsl:apply-templates mode="dot:depout" select="
|
||||||
|
ancestor::lv:package/preproc:symtable/preproc:sym[ @name=$parent ]
|
||||||
|
">
|
||||||
|
<xsl:with-param name="usedby" select="$usedby" />
|
||||||
|
</xsl:apply-templates>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Trigger processing of symbol associated with the ref
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym-ref" mode="dot:depout" priority="2">
|
||||||
|
<xsl:param name="usedby" select="parent::preproc:sym-dep/@name" />
|
||||||
|
|
||||||
|
<xsl:variable name="name" select="@name" />
|
||||||
|
|
||||||
|
<xsl:apply-templates mode="dot:depout" select="
|
||||||
|
ancestor::lv:package/preproc:symtable/preproc:sym[ @name=$name ]
|
||||||
|
">
|
||||||
|
<xsl:with-param name="usedby" select="$usedby" />
|
||||||
|
</xsl:apply-templates>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Output symbol reference to directed graph
|
||||||
|
|
||||||
|
The symbol (dependency) is referenced as a node adjacent to the node of the
|
||||||
|
symbol that uses it. The edge is directed toward the dependency and shall be
|
||||||
|
read as "uses".
|
||||||
|
|
||||||
|
For example: "foo uses bar":
|
||||||
|
(foo) -> (bar)
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym" mode="dot:depout" priority="5">
|
||||||
|
<xsl:param name="usedby" />
|
||||||
|
|
||||||
|
<xsl:variable name="attr">
|
||||||
|
<xsl:call-template name="dot:render-attr-list">
|
||||||
|
<xsl:with-param name="attr-list">
|
||||||
|
<xsl:apply-templates select="." mode="dot:attr-extern" />
|
||||||
|
<xsl:apply-templates select="." mode="dot:attr-color" />
|
||||||
|
</xsl:with-param>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:text>"</xsl:text>
|
||||||
|
<xsl:value-of select="$usedby" />
|
||||||
|
<xsl:text disable-output-escaping="yes">" -> "</xsl:text>
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text>"</xsl:text>
|
||||||
|
|
||||||
|
<xsl:if test="not( $attr='' )">
|
||||||
|
<xsl:text> [</xsl:text>
|
||||||
|
<xsl:value-of select="$attr" />
|
||||||
|
<xsl:text>]</xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:text>;</xsl:text>
|
||||||
|
|
||||||
|
<xsl:value-of select="$dot:nl" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Bail out if asked to render something unexpected
|
||||||
|
-->
|
||||||
|
<xsl:template match="*" mode="dot:depout" priority="1">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>error: what do I do!?: unexpected </xsl:text>
|
||||||
|
<xsl:value-of select="name()" />
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Extra comments and attributes are ignored
|
||||||
|
|
||||||
|
text() is ignored, otherwise, extra whitespace corresponding to the
|
||||||
|
indentation of nodes appears in the output.
|
||||||
|
|
||||||
|
Ignoring attributes is just in case of an xpath whoopsie, but probably isn't
|
||||||
|
necessary, and is probably dangerous (because it may veil bugs).
|
||||||
|
-->
|
||||||
|
<xsl:template match="@*|text()" mode="dot:depout" priority="1">
|
||||||
|
<!-- ignore -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Processes executable file dependency graph
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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:l="http://www.lovullo.com/rater/linker"
|
||||||
|
xmlns:dot="http://www.lovullo.com/calc/dot"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Entry point for linked executable (.xmle) DOT generation
|
||||||
|
|
||||||
|
We wish to generate a dependency graph for an entire program. This approach is
|
||||||
|
a little bit different than the approach to processing object files, because
|
||||||
|
we know that the linker's symbol table contains *only* those symbols that are
|
||||||
|
used (or kept). We further know that each symbol (unless there's a bug in the
|
||||||
|
linker) is referenced only a single time in the symbol table.
|
||||||
|
|
||||||
|
This makes our job easy: simply walk the symbol table, look up the
|
||||||
|
preproc:sym-dep in the source package, and render as we normally would for an
|
||||||
|
object file.
|
||||||
|
|
||||||
|
Lord Jesus it's a fire.
|
||||||
|
-->
|
||||||
|
<xsl:template match="lv:package[ l:dep ]" priority="9">
|
||||||
|
<xsl:apply-templates select="." mode="dot:head" />
|
||||||
|
|
||||||
|
<!-- we know that all symbols in the linker symbol table are used, so we can
|
||||||
|
immediately generate the node definitions -->
|
||||||
|
<xsl:apply-templates mode="dot:defnode"
|
||||||
|
select="l:dep/preproc:sym" />
|
||||||
|
|
||||||
|
<!-- outputting the dependencies of those symbols is more involved and
|
||||||
|
requires processing data from each object file -->
|
||||||
|
<xsl:apply-templates select="l:dep/preproc:sym" mode="dot:ldep-sym-deps">
|
||||||
|
<xsl:with-param name="exec-name" select="concat( @__rootpath, @name )" />
|
||||||
|
</xsl:apply-templates>
|
||||||
|
|
||||||
|
<xsl:apply-templates select="." mode="dot:tail" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Omit symbols with parent references
|
||||||
|
|
||||||
|
Symbols with parents are generated from that parent and will be considered to
|
||||||
|
be a single unit. Since the parent will also be in the symbol table (it is,
|
||||||
|
after all, a dependency), we don't have to worry about these at all.
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym[ @parent ]" mode="dot:ldep-sym-deps" priority="5">
|
||||||
|
<!-- ignore -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Process dependencies for each symbol
|
||||||
|
|
||||||
|
The linker symbol table only stores a flattened symbol list; to get the
|
||||||
|
symbol's dependencies, we must consult the source object file.
|
||||||
|
-->
|
||||||
|
<xsl:template match="preproc:sym" mode="dot:ldep-sym-deps" priority="1">
|
||||||
|
<xsl:param name="exec-name" />
|
||||||
|
|
||||||
|
<xsl:variable name="name" select="@name" />
|
||||||
|
|
||||||
|
<!-- empty @src implies program package -->
|
||||||
|
<xsl:variable name="pkg" select="
|
||||||
|
if ( @src and not( @src='' ) ) then
|
||||||
|
document( concat( @src, '.xmlo' ), / )/lv:package
|
||||||
|
else
|
||||||
|
document( concat( $exec-name, '.xmlo' ), / )/lv:package
|
||||||
|
" />
|
||||||
|
|
||||||
|
<xsl:variable name="sym-dep" select="
|
||||||
|
$pkg/preproc:sym-deps/preproc:sym-dep[
|
||||||
|
@name=$name
|
||||||
|
]
|
||||||
|
" />
|
||||||
|
|
||||||
|
<xsl:if test="not( $sym-dep )">
|
||||||
|
<xsl:message terminate="yes">
|
||||||
|
<xsl:text>error: cannot locate symbol dependencies for `</xsl:text>
|
||||||
|
<xsl:value-of select="concat( @src, '/', @name )" />
|
||||||
|
<xsl:text>'</xsl:text>
|
||||||
|
</xsl:message>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:apply-templates select="$sym-dep" mode="dot:depout" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Processes object file dependency graph
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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:dot="http://www.lovullo.com/calc/dot"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Entry point for object file DOT generation
|
||||||
|
|
||||||
|
To render the graph, we first declare all nodes associated with all referenced
|
||||||
|
symbols in the symbol tree (it's important to check against preproc:sym-deps,
|
||||||
|
since it's likely that not all imported symbols are used); this allows setting
|
||||||
|
attributes for the symbol nodes on the graph without having to worry about
|
||||||
|
duplicate code later on.
|
||||||
|
|
||||||
|
After that, we simply recurse through the dependency list and neighbor the
|
||||||
|
nodes.
|
||||||
|
-->
|
||||||
|
<xsl:template match="lv:package[ preproc:sym-deps ]" priority="5">
|
||||||
|
<xsl:apply-templates select="." mode="dot:head" />
|
||||||
|
|
||||||
|
<xsl:variable name="sym-deps" select="preproc:sym-deps" />
|
||||||
|
|
||||||
|
<!-- pre-style all referenced nodes (the symbol table is likely to contain
|
||||||
|
references to symbols that were imported but not used) -->
|
||||||
|
<xsl:apply-templates mode="dot:defnode" select="
|
||||||
|
preproc:symtable/preproc:sym[
|
||||||
|
@name=$sym-deps/preproc:sym-dep/preproc:sym-ref/@name
|
||||||
|
or @name=$sym-deps/preproc:sym-dep/preproc:sym-ref/@parent
|
||||||
|
]
|
||||||
|
" />
|
||||||
|
|
||||||
|
<!-- output graph description -->
|
||||||
|
<xsl:apply-templates select="preproc:sym-deps" mode="dot:depout" />
|
||||||
|
|
||||||
|
<xsl:apply-templates select="." mode="dot:tail" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
|
@ -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> & </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"> & </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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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="' 	
'" />
|
||||||
|
<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>
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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:* ) < 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:* ) < 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.
|
||||||
|
-->
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
File diff suppressed because it is too large
Load Diff
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||||
|
|
||||||
|
<xsl:include href="compiler/linker.xsl" />
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
|
@ -0,0 +1,412 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
targetNamespace="http://www.lovullo.com/rater/map"
|
||||||
|
xmlns="http://www.lovullo.com/rater/map"
|
||||||
|
elementFormDefault="qualified">
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="classDescriptorType">
|
||||||
|
<xs:attribute name="name" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Classification name (lv:classify/@as)
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="ignores-eligibility" type="xs:boolean">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Classification should not add a match requiring that at least one
|
||||||
|
eligible supplier use it (if supported by implementation)
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:simpleType name="valueType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
String constant
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:restriction base="xs:string" />
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="defaultType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Default complex value for a translation
|
||||||
|
|
||||||
|
Concatenates each value.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:choice maxOccurs="unbounded">
|
||||||
|
<xs:element name="from" type="fromType"
|
||||||
|
minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
<xs:element name="value" type="valueType"
|
||||||
|
minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xs:choice>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="translateType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Defines a translation for a given value
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:choice maxOccurs="unbounded">
|
||||||
|
<xs:element name="from" type="fromType"
|
||||||
|
minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
<xs:element name="value" type="valueType"
|
||||||
|
minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xs:choice>
|
||||||
|
|
||||||
|
<xs:attribute name="key" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Source value to match against for translation
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="value" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Value to translate to
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="empty" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Default value when the resulting translation is the
|
||||||
|
empty string
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="fromType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Defines translation rules between source and destination fields; not
|
||||||
|
to be used with @from
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:choice maxOccurs="unbounded">
|
||||||
|
<!-- translation rule -->
|
||||||
|
<xs:element name="translate" type="translateType"
|
||||||
|
minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
<xs:element name="default" type="defaultType"
|
||||||
|
minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xs:choice>
|
||||||
|
|
||||||
|
<xs:attribute name="name" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Identifier of source field
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="default" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Optional default value if no source value is available
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="affects-eligibility" type="xs:boolean">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Whether this field should be considered when generating eligibility
|
||||||
|
classes (if supported by implementation); default true
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:group name="setTransformGroup">
|
||||||
|
<xs:choice>
|
||||||
|
<xs:element name="set" type="setType" />
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="const">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Maps a static value
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:attribute name="value" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Static value to map to destination
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="from">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Maps a source value to its destination by index
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:attribute name="name" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Source field identifier
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="index" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Iterator variable or constant integer representing the source
|
||||||
|
value index
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:choice>
|
||||||
|
</xs:group>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="setType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Translates source data into a set
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:group ref="setTransformGroup" minOccurs="1" maxOccurs="unbounded" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="each" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Source field identifier to use as index for the iterator
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="index" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Variable to serve as a reference for the iterator index
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="ignore-empty" type="xs:boolean">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
When true, if a transformation yields a value that is undefined, an
|
||||||
|
empty string, or the string "0", then omit it from the set
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="mapType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Defines a map from a source field to a destination field with optional
|
||||||
|
transformation rules
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="from" type="fromType" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="set" type="setType" minOccurs="0" maxOccurs="1" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="to" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Identifier of destination field
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="from" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Identifier of source field if no data transformations are to be
|
||||||
|
performed; cannot be used with @value
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="value" type="xs:string">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Constant value to be mapped to destination; cannot be used with @from
|
||||||
|
or from node
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="affects-eligibility" type="xs:boolean">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Whether this field should be considered when generating eligibility
|
||||||
|
classes (if supported by implementation); default true
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="override" type="xs:boolean">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Override mapping sharing the same destination identifier in an
|
||||||
|
imported package
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="passType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Maps from a source field to a destination field of the same name without
|
||||||
|
any translation; shorthand for identical @to and @from attributes on a
|
||||||
|
general map node
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:attribute name="name" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Identifier of the source (and consequently destination) field
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="novalidate" type="xs:boolean">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Do not validate that the field exists; useful for mapping data that is
|
||||||
|
not explicitly recognized as a field by the source
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="affects-eligibility" type="xs:boolean">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Whether this field should be considered when generating eligibility
|
||||||
|
classes (if supported by implementation); default true
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="override" type="xs:boolean">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Override mapping sharing the same destination identifier in an
|
||||||
|
imported package
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- represents some type of mapping -->
|
||||||
|
<xs:group name="mappingGroup">
|
||||||
|
<xs:choice>
|
||||||
|
<xs:element name="map" type="mapType"
|
||||||
|
minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
<xs:element name="pass" type="passType"
|
||||||
|
minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xs:choice>
|
||||||
|
</xs:group>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:complexType name="importType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Includes mappings from another source file
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:attribute name="path" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Path to source file
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="program-map">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Maps program data between two points
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="import" type="importType"
|
||||||
|
minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
<xs:element name="class" type="classDescriptorType"
|
||||||
|
minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
|
||||||
|
<xs:group ref="mappingGroup" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="src" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Source document to validate against (document root node must be
|
||||||
|
known to the implementation)
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="return-map">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Specifies data transformations/filtering to be performed on data before
|
||||||
|
being returned to a caller
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="import" type="importType"
|
||||||
|
minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
|
||||||
|
<xs:group ref="mappingGroup" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:schema>
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Writes preprocessor output to disk to eliminate the overhead of reprocessing
|
||||||
|
for each task that requires such output.
|
||||||
|
|
||||||
|
Also performs validation.
|
||||||
|
|
||||||
|
N.B.: Requires XSLT >=2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:lvm="http://www.lovullo.com/rater/map"
|
||||||
|
xmlns:w="http://www.lovullo.com/rater/worksheet"
|
||||||
|
xmlns:lv="http://www.lovullo.com/rater"
|
||||||
|
xmlns:lvp="http://www.lovullo.com">
|
||||||
|
|
||||||
|
<xsl:output method="text" />
|
||||||
|
|
||||||
|
<xsl:variable name="nl" select="' '" />
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lv:rater|lv:package">
|
||||||
|
<!-- output deps, one per line -->
|
||||||
|
<xsl:for-each select="lv:import[ @package ]">
|
||||||
|
<xsl:value-of select="concat( @package, $nl )" />
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="lvp:program">
|
||||||
|
<!-- output deps, one per line -->
|
||||||
|
<xsl:for-each select="lvp:import[ @package ]">
|
||||||
|
<xsl:value-of select="concat( @package, $nl )" />
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="lvm:program-map|lvm:return-map">
|
||||||
|
<!-- output deps, one per line -->
|
||||||
|
<xsl:for-each select="lvm:import[ @path ]">
|
||||||
|
<xsl:value-of select="concat( @path, $nl )" />
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="w:worksheet">
|
||||||
|
<xsl:value-of select="concat( @package, $nl )" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="*">
|
||||||
|
<!-- do nothing -->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
||||||
|
# may be copied into the cwd for testing, since it is a dep
|
||||||
|
saxon8.jar
|
||||||
|
|
||||||
|
*.class
|
||||||
|
*.jar
|
||||||
|
*.manifest
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
dslc_src := $(wildcard com/lovullo/dslc/*.java)
|
||||||
|
dslc_bin := $(dslc_src:.java=.class)
|
||||||
|
|
||||||
|
.PHONY: dslc clean
|
||||||
|
|
||||||
|
dslc: dslc.jar
|
||||||
|
|
||||||
|
%.class: %.java
|
||||||
|
javac $<
|
||||||
|
|
||||||
|
# we explicitly specify a glob on the path because inner classes are compiled
|
||||||
|
# into their own files
|
||||||
|
dslc.jar: $(dslc_bin)
|
||||||
|
jar cfm $@ dslc.manifest com/lovullo/dslc/*.class
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(dslc_bin) dslc.jar
|
|
@ -0,0 +1,303 @@
|
||||||
|
|
||||||
|
package com.lovullo.dslc;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
import javax.xml.transform.*;
|
||||||
|
import javax.xml.validation.*;
|
||||||
|
import javax.xml.transform.sax.SAXTransformerFactory;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.SAXNotRecognizedException;
|
||||||
|
import org.xml.sax.SAXNotSupportedException;
|
||||||
|
|
||||||
|
public class DslCompiler
|
||||||
|
{
|
||||||
|
private static class _DslCompiler
|
||||||
|
{
|
||||||
|
private Validator _xsd;
|
||||||
|
private HashMap<String,Transformer> _xsl;
|
||||||
|
|
||||||
|
|
||||||
|
public _DslCompiler()
|
||||||
|
{
|
||||||
|
_xsd = _createXsd();
|
||||||
|
_xsl = new HashMap<String,Transformer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void compile(
|
||||||
|
Source doc,
|
||||||
|
String cmd,
|
||||||
|
String src,
|
||||||
|
String dest,
|
||||||
|
HashMap<String,String> params
|
||||||
|
) throws Exception
|
||||||
|
{
|
||||||
|
if ( cmd.equals( "validate" ) )
|
||||||
|
{
|
||||||
|
_xsd.validate( doc );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ( cmd.equals( "rm" ) )
|
||||||
|
{
|
||||||
|
// remove file (purposely uncaught)
|
||||||
|
( new File( src ) ).delete();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dest.equals( "" ) )
|
||||||
|
{
|
||||||
|
System.err.printf(
|
||||||
|
"fatal: no destination path provided\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
System.exit( 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// transform to dest
|
||||||
|
File destfile = new File( dest );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_transform(
|
||||||
|
src,
|
||||||
|
doc,
|
||||||
|
cmd,
|
||||||
|
new StreamResult( new File( dest ) ),
|
||||||
|
params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
// delete the output file; it's garbage
|
||||||
|
destfile.delete();
|
||||||
|
|
||||||
|
// be verbose and unprofessional.
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void _transform(
|
||||||
|
String src,
|
||||||
|
Source doc,
|
||||||
|
String cmd,
|
||||||
|
StreamResult dest,
|
||||||
|
HashMap<String,String> params
|
||||||
|
) throws Exception
|
||||||
|
{
|
||||||
|
// load the stylesheet if it has not been already (we load lazily in
|
||||||
|
// case the stylesheet is never needed)
|
||||||
|
if ( !( _xsl.containsKey( cmd ) ) )
|
||||||
|
{
|
||||||
|
_xsl.put( cmd, _createXslt( cmd ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// since XSL's abstraction does not provide a means to retrieve the
|
||||||
|
// document path (nor does it make sense to), we will pass it in
|
||||||
|
// ourselves, stripped of the file extension
|
||||||
|
String srcpkg = src.substring( 0, src.lastIndexOf( '.' ) );
|
||||||
|
|
||||||
|
// similarily, quickly resolve the relative root path
|
||||||
|
Integer dircount = srcpkg.replaceAll( "[^/]", "" ).length();
|
||||||
|
String relroot = new String( new char[ dircount ] ).replace( "\0", "../" );
|
||||||
|
|
||||||
|
Transformer t = _xsl.get( cmd );
|
||||||
|
t.setParameter( "__srcpkg", srcpkg );
|
||||||
|
t.setParameter( "__relroot", relroot );
|
||||||
|
t.setParameter( "__rseed", (int)( Math.random() * 10e6 ) );
|
||||||
|
|
||||||
|
_setTemplateParams( t, params );
|
||||||
|
|
||||||
|
t.transform( doc, dest );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void _setTemplateParams(
|
||||||
|
Transformer t,
|
||||||
|
HashMap<String,String> params
|
||||||
|
) throws Exception
|
||||||
|
{
|
||||||
|
for ( Map.Entry<String, String> param : params.entrySet() )
|
||||||
|
{
|
||||||
|
t.setParameter( param.getKey(), param.getValue() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Validator _createXsd()
|
||||||
|
{
|
||||||
|
final SchemaFactory factory = SchemaFactory.newInstance(
|
||||||
|
XMLConstants.W3C_XML_SCHEMA_NS_URI
|
||||||
|
);
|
||||||
|
|
||||||
|
// we must disable Unique Particle Attribution (UPC) checking; the
|
||||||
|
// validator used during development did not check for this and it
|
||||||
|
// currently does not pass this test (note that disabling this also
|
||||||
|
// improves the speed of the validator)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
factory.setFeature(
|
||||||
|
"http://apache.org/xml/features/validation/schema-full-checking",
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
System.err.println(
|
||||||
|
"fatal: cannot disable UPA checking; " +
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
|
||||||
|
System.exit( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final Schema schema =
|
||||||
|
factory.newSchema( new File( "rater/rater.xsd" ) );
|
||||||
|
|
||||||
|
return schema.newValidator();
|
||||||
|
}
|
||||||
|
catch ( SAXException e )
|
||||||
|
{
|
||||||
|
System.err.printf(
|
||||||
|
"fatal: %s\n",
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
|
||||||
|
System.exit( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Transformer _createXslt( String src )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final TransformerFactory factory = TransformerFactory.newInstance(
|
||||||
|
"net.sf.saxon.TransformerFactoryImpl", null
|
||||||
|
);
|
||||||
|
|
||||||
|
final Source xsl = new StreamSource( "rater/" + src + ".xsl" );
|
||||||
|
|
||||||
|
return factory.newTransformer( xsl );
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
System.err.printf(
|
||||||
|
"fatal: compilation failed; %s\n",
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
|
||||||
|
System.exit( 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void main( String[] args ) throws Exception
|
||||||
|
{
|
||||||
|
BufferedReader stdin = new BufferedReader(
|
||||||
|
new InputStreamReader( System.in )
|
||||||
|
);
|
||||||
|
|
||||||
|
String src = ( args.length > 0 ) ? args[0] : "";
|
||||||
|
|
||||||
|
_DslCompiler dslc = new _DslCompiler();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if ( src != "" )
|
||||||
|
{
|
||||||
|
compileSrc( dslc, src );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while ( ( src = stdin.readLine() ) != null )
|
||||||
|
{
|
||||||
|
compileSrc( dslc, src );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( IOException e )
|
||||||
|
{
|
||||||
|
System.err.println(
|
||||||
|
"fatal: I/O error while reading input files: " +
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
|
||||||
|
System.exit( 1 );
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
System.err.printf(
|
||||||
|
"fatal: `%s': %s\n",
|
||||||
|
src,
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
|
||||||
|
// generic exception..ruh roh
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void compileSrc( _DslCompiler dslc, String cmdline ) throws Exception
|
||||||
|
{
|
||||||
|
System.err.println( cmdline );
|
||||||
|
String[] args = cmdline.split( " " );
|
||||||
|
String dest = "";
|
||||||
|
|
||||||
|
if ( args.length < 2 )
|
||||||
|
{
|
||||||
|
System.err.printf( "fatal: invalid command: %s\n", cmdline );
|
||||||
|
System.exit( 3 );
|
||||||
|
}
|
||||||
|
else if ( args.length >= 3 )
|
||||||
|
{
|
||||||
|
dest = args[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
String cmd = args[0];
|
||||||
|
String src = args[1];
|
||||||
|
|
||||||
|
HashMap<String,String> params = _getXslParams( args );
|
||||||
|
|
||||||
|
Source doc = new StreamSource( src );
|
||||||
|
dslc.compile( doc, cmd, src, dest, params );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static HashMap<String,String> _getXslParams( String[] args )
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
HashMap<String,String> params = new HashMap<String,String>();
|
||||||
|
|
||||||
|
for ( int i = 3; i < args.length; i++ )
|
||||||
|
{
|
||||||
|
String[] keyval = args[ i ].split( "=" );
|
||||||
|
|
||||||
|
if ( keyval.length < 2 )
|
||||||
|
{
|
||||||
|
throw new Exception(
|
||||||
|
"Invalid template param assignment: " +
|
||||||
|
args[ i ]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
params.put( keyval[ 0 ], keyval[ 1 ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,226 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!--
|
||||||
|
Outputs the global classifier that can be used to determine classifications
|
||||||
|
across all eligible suppliers.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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:c="http://www.lovullo.com/calc"
|
||||||
|
xmlns:l="http://www.lovullo.com/rater/linker"
|
||||||
|
xmlns:compiler="http://www.lovullo.com/rater/compiler"
|
||||||
|
xmlns:calc-compiler="http://www.lovullo.com/calc/compiler"
|
||||||
|
xmlns:util="http://www.lovullo.com/util"
|
||||||
|
|
||||||
|
xmlns:ext="http://www.lovullo.com/ext"
|
||||||
|
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:output
|
||||||
|
indent="yes"
|
||||||
|
omit-xml-declaration="yes"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<xsl:include href="include/dslc-base.xsl" />
|
||||||
|
|
||||||
|
<!-- compiler -> JS -->
|
||||||
|
<xsl:include href="compiler/linker.xsl" />
|
||||||
|
<xsl:include href="compiler/map.xsl" />
|
||||||
|
<xsl:include href="include/depgen.xsl" />
|
||||||
|
|
||||||
|
<!-- path to program XML -->
|
||||||
|
<xsl:param name="path-program-ui" />
|
||||||
|
|
||||||
|
<xsl:template match="/" priority="5">
|
||||||
|
<!-- the rater itself -->
|
||||||
|
<xsl:text>var rater = </xsl:text>
|
||||||
|
<xsl:value-of disable-output-escaping="yes" select="/lv:package/l:exec/text()" />
|
||||||
|
<xsl:text>; </xsl:text>
|
||||||
|
|
||||||
|
<!-- maps may or may not exist -->
|
||||||
|
<xsl:variable name="map" select="/lv:package/l:map-exec" />
|
||||||
|
<xsl:variable name="retmap" select="/lv:package/l:retmap-exec" />
|
||||||
|
|
||||||
|
<!-- store a reference to the mapper in rater.fromMap() -->
|
||||||
|
<xsl:text>rater.fromMap = </xsl:text>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$map">
|
||||||
|
<xsl:value-of disable-output-escaping="yes" select="$map/text()" />
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- no map available -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<!-- simply invoke the conintuation with the provided data -->
|
||||||
|
<xsl:text>function(d,c){c(d);}</xsl:text>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
<xsl:text>; </xsl:text>
|
||||||
|
|
||||||
|
<!-- return map -->
|
||||||
|
<xsl:text>rater._retmap = </xsl:text>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$retmap">
|
||||||
|
<xsl:value-of disable-output-escaping="yes" select="$retmap/text()" />
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<!-- no map available -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<!-- simply invoke the conintuation with the provided data -->
|
||||||
|
<xsl:text>function(d,c){c(d);}</xsl:text>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
<xsl:text>; </xsl:text>
|
||||||
|
|
||||||
|
<!-- we'll export a version that automatically performs the mapping -->
|
||||||
|
<xsl:text>module.exports = function( args_base ) { </xsl:text>
|
||||||
|
<xsl:text>var ret; rater.fromMap( args_base, function( args ) {</xsl:text>
|
||||||
|
<xsl:text>
|
||||||
|
var rater_result = rater( args );
|
||||||
|
|
||||||
|
// perf counter
|
||||||
|
var start = ( new Date() ).getTime();
|
||||||
|
|
||||||
|
rater._retmap( rater_result.vars, function( result )
|
||||||
|
{
|
||||||
|
// add the final premium
|
||||||
|
result.premium = rater_result.premium;
|
||||||
|
result.__classes = rater_result.classes;
|
||||||
|
|
||||||
|
// process the rating worksheet
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result.__worksheet = process_worksheet(
|
||||||
|
rater.worksheet,
|
||||||
|
rater_result.vars,
|
||||||
|
rater_result.consts,
|
||||||
|
rater_result.debug,
|
||||||
|
rater_result.premium
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch ( e )
|
||||||
|
{
|
||||||
|
result.__worksheet = [ 'Failed: ' + e.message ];
|
||||||
|
}
|
||||||
|
ret = result;
|
||||||
|
} );
|
||||||
|
|
||||||
|
// add performance data
|
||||||
|
var end = ( new Date() ).getTime(),
|
||||||
|
time = ( ( new Date() ).getTime() - start );
|
||||||
|
|
||||||
|
ret.__perf = {
|
||||||
|
time: {
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
total: time
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</xsl:text>
|
||||||
|
<xsl:text>} );</xsl:text>
|
||||||
|
|
||||||
|
<xsl:text>return ret;</xsl:text>
|
||||||
|
<xsl:text>}; </xsl:text>
|
||||||
|
|
||||||
|
<xsl:text>
|
||||||
|
function process_worksheet( worksheet, vars, consts, debug, premium )
|
||||||
|
{
|
||||||
|
var ret = {};
|
||||||
|
|
||||||
|
for ( var name in worksheet )
|
||||||
|
{
|
||||||
|
var data = Array.prototype.slice.call( worksheet[ name ] ),
|
||||||
|
disp = data[0],
|
||||||
|
calc = data[1],
|
||||||
|
always = data[2];
|
||||||
|
|
||||||
|
ret[ name ] = [
|
||||||
|
disp,
|
||||||
|
process_wdisplay_set( [calc], vars, consts, debug ),
|
||||||
|
|
||||||
|
( ( name === 'yield' )
|
||||||
|
? premium
|
||||||
|
: ( vars[ name ] || consts[ name ] )
|
||||||
|
),
|
||||||
|
|
||||||
|
( always === 'true' )
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function process_wdisplay( data, vars, consts, debug )
|
||||||
|
{
|
||||||
|
if ( data === null )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = data[ 0 ],
|
||||||
|
desc = data[ 1 ],
|
||||||
|
sub = data[ 2 ],
|
||||||
|
val = data[ 3 ]; // may not exist
|
||||||
|
|
||||||
|
return [
|
||||||
|
name,
|
||||||
|
desc,
|
||||||
|
process_wdisplay_set( sub, vars, consts, debug ),
|
||||||
|
val || process_wval( name, desc, vars, consts, debug )
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function process_wval( type, desc, vars, consts, debug )
|
||||||
|
{
|
||||||
|
if ( desc.runtime )
|
||||||
|
{
|
||||||
|
type = 'runtime';
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( type )
|
||||||
|
{
|
||||||
|
case 'apply':
|
||||||
|
case 'cases':
|
||||||
|
case 'case':
|
||||||
|
case 'otherwise':
|
||||||
|
case 'runtime':
|
||||||
|
return ( debug[ desc._id ] );
|
||||||
|
|
||||||
|
case 'value-of':
|
||||||
|
return ( vars[ desc.name ] || consts[ desc.name ] );
|
||||||
|
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function process_wdisplay_set( sub, vars, consts, debug )
|
||||||
|
{
|
||||||
|
var ret = [],
|
||||||
|
i = sub.length;
|
||||||
|
|
||||||
|
while ( i-- )
|
||||||
|
{
|
||||||
|
if ( sub[ i ] === undefined )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[ i ] = process_wdisplay( sub[ i ], vars, consts, debug );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
</xsl:text>
|
||||||
|
|
||||||
|
<!-- expose the raw, unmapped rater -->
|
||||||
|
<xsl:text>module.exports.rater = rater;</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
|
@ -0,0 +1,835 @@
|
||||||
|
/**
|
||||||
|
* Rater XML summary stylesheet
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
/* menu width * menu em + 1 */
|
||||||
|
margin: 0em 0em 0em 13em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu
|
||||||
|
{
|
||||||
|
position: fixed;
|
||||||
|
overflow: scroll;
|
||||||
|
|
||||||
|
background-color: #ad7fa8;
|
||||||
|
border-right: 1px solid black;
|
||||||
|
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
width: 15em;
|
||||||
|
|
||||||
|
padding: 0.25em;
|
||||||
|
|
||||||
|
font-size: 0.8em;
|
||||||
|
|
||||||
|
resize: horizontal;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu h1
|
||||||
|
{
|
||||||
|
font-size: 1.4em;
|
||||||
|
margin-bottom: 0.15em;
|
||||||
|
border-bottom: 1px solid #75507b;
|
||||||
|
}
|
||||||
|
.menu h1:not(:first-child)
|
||||||
|
{
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu h2
|
||||||
|
{
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
margin-bottom: 0.15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu ul
|
||||||
|
{
|
||||||
|
margin: 0px;
|
||||||
|
padding-left: 1.25em;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset,
|
||||||
|
.container-param,
|
||||||
|
.tcontent
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
fieldset:target,
|
||||||
|
.container-param:target,
|
||||||
|
.tcontent:target
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset fieldset
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#xml-raw:not(.show)
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table > caption
|
||||||
|
{
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt
|
||||||
|
{
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt.param.classifies {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
dt.param > .type
|
||||||
|
{
|
||||||
|
font-size: 0.8em;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.params > .default
|
||||||
|
{
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table
|
||||||
|
{
|
||||||
|
border: 1px solid #888a87;
|
||||||
|
margin: 1em 0px 0px 0px;
|
||||||
|
}
|
||||||
|
table th
|
||||||
|
{
|
||||||
|
border-bottom: 2px solid #888a87;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
table tr > td
|
||||||
|
{
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
table tr:not(:last-child) > td
|
||||||
|
{
|
||||||
|
border-bottom: 1px solid #888a87;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset
|
||||||
|
{
|
||||||
|
border: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.class .requires,
|
||||||
|
.class .name,
|
||||||
|
.class .usedby,
|
||||||
|
.typedef .type,
|
||||||
|
.typedef .name,
|
||||||
|
.params .usedby,
|
||||||
|
.rate .yields,
|
||||||
|
.rate .param,
|
||||||
|
.func .param,
|
||||||
|
.func .usedby
|
||||||
|
{
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.usedby a
|
||||||
|
{
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calc-order,
|
||||||
|
.classifier-calcs
|
||||||
|
{
|
||||||
|
max-height: 20em;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workstatus
|
||||||
|
{
|
||||||
|
position: fixed;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
background-color: #eeeeec;
|
||||||
|
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
right: auto;
|
||||||
|
padding: 0.25em;
|
||||||
|
|
||||||
|
font-size: 0.9em;
|
||||||
|
border-bottom: 1px solid #babdb6;
|
||||||
|
border-right: 1px solid #babdb6;
|
||||||
|
|
||||||
|
/* entry-form is 2000 */
|
||||||
|
z-index: 1999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workstatus.show
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package
|
||||||
|
{
|
||||||
|
background-color: #eeeeec;
|
||||||
|
|
||||||
|
border: 1px solid #babdb6;
|
||||||
|
border-radius: 1em;
|
||||||
|
|
||||||
|
padding: 1em;
|
||||||
|
|
||||||
|
margin-bottom: 3em;
|
||||||
|
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.package.devsummary
|
||||||
|
{
|
||||||
|
background-color: #ad7fa8;
|
||||||
|
border-color: #75507b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package > .title
|
||||||
|
{
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
background-color: #d3d7cf;
|
||||||
|
|
||||||
|
border-bottom: 1px solid #babdb6;
|
||||||
|
border-radius: 1em 1em 0px 0px;
|
||||||
|
|
||||||
|
margin: -1em -1em 0px -1em;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
.package > .title > h2
|
||||||
|
{
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package > h3,
|
||||||
|
.package > div > h3
|
||||||
|
{
|
||||||
|
border-width: 0px 0px 2px 0px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #babdb6;
|
||||||
|
|
||||||
|
margin: 1em -0.9em;
|
||||||
|
padding: 0.1em 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package.us > .title,
|
||||||
|
.package.devsummary > .title
|
||||||
|
{
|
||||||
|
background-color: #ad7fa8;
|
||||||
|
}
|
||||||
|
.package.devsummary > .title,
|
||||||
|
.package.devsummary > h3,
|
||||||
|
.package.devsummary > div > h3
|
||||||
|
{
|
||||||
|
border-bottom-color: #75507b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package h4.rate-group
|
||||||
|
{
|
||||||
|
border-bottom: 1px dashed #babdb6;
|
||||||
|
margin-top: 3em;
|
||||||
|
margin-left: -0.5em;
|
||||||
|
}
|
||||||
|
.rate-groups .generates
|
||||||
|
{
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package > .title > .imports
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
|
||||||
|
margin: 1.25em;
|
||||||
|
}
|
||||||
|
.package > .title > .imports::before
|
||||||
|
{
|
||||||
|
content: 'Imports: ';
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > fieldset
|
||||||
|
{
|
||||||
|
position: relative;
|
||||||
|
padding: 5em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > fieldset > legend
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
background-color: #eeeeec;
|
||||||
|
|
||||||
|
border-top: 1px solid #babdb6;
|
||||||
|
border-bottom: 1px solid #babdb6;
|
||||||
|
|
||||||
|
padding: 0.5em;
|
||||||
|
left: -0.5em;
|
||||||
|
top: 0em;
|
||||||
|
right: 0px;
|
||||||
|
|
||||||
|
font-size: 1.5em;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > fieldset > legend > a.pkg
|
||||||
|
{
|
||||||
|
float: right;
|
||||||
|
font-size: 0.5em;
|
||||||
|
line-height: 2.5em;
|
||||||
|
|
||||||
|
color: inherit;
|
||||||
|
border: none;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > fieldset > legend + p.desc
|
||||||
|
{
|
||||||
|
margin-top: 0em;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset.rate > legend > a
|
||||||
|
{
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px dotted black;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset.rate .classes
|
||||||
|
{
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
margin: -1em 0em 2em 0em;
|
||||||
|
padding-bottom: 0.25em;
|
||||||
|
|
||||||
|
font-size: 0.9em;
|
||||||
|
border-bottom: 1px dotted black;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset.rate .classes > .prefix
|
||||||
|
{
|
||||||
|
font-variant: small-caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* more than just .rate */
|
||||||
|
fieldset .calc-yields
|
||||||
|
{
|
||||||
|
font-variant: small-caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ul.let
|
||||||
|
{
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.let li.letequ
|
||||||
|
{
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.let .letdesc
|
||||||
|
{
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.rate .body,
|
||||||
|
.func .body,
|
||||||
|
.yield .body
|
||||||
|
{
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.rate .right,
|
||||||
|
.func .right,
|
||||||
|
.yield .right
|
||||||
|
{
|
||||||
|
float: right;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
max-width: 40%;
|
||||||
|
}
|
||||||
|
.rate .body
|
||||||
|
{
|
||||||
|
/** give room for accumulators, depends, etc **/
|
||||||
|
margin-bottom: 5em;
|
||||||
|
}
|
||||||
|
.right h4
|
||||||
|
{
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
|
||||||
|
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
.right > div:not(:first-child)
|
||||||
|
{
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
.right > .parts.many
|
||||||
|
{
|
||||||
|
-webkit-columns: 2;
|
||||||
|
-moz-columns: 2;
|
||||||
|
}
|
||||||
|
.right > .parts > .part,
|
||||||
|
.right > .generators > .generator
|
||||||
|
{
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
.right > .parts > .part:first-child
|
||||||
|
{
|
||||||
|
margin-top: 0em;
|
||||||
|
}
|
||||||
|
.right > .parts.many > .part
|
||||||
|
{
|
||||||
|
/** FF, Webkit and W3C respectively */
|
||||||
|
display: table;
|
||||||
|
-webkit-column-break-inside: avoid;
|
||||||
|
break-inside: avoid-column;
|
||||||
|
}
|
||||||
|
.right > .parts > .part > .label,
|
||||||
|
.right > .generators > .generator > .desc
|
||||||
|
{
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.accum
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
bottom: 1em;
|
||||||
|
|
||||||
|
font-size: 0.9em;
|
||||||
|
|
||||||
|
max-width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error
|
||||||
|
{
|
||||||
|
font-weight: bold;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** entry form **/
|
||||||
|
#test-data
|
||||||
|
{
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
#test-data:not(:target)
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.entry-form
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
form.entry-form.focus
|
||||||
|
}
|
||||||
|
|
||||||
|
form.entry-form > dl
|
||||||
|
}
|
||||||
|
|
||||||
|
form.entry-form.focus > dl
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
form.entry-form dt
|
||||||
|
{
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.entry-form .matrix
|
||||||
|
{
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px inset;
|
||||||
|
padding: 0.25em;
|
||||||
|
|
||||||
|
float: left;
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.entry-form .entry-add
|
||||||
|
{
|
||||||
|
float: left;
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.entry-form > .foot
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
form.entry-form > .foot > .ratemsg
|
||||||
|
{
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.entry-form .final-accept:not(.show),
|
||||||
|
form.entry-form .final-premium:not(.show)
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.entry-form .final-premium
|
||||||
|
{
|
||||||
|
margin: 0.25em;
|
||||||
|
|
||||||
|
font-size: 3em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: green;
|
||||||
|
|
||||||
|
text-shadow: 1px 1px 1px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.entry-form .final-premium:before
|
||||||
|
{
|
||||||
|
content: '$';
|
||||||
|
|
||||||
|
min-height: 0em;
|
||||||
|
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.entry-form input[type="reset"]
|
||||||
|
{
|
||||||
|
/* help protect against accidental clicks */
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
form .final-comments
|
||||||
|
{
|
||||||
|
background-color: rgba( 255, 255, 255, 0.90 );
|
||||||
|
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
form .final-comments.show
|
||||||
|
{
|
||||||
|
position: fixed;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
border: 0.25em solid black;
|
||||||
|
|
||||||
|
top: 0.25em;
|
||||||
|
right: 0.25em;
|
||||||
|
bottom: 0.25em;
|
||||||
|
left: 12.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
form .final-comments textarea
|
||||||
|
{
|
||||||
|
width: 95%;
|
||||||
|
height: 20em;
|
||||||
|
}
|
||||||
|
|
||||||
|
form .final-comments button
|
||||||
|
{
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
form .final-comments #final-submit
|
||||||
|
{
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** load dialog **/
|
||||||
|
#prior:not(:target)
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-dialog td
|
||||||
|
{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-dialog > button
|
||||||
|
{
|
||||||
|
margin-top: 0.5em;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-dialog tr > td:first-child,
|
||||||
|
.load-dialog tr > td.premium
|
||||||
|
{
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-dialog tr > td.premium,
|
||||||
|
.load-dialog tr > td.expected
|
||||||
|
{
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-dialog tr.good
|
||||||
|
{
|
||||||
|
background-color: #c0ffc0;
|
||||||
|
}
|
||||||
|
.load-dialog tr.bad
|
||||||
|
{
|
||||||
|
background-color: #ffc0c0;
|
||||||
|
}
|
||||||
|
.load-dialog tr.good.waiting
|
||||||
|
{
|
||||||
|
background-color: #edd400;
|
||||||
|
}
|
||||||
|
.load-dialog tr.bad.waiting
|
||||||
|
{
|
||||||
|
background-color: #f57900;
|
||||||
|
}
|
||||||
|
.load-dialog tr.changed:not(.skipped)
|
||||||
|
{
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal !important;
|
||||||
|
}
|
||||||
|
.load-dialog tr.premchanged
|
||||||
|
{
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.load-dialog tr.skipped
|
||||||
|
{
|
||||||
|
background-color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.load-dialog.show
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.entry-value,
|
||||||
|
.entry-value-prior
|
||||||
|
{
|
||||||
|
background-color: yellow;
|
||||||
|
|
||||||
|
padding: 0.1em;
|
||||||
|
margin-left: 1em;
|
||||||
|
|
||||||
|
font-weight: bold;
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
.entry-value-prior
|
||||||
|
{
|
||||||
|
background-color: purple;
|
||||||
|
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
body:not(.prior) .entry-value-prior
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** validation errors **/
|
||||||
|
.validation-errors
|
||||||
|
{
|
||||||
|
position: fixed;
|
||||||
|
background-color: #FFAFAF;
|
||||||
|
|
||||||
|
border: 0.5em solid rgba( 255, 0, 0, 0.75 );
|
||||||
|
border-bottom: none;
|
||||||
|
|
||||||
|
bottom: -30.5em;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
|
||||||
|
padding: 0px 0px 0px 0.5em;
|
||||||
|
|
||||||
|
z-index: 9000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.validation-errors:hover
|
||||||
|
{
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.validation-errors ol
|
||||||
|
{
|
||||||
|
height: 30em;
|
||||||
|
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.validation-errors li > .content
|
||||||
|
{
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nb
|
||||||
|
{
|
||||||
|
border-top: 1px solid #babdb6;
|
||||||
|
padding-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.ultra-breakdown
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
font-size: 0.9em;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ultra-breakdown > h2
|
||||||
|
{
|
||||||
|
margin-top: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ultra-breakdown + .yields
|
||||||
|
{
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ultra-breakdown legend > .uid
|
||||||
|
{
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ultra-breakdown fieldset
|
||||||
|
{
|
||||||
|
margin-top: 1em;
|
||||||
|
|
||||||
|
border: 1px solid #babdb6;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ultra-breakdown fieldset:hover
|
||||||
|
{
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.test-summary
|
||||||
|
{
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.test-summary table
|
||||||
|
{
|
||||||
|
float: right;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
#voi-container,
|
||||||
|
#class-overview
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
margin: 0em 0.5em 2em 0em;
|
||||||
|
}
|
||||||
|
#class-overview td.prior
|
||||||
|
{
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: purple;
|
||||||
|
}
|
||||||
|
body:not(.prior) #class-overview td.prior
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#voi-container.show,
|
||||||
|
#class-overview.show
|
||||||
|
{
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#voi-container td.prior
|
||||||
|
{
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: purple;
|
||||||
|
}
|
||||||
|
body:not(.prior) #voi-container td.prior
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sel0
|
||||||
|
{
|
||||||
|
background-color: #ccccff;
|
||||||
|
}
|
||||||
|
.sel1
|
||||||
|
{
|
||||||
|
background-color: #ccffcc;
|
||||||
|
}
|
||||||
|
.sel2
|
||||||
|
{
|
||||||
|
background-color: #ffcccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#voi-painter
|
||||||
|
{
|
||||||
|
position: fixed;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
background-color: white;
|
||||||
|
border: 3px solid #eeeeec;
|
||||||
|
border-radius: 0.25em;
|
||||||
|
|
||||||
|
top: -3px;
|
||||||
|
left: 30em;
|
||||||
|
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.3em;
|
||||||
|
|
||||||
|
padding: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#prior-message
|
||||||
|
{
|
||||||
|
background-color: #c0ffc0;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
border: 0.25em solid #4e9a06;
|
||||||
|
width: 50%;
|
||||||
|
|
||||||
|
font-family: monospace;
|
||||||
|
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#prior-message.bad
|
||||||
|
{
|
||||||
|
background-color: #ffc0c0;
|
||||||
|
border-color: #c00000;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,110 @@
|
||||||
|
#!/usr/bin/awk -f
|
||||||
|
#
|
||||||
|
# Compiles the given CSV into a table definition
|
||||||
|
|
||||||
|
|
||||||
|
function columngen( header )
|
||||||
|
{
|
||||||
|
# output a field constant for each field in the header
|
||||||
|
i = 0
|
||||||
|
while ( field = header[ ++i ] )
|
||||||
|
{
|
||||||
|
printf " <t:table-column name=\"%s\" " \
|
||||||
|
"index=\"%d\" seq=\"%s\" />\n",
|
||||||
|
field,
|
||||||
|
( i - 1 ),
|
||||||
|
( seq[ i ] ) ? "true" : "false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function seqchk( last )
|
||||||
|
{
|
||||||
|
# if there's no last row, then do not bother
|
||||||
|
i = 0
|
||||||
|
while ( i++ < NF )
|
||||||
|
{
|
||||||
|
if ( seq[ i ] == "" ) seq[ i ] = 1
|
||||||
|
|
||||||
|
# this field is sequential if it is greater than or equal to the last field
|
||||||
|
# (we don't check for descending [yet]); note that on the first check, last
|
||||||
|
# will be empty and therefore this check will succeed (properly
|
||||||
|
# initializing seq[i] to 1)
|
||||||
|
seq[ i ] = seq[ i ] && ( $(i) >= last[ i ] )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# header
|
||||||
|
BEGIN {
|
||||||
|
rootpath = "../../../"
|
||||||
|
file = ARGV[1]
|
||||||
|
|
||||||
|
# grab only the filename (remove all preceding directories and the file ext)
|
||||||
|
name = gensub( /^.*\/|\.[^.]+$/, "", "g", file )
|
||||||
|
|
||||||
|
|
||||||
|
# output package header
|
||||||
|
printf \
|
||||||
|
"<?xml-stylesheet type=\"text/xsl\" href=\"%1$srater/summary.xsl\"?>\n" \
|
||||||
|
"<package\n" \
|
||||||
|
" xmlns=\"http://www.lovullo.com/rater\"\n" \
|
||||||
|
" xmlns:c=\"http://www.lovullo.com/calc\"\n" \
|
||||||
|
" xmlns:t=\"http://www.lovullo.com/rater/apply-template\"\n" \
|
||||||
|
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" \
|
||||||
|
" xsi:schemaLocation=\"http://www.lovullo.com/rater %1$srater/rater.xsd\"\n\n" \
|
||||||
|
" name=\"suppliers/rates/tables/%2$s\"\n" \
|
||||||
|
" desc=\"%2$s rate table\">\n\n" \
|
||||||
|
" <!--\n" \
|
||||||
|
" WARNING: This file was generated by csv2xml; do not modify!\n" \
|
||||||
|
" -->\n\n" \
|
||||||
|
" <import package=\"/rater/core\" />\n" \
|
||||||
|
" <import package=\"/rater/core/vector/table\" />\n\n", \
|
||||||
|
rootpath, name
|
||||||
|
|
||||||
|
# the first row of the CSV is the header representing the column identifiers
|
||||||
|
getline
|
||||||
|
split( $0, header, /,/ )
|
||||||
|
|
||||||
|
# table constant identifier
|
||||||
|
tconst = toupper( gensub( /-/, "_", "g", name ) ) "_RATE_TABLE"
|
||||||
|
|
||||||
|
# generate the header for the table constant
|
||||||
|
printf " <t:create-table name=\"%s\">\n", name
|
||||||
|
|
||||||
|
printf "%s", " <t:table-rows data=\"\n"
|
||||||
|
|
||||||
|
# delimit fields by commas (the field separator for CSVs); note that this
|
||||||
|
# won't work properly if strings contain commas
|
||||||
|
FS = ","
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# each row of the CSV
|
||||||
|
{
|
||||||
|
# generate value string for each field
|
||||||
|
i = 0
|
||||||
|
while ( i++ < NF )
|
||||||
|
{
|
||||||
|
printf "%s", ( ( i > 1 ) ? "," : "" ) $(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
print ";"
|
||||||
|
|
||||||
|
seqchk( last )
|
||||||
|
split( $0, last )
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# footer
|
||||||
|
END {
|
||||||
|
# end of table-rows node
|
||||||
|
print "\" />"
|
||||||
|
|
||||||
|
# columns can't be generated until after we know which ones represent
|
||||||
|
# sequential data
|
||||||
|
columngen( header )
|
||||||
|
|
||||||
|
print " </t:create-table>"
|
||||||
|
print "</package>"
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
#!/usr/bin/awk -f
|
||||||
|
#
|
||||||
|
# Performs interpolation for columns in a CSV and outputs the result
|
||||||
|
#
|
||||||
|
# Configurable values (use -vname=value from command line):
|
||||||
|
# step - use predeterminated step instead of calculating from first two rows
|
||||||
|
#
|
||||||
|
# #
|
||||||
|
|
||||||
|
function storeline()
|
||||||
|
{
|
||||||
|
for ( i = 1; i <= hlen; i++ ) {
|
||||||
|
prev[i] = $i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearline()
|
||||||
|
{
|
||||||
|
for ( i = 1; i <= hlen; i++ ) {
|
||||||
|
prev[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getprev()
|
||||||
|
{
|
||||||
|
for ( i = 1; i <= hlen; i++ ) {
|
||||||
|
$i = prev[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function interpolate()
|
||||||
|
{
|
||||||
|
lastval = prev[1]
|
||||||
|
|
||||||
|
curval = $1
|
||||||
|
diff = curval - lastval
|
||||||
|
|
||||||
|
# does this value fall in line with the requested step?
|
||||||
|
if ( diff == step )
|
||||||
|
{
|
||||||
|
storeline()
|
||||||
|
|
||||||
|
# we're good; continue
|
||||||
|
print
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
# if we do not yet have a value large enough to reach our step, then continue
|
||||||
|
# until we do (do not store this line)
|
||||||
|
n = int( diff / step )
|
||||||
|
if ( n <= 0 ) {
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
# determine interpolation values
|
||||||
|
for ( i = 2; i <= hlen; i++ ) {
|
||||||
|
ival[i] = ( ( $i - prev[i] ) / n )
|
||||||
|
}
|
||||||
|
|
||||||
|
getprev()
|
||||||
|
|
||||||
|
# let us interpolate values that are divisible by the step
|
||||||
|
do
|
||||||
|
{
|
||||||
|
# increase the last value by our step
|
||||||
|
$1 += step
|
||||||
|
|
||||||
|
# interpolate each column value (notice that we skip the first column, which
|
||||||
|
# was handled directly above)
|
||||||
|
for ( i = 2; i <= hlen; i++ ) {
|
||||||
|
$i += ival[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
# print the new line
|
||||||
|
print
|
||||||
|
} while ( ( diff -= step ) > 0 )
|
||||||
|
|
||||||
|
# anything remaining does not fit into our step and will be ignored; we'll
|
||||||
|
# continue with our next step at the next line
|
||||||
|
|
||||||
|
# consider this to be our last line
|
||||||
|
storeline()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
# the first row of the CSV is the header representing the column identifiers
|
||||||
|
getline
|
||||||
|
hlen = split( $0, header, /,/ )
|
||||||
|
|
||||||
|
# output the header
|
||||||
|
print $0
|
||||||
|
|
||||||
|
# delimit fields by commas (the field separator for CSVs); note that this
|
||||||
|
# won't work properly if strings contain commas
|
||||||
|
FS = OFS = ","
|
||||||
|
|
||||||
|
clearline()
|
||||||
|
getline
|
||||||
|
|
||||||
|
# if no step was provided, then calculate one based on the first two rows
|
||||||
|
if ( step == 0 ) {
|
||||||
|
# output the first row, which does not need to be interpolated
|
||||||
|
print
|
||||||
|
|
||||||
|
# compute the step
|
||||||
|
vala = $1
|
||||||
|
getline
|
||||||
|
valb = $1
|
||||||
|
step = valb - vala
|
||||||
|
|
||||||
|
# since the second line is used to determine the step, then it must match the
|
||||||
|
# step and therefore is good to output
|
||||||
|
print
|
||||||
|
|
||||||
|
# begin.
|
||||||
|
storeline()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# for each row
|
||||||
|
{ interpolate() }
|
|
@ -0,0 +1,112 @@
|
||||||
|
#!/usr/bin/awk -f
|
||||||
|
#
|
||||||
|
# Compiles a "magic" CSV file into a normal CSV
|
||||||
|
#
|
||||||
|
# "Magic" CSVs simply exist to make life easier: they permit comments, blank
|
||||||
|
# lines, variables, sub-delimiter expansion, and any number of ranges per line.
|
||||||
|
# Ranges will be expanded in every combination, making rate tables highly
|
||||||
|
# maintainable.
|
||||||
|
#
|
||||||
|
# Variables are also supported when defined using :var=val. Variables may expand
|
||||||
|
# into ranges, 'cause they're awesome. Multiple variables may be delimited by
|
||||||
|
# semi-colons, as may multiple values.
|
||||||
|
#
|
||||||
|
# For example:
|
||||||
|
# :foo=1--3
|
||||||
|
# $foo;7;9--10:$foo, 5--10
|
||||||
|
#
|
||||||
|
# Would generate:
|
||||||
|
# 1, 5
|
||||||
|
# 1, 6
|
||||||
|
# ...
|
||||||
|
# 5, 10
|
||||||
|
# 2, 5
|
||||||
|
# ...
|
||||||
|
# 9, 5
|
||||||
|
# ...
|
||||||
|
# 1, 5
|
||||||
|
# 1, 6
|
||||||
|
# ...
|
||||||
|
|
||||||
|
|
||||||
|
function rangeout( i, m, j, me, orig )
|
||||||
|
{
|
||||||
|
if ( i > NF )
|
||||||
|
{
|
||||||
|
print
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
orig = $i
|
||||||
|
|
||||||
|
# check first for delimiters
|
||||||
|
if ( match( $i, /^([^;]+);(.*)$/, m ) )
|
||||||
|
{
|
||||||
|
# give it a shot with the first value
|
||||||
|
$i = m[1]
|
||||||
|
rangeout( i )
|
||||||
|
|
||||||
|
# strip off the first value and process with following value(s)
|
||||||
|
$i = m[2]
|
||||||
|
rangeout( i )
|
||||||
|
|
||||||
|
# we've delegated; we're done
|
||||||
|
$i = orig
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# attempt to parse variable (may expand into a range)
|
||||||
|
if ( match( $i, /^\$([a-zA-Z_-]+)$/, m ) )
|
||||||
|
{
|
||||||
|
$i = vars[ m[1] ];
|
||||||
|
}
|
||||||
|
|
||||||
|
# parse range
|
||||||
|
if ( match( $i, /^([0-9]+)--([0-9]+)$/, m ) )
|
||||||
|
{
|
||||||
|
j = m[1]
|
||||||
|
me = m[2]
|
||||||
|
do
|
||||||
|
{
|
||||||
|
$i = j
|
||||||
|
rangeout( i + 1 )
|
||||||
|
} while ( j++ < me )
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rangeout( i + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
# restore to original value
|
||||||
|
$i = orig
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
# we're parsing CSVs
|
||||||
|
FS = " *, *"
|
||||||
|
OFS = ","
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# skip all lines that begin with `#', which denotes a comment, or are empty
|
||||||
|
/^#|^$/ { next; }
|
||||||
|
|
||||||
|
# lines that begin with a colon are variable definitions
|
||||||
|
/^:/ {
|
||||||
|
match( $0, /^:([a-zA-Z_-]+)=(.*?)$/, m )
|
||||||
|
vars[ m[1] ] = m[2]
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
# lines containing ranges (denoted by `--', the en dash, which is a typesetting
|
||||||
|
# convetion for ranges), sub-delimiters, or variables must be expanded
|
||||||
|
/--|;|\$[a-zA-Z_-]/ { rangeout( 1 ); next; }
|
||||||
|
|
||||||
|
# all other lines are normal; simply output them verbatim
|
||||||
|
{
|
||||||
|
# this assignment will ensure that awk processes the output, ensuring that
|
||||||
|
# extra spaces between commas are stripped
|
||||||
|
$1=$1
|
||||||
|
print
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Generates Makefile containing dependencies for each package
|
||||||
|
# #
|
||||||
|
|
||||||
|
# windows machines may not have the tools to resolve a path, so let's do so
|
||||||
|
# ourselves (TODO: there's better (and more performant) ways of doing this than
|
||||||
|
# repeated string replacements); TODO: ./
|
||||||
|
resolv-path()
|
||||||
|
{
|
||||||
|
# no need to do anything if the string does not contain a parent dir reference
|
||||||
|
# (we use this convoluted string replacement check for woe32/64 to prevent
|
||||||
|
# additional spawns (e.g. sed) that would slow us down and because =~ is not
|
||||||
|
# properly supported in msys
|
||||||
|
[[ "$1" != "${1/..\//}"a ]] || {
|
||||||
|
echo "$1"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
local path=
|
||||||
|
while read name; do
|
||||||
|
if [ "$name" == .. ]; then
|
||||||
|
[ -n "$path" ] || {
|
||||||
|
echo "warning: will not resolve $1" >&2
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
|
||||||
|
path="${path%/*}"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
path="$path/$name"
|
||||||
|
done <<< "${1//\//$'\n'}"
|
||||||
|
|
||||||
|
# echo path without leading /
|
||||||
|
echo -n "${path:1}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# rule for building
|
||||||
|
[ -z "$GEN_MAKE" ] && {
|
||||||
|
echo "%.xmlo:: %.tmp"
|
||||||
|
echo -e "\t@rm -f \$@ \$<"
|
||||||
|
[ -n "$xmlo_cmd" ] \
|
||||||
|
&& echo -e "\t$xmlo_cmd" \
|
||||||
|
|| echo -e "\ttouch \$@"
|
||||||
|
|
||||||
|
echo "%.xmlo:: %.xml | prexmlo"
|
||||||
|
[ -n "$xmlo_cmd" ] \
|
||||||
|
&& echo -e "\t$xmlo_cmd" \
|
||||||
|
|| echo -e "\ttouch \$@"
|
||||||
|
|
||||||
|
export GEN_MAKE="$( pwd )/$0"
|
||||||
|
exec "$GEN_MAKE" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
until [ $# -eq 0 ]; do (
|
||||||
|
path="${1%%/}"
|
||||||
|
echo "[gen-make] scanning $path" >&2
|
||||||
|
|
||||||
|
cd "$( basename $path )/" || exit $?
|
||||||
|
|
||||||
|
deps=$( find -maxdepth 1 -iname '*.dep' )
|
||||||
|
for dpath in $deps; do
|
||||||
|
# equivalent to basename command; use this since spawning processes on
|
||||||
|
# windoze is slow as shit (originally we did find -exec bashename)
|
||||||
|
d="${dpath##*/}"
|
||||||
|
|
||||||
|
echo "[gen-make] found $path/$d" >&2
|
||||||
|
echo -n "$path/${d%.*}.xmlo:"
|
||||||
|
|
||||||
|
# output deps
|
||||||
|
while read dep; do
|
||||||
|
# if the first character is a slash, then it's relative to the project
|
||||||
|
# root---the resolution has already been done for us!
|
||||||
|
if [ "${dep:0:1}" == '/' ]; then
|
||||||
|
echo -n " ${dep:1}.xmlo"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n ' '
|
||||||
|
resolv-path "$path/$dep.xmlo"
|
||||||
|
done < "$d"
|
||||||
|
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
|
||||||
|
# recurse on every subdirectory
|
||||||
|
for p in */; do
|
||||||
|
[ "$p" == ./ -o "$p" == ../ ] && continue
|
||||||
|
[ ! -d "$p" ] || "$GEN_MAKE" "$path/$p" || {
|
||||||
|
echo "fatal: failed to recurse on $( pwd )/$path/$p" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
); shift; done
|
|
@ -0,0 +1,124 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
function gen_re_quick( $data )
|
||||||
|
{
|
||||||
|
$re = ( '^' . gen_re( $data, 0 ) );
|
||||||
|
|
||||||
|
// attempt to simplify the regex (we're not going to put a lot of effort into
|
||||||
|
// this)
|
||||||
|
return re_simplify( $re );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function gen_re( $data, $offset )
|
||||||
|
{
|
||||||
|
// if we've reached the end of the zip length, or if there's no more zips to
|
||||||
|
// look at, then stop
|
||||||
|
if ( ( count( $data ) === 0 )
|
||||||
|
|| ( $offset === 5 )
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = '(';
|
||||||
|
|
||||||
|
// loop through each digit at the current offset
|
||||||
|
$last = '';
|
||||||
|
foreach ( $data as $zip )
|
||||||
|
{
|
||||||
|
if ( !( isset( $zip[ $offset ] ) ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$digit = $zip[ $offset ];
|
||||||
|
|
||||||
|
// if we've already seen this digit in the current position, then
|
||||||
|
// continue
|
||||||
|
if ( $digit === $last )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're going to recurse now, delimiting allowable digits with pipes
|
||||||
|
// (for 'OR'); we'll recurse on a sublist that matches the zip up to
|
||||||
|
// (and including) the current digit (to do this, note that we only need
|
||||||
|
// to check the current digit, since our current list is already a
|
||||||
|
// sublist of the parent list up to the current point)
|
||||||
|
$prefix = substr( $zip, 0, $offset + 1 );
|
||||||
|
|
||||||
|
$out .= ( $last === '' ) ? '' : '|';
|
||||||
|
$out .= $digit . gen_re(
|
||||||
|
filter_data( $data, $digit, $offset ),
|
||||||
|
( $offset + 1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
$last = $digit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter_data( $data, $chr, $offset )
|
||||||
|
{
|
||||||
|
$ret = array();
|
||||||
|
|
||||||
|
foreach ( $data as $val )
|
||||||
|
{
|
||||||
|
if ( $val[ $offset] === $chr )
|
||||||
|
{
|
||||||
|
$ret[] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function re_simplify( $re )
|
||||||
|
{
|
||||||
|
// the only simplification we currently do is joining sequential digit ORs
|
||||||
|
// into a character range (e.g. (1|2|3|4) becomes [1-4])
|
||||||
|
return preg_replace_callback( '/\([0-9](\|[0-9])*\)/', function( $results )
|
||||||
|
{
|
||||||
|
$match = $results[ 0 ];
|
||||||
|
$digits = explode( '|', str_replace( array( '(', ')' ), '', $match ) );
|
||||||
|
|
||||||
|
// are the digits sequential (we will only perform this optimization if
|
||||||
|
// there's more than 3 digits, since otherwise the replacement would
|
||||||
|
// result in a string of equal or greater length)?
|
||||||
|
if ( ( count( $digits ) > 3 ) && is_seq( $digits ) )
|
||||||
|
{
|
||||||
|
return sprintf( '[%d-%d]',
|
||||||
|
$digits[ 0 ],
|
||||||
|
$digits[ count( $digits ) - 1 ]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
elseif ( count( $digits ) === 1 )
|
||||||
|
{
|
||||||
|
// if there's only one digit, then that's all we need to return
|
||||||
|
return $digits[ 0 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return '[' . implode( '', $digits ) . ']';
|
||||||
|
}, $re );
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_seq( $digits, $last = '' )
|
||||||
|
{
|
||||||
|
// stop recursing once we're out of digits
|
||||||
|
if ( count( $digits ) === 0 )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// grab the current digit and remove it from the list (this has the effect
|
||||||
|
// of both cons and cdr)
|
||||||
|
$digit = (int)( array_shift( $digits ) );
|
||||||
|
|
||||||
|
// consider this a sequence if this digit is one more than the last (or if
|
||||||
|
// there is no last digit) and if the following digit is sequential
|
||||||
|
return ( ( $last === '' ) || ( $digit === ( $last + 1) ) )
|
||||||
|
&& is_seq( $digits, $digit );
|
||||||
|
}
|
|
@ -0,0 +1,274 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?xml-stylesheet type="text/xsl" href="../../rater/summary.xsl"?>
|
||||||
|
<lv:package
|
||||||
|
xmlns:lv="http://www.lovullo.com/rater"
|
||||||
|
xmlns:c="http://www.lovullo.com/calc"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.lovullo.com/rater ../../rater/rater.xsd"
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
include 'lib/zipre.php';
|
||||||
|
|
||||||
|
function parse_tdesc( $line )
|
||||||
|
{
|
||||||
|
if ( !( preg_match( '/^([0-9A-Z]+) (.+)$/', $line, $match ) ) )
|
||||||
|
{
|
||||||
|
throw new Exception( 'Invalid territory descriptor' );
|
||||||
|
}
|
||||||
|
|
||||||
|
return array( $match[ 1 ], $match[ 2 ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
function gen_yields( $id, $name )
|
||||||
|
{
|
||||||
|
return sprintf( 'is%sTerr%s', ucfirst( $name ), $id );
|
||||||
|
}
|
||||||
|
|
||||||
|
function gen_classification( $id, $name, $desc, $prev_yields, $queue, $or )
|
||||||
|
{
|
||||||
|
$yields = gen_yields( $id, $name );
|
||||||
|
|
||||||
|
$prev_value = '';
|
||||||
|
foreach ( $prev_yields as $prev )
|
||||||
|
{
|
||||||
|
if ( !$prev )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$prev_value .= ' <lv:match on="' . $prev . '" value="FALSE" />' . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(
|
||||||
|
'<lv:classify as="%s-terr%s" desc="%s" yields="%s">' .
|
||||||
|
"\n%s" .
|
||||||
|
" %s\n" .
|
||||||
|
"\n</lv:classify>\n",
|
||||||
|
$name,
|
||||||
|
gen_identifier( $id ),
|
||||||
|
$desc,
|
||||||
|
$yields,
|
||||||
|
$prev_value,
|
||||||
|
gen_any_block( $queue, $or )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function gen_any_block( $queue, $or )
|
||||||
|
{
|
||||||
|
$any = gen_zip_re( $queue ) .
|
||||||
|
gen_on_class( $or );
|
||||||
|
|
||||||
|
return ( $any )
|
||||||
|
? '<lv:any>' . $any . '</lv:any>'
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function gen_zip_re( $data )
|
||||||
|
{
|
||||||
|
if ( count( $data ) === 0 )
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(
|
||||||
|
'<lv:match on="zip" pattern="%s" />',
|
||||||
|
gen_re_quick( $data )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function gen_on_class( $data )
|
||||||
|
{
|
||||||
|
if ( count( $data ) === 0 )
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$cur = array_shift( $data );
|
||||||
|
|
||||||
|
return sprintf(
|
||||||
|
'<lv:match on="%s" value="TRUE" />%s',
|
||||||
|
$cur,
|
||||||
|
gen_on_class( $data )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function gen_identifier( $id )
|
||||||
|
{
|
||||||
|
return is_numeric( $id )
|
||||||
|
? $id
|
||||||
|
: '-' . strtolower( $id );
|
||||||
|
}
|
||||||
|
|
||||||
|
function gen_identifier_value( $id )
|
||||||
|
{
|
||||||
|
// for non-numeric identifiers, return ascii value
|
||||||
|
// of character to represent our value
|
||||||
|
return is_numeric( $id )
|
||||||
|
? $id
|
||||||
|
: ord( $id );
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $argv[ 1 ];
|
||||||
|
$fdat = explode( '.', basename( $file ) );
|
||||||
|
$name = $fdat[ 0 ];
|
||||||
|
|
||||||
|
$cur = '';
|
||||||
|
$queue = array();
|
||||||
|
$or = array();
|
||||||
|
|
||||||
|
$fh = fopen( $file, 'r' );
|
||||||
|
|
||||||
|
echo 'name="rates/territories/', $name, '" ', "\n",
|
||||||
|
'desc="', ucfirst( $name ), ' territory classifications">' . "\n\n";
|
||||||
|
|
||||||
|
echo "<!--\n",
|
||||||
|
" WARNING: This file was generated by {$argv[0]}; do not modify!\n",
|
||||||
|
"-->\n\n";
|
||||||
|
|
||||||
|
$ids = array();
|
||||||
|
$params = array();
|
||||||
|
$imports = array();
|
||||||
|
$prev_yields = '';
|
||||||
|
$prev_yields_all = array();
|
||||||
|
$classes = '';
|
||||||
|
|
||||||
|
$param_type = 'terrType' . ucfirst( $name );
|
||||||
|
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
// read the line within the loop so that we do not terminate until after we
|
||||||
|
// treat eof as an empty line
|
||||||
|
$line = str_replace( array( "\n", "\r" ), '', fgets( $fh ) );
|
||||||
|
|
||||||
|
if ( !$cur )
|
||||||
|
{
|
||||||
|
if ( substr( $line, 0, 12 ) === '@import-pkg ' )
|
||||||
|
{
|
||||||
|
$imports[] = substr( $line, 12 );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we expect this line to be a territory descriptor
|
||||||
|
try
|
||||||
|
{
|
||||||
|
list ( $id, $desc ) = parse_tdesc( $line );
|
||||||
|
}
|
||||||
|
catch ( Exception $e )
|
||||||
|
{
|
||||||
|
fwrite( STDERR, 'Invalid territory descriptor: ' . $line );
|
||||||
|
exit( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids[] = $id;
|
||||||
|
$cur = $id;
|
||||||
|
}
|
||||||
|
elseif ( ( $line === '' ) || feof( $fh ) )
|
||||||
|
{
|
||||||
|
// generate param for typedef
|
||||||
|
$params[ $id ] = $desc;
|
||||||
|
|
||||||
|
// if there's nothing in the queue, then treat this as an 'ROS' (this
|
||||||
|
// should appear as the *last* territory, or it will not function as
|
||||||
|
// expected)
|
||||||
|
if ( count( $queue ) === 0 )
|
||||||
|
{
|
||||||
|
$prev = $prev_yields_all;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$prev = array( $prev_yields );
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate the classification
|
||||||
|
$classes .= gen_classification( $id, $name, $desc, $prev, $queue, $or );
|
||||||
|
|
||||||
|
// this accomplishes two things: (1) avoids regexes if there's a
|
||||||
|
// previous match and (2) ensures that we cannot possibly match multiple
|
||||||
|
// territories
|
||||||
|
$prev_yields = gen_yields( $id, $name );
|
||||||
|
$prev_yields_all[] = $prev_yields;
|
||||||
|
|
||||||
|
$cur = '';
|
||||||
|
$queue = array();
|
||||||
|
$or = array();
|
||||||
|
|
||||||
|
if ( feof( $fh ) )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ( $line[0] === '=' )
|
||||||
|
{
|
||||||
|
// =foo means match on classification @yields "foo"
|
||||||
|
$or[] = substr( $line, 1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$queue[] = $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$param_name = 'territory_' . $name;
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php /* XXX: This is hard-coded! */ ?>
|
||||||
|
<lv:import package="/rater/core/tdat" />
|
||||||
|
|
||||||
|
<?php foreach ( $imports as $pkg ) { ?>
|
||||||
|
<lv:import package="<?php echo $pkg; ?>" />
|
||||||
|
<?php } ?>
|
||||||
|
|
||||||
|
<lv:extern name="zip" type="param" dtype="integer" dim="1"
|
||||||
|
missing="this territory package requires an available `zip' parameter; please
|
||||||
|
import a package that provides it" />
|
||||||
|
|
||||||
|
<lv:param name="<?php echo $param_name; ?>" type="<?php echo $param_type; ?>" default="0" set="vector" desc="Territory Override" />
|
||||||
|
|
||||||
|
<lv:typedef name="<?php echo $param_type; ?>" desc="<?php echo ucfirst( $name ); ?> Territories">
|
||||||
|
<lv:enum type="integer">
|
||||||
|
<?php $item_prefix = 'TERR_' . strtoupper( $name ) . '_'; ?>
|
||||||
|
<lv:item name="<?php echo $item_prefix; ?>_NONE" value="0" desc="No Override" />
|
||||||
|
<?php foreach ( $params as $id => $desc ) { ?>
|
||||||
|
<?php $item_name = $item_prefix . $id; ?>
|
||||||
|
<lv:item name="<?php echo $item_name; ?>" value="<?php echo gen_identifier_value( $id ); ?>" desc="<?php echo $desc; ?>" />
|
||||||
|
<?php } ?>
|
||||||
|
</lv:enum>
|
||||||
|
</lv:typedef>
|
||||||
|
|
||||||
|
<?php echo $classes; ?>
|
||||||
|
|
||||||
|
<lv:section title="Territory Determination">
|
||||||
|
<?php foreach ( $ids as $id ) { ?>
|
||||||
|
<?php $yields = sprintf( '%sTerr%s', $name, $id ); ?>
|
||||||
|
<?php $class = sprintf( '%s-terr%s', $name, gen_identifier( $id ) ); ?>
|
||||||
|
<lv:apply-template name="_terr-code_" class="<?php echo $class; ?>" code="<?php echo gen_identifier_value( $id ); ?>" generates="<?php echo $yields; ?>" />
|
||||||
|
<?php } ?>
|
||||||
|
|
||||||
|
<lv:rate yields="_<?php echo $name; ?>TerrCode">
|
||||||
|
<c:sum of="zip" index="k" generates="<?php echo $name; ?>TerrCode" desc="Territory code">
|
||||||
|
<c:cases>
|
||||||
|
<c:case>
|
||||||
|
<c:when name="<?php echo $param_name; ?>" index="k">
|
||||||
|
<c:gt>
|
||||||
|
<c:const value="0" type="integer" desc="Use territory override if set" />
|
||||||
|
</c:gt>
|
||||||
|
</c:when>
|
||||||
|
|
||||||
|
<c:value-of name="<?php echo $param_name; ?>" index="k" />
|
||||||
|
</c:case>
|
||||||
|
|
||||||
|
<c:otherwise>
|
||||||
|
<c:sum label="Determine applicable territory code">
|
||||||
|
<?php foreach ( $ids as $id ) { ?>
|
||||||
|
<c:value-of name="<?php echo $name; ?>Terr<?php echo $id; ?>" index="k" />
|
||||||
|
<?php } ?>
|
||||||
|
</c:sum>
|
||||||
|
</c:otherwise>
|
||||||
|
</c:cases>
|
||||||
|
</c:sum>
|
||||||
|
</lv:rate>
|
||||||
|
</lv:section>
|
||||||
|
</lv:package>
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Given a set of sorted zips, generates a regular expression to match only the
|
||||||
|
* given input
|
||||||
|
*
|
||||||
|
* I wanted to write this in Scheme (it's a perfect recursive application), but
|
||||||
|
* I figured that other developers may get annoyed having to find a Scheme impl
|
||||||
|
* that works for them...so...PHP it is...
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* THIS SCRIPT EXPECTS THE DATA TO BE SORTED! This can be easily accomplished by
|
||||||
|
* doing the following:
|
||||||
|
* sort -d zipfile | ./zipre
|
||||||
|
*/
|
||||||
|
|
||||||
|
include 'lib/zipre.php';
|
||||||
|
|
||||||
|
// grab input from stdin (must be sorted!)
|
||||||
|
$data = explode( "\n", file_get_contents( 'php://stdin' ) );
|
||||||
|
|
||||||
|
// build and output
|
||||||
|
echo gen_re_quick( $data );
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
targetNamespace="http://www.lovullo.com/rater/worksheet"
|
||||||
|
xmlns="http://www.lovullo.com/rater/worksheet"
|
||||||
|
xmlns:w="http://www.lovullo.com/rater/worksheet"
|
||||||
|
elementFormDefault="qualified">
|
||||||
|
|
||||||
|
|
||||||
|
<xs:element name="worksheet">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Root node for rating worksheets
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||||
|
</xs:sequence>
|
||||||
|
|
||||||
|
<xs:attribute name="name" type="xs:string" use="required" />
|
||||||
|
|
||||||
|
<xs:attribute name="package" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation xml:lang="en">
|
||||||
|
Package for which worksheet is being generated
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
</xs:schema>
|
Loading…
Reference in New Issue