835 lines
27 KiB
XML
835 lines
27 KiB
XML
<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
<!--
|
|
Compile package
|
|
|
|
Copyright (C) 2016 R-T Specialty, LLC.
|
|
|
|
This file is part of TAME.
|
|
|
|
TAME 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 Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see
|
|
<http://www.gnu.org/licenses/>.
|
|
|
|
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>
|