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
|
||||
|
||||
# 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)
|
||||
|
||||
# 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.
|
||||
|
||||
|
||||
## "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
|
||||
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
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
path_src := ../src
|
||||
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)
|
||||
|
||||
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" />
|