Another round of xmlo compilation performance enhancements
This reduces overall build times for one of our systems by ~50% by addressing a lot of the low-hanging fruit for compilation of object files. There is much more work to be done, and the addition of maps added a little bit of a mess that will be abstracted in future commits once I'm done surveying the possible improvements that can be done.master
commit
c5a99e594d
|
@ -19,139 +19,130 @@
|
|||
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 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:map="http://www.w3.org/2005/xpath-functions/map"
|
||||
xmlns:lv="http://www.lovullo.com/rater"
|
||||
xmlns:c="http://www.lovullo.com/calc"
|
||||
xmlns:preproc="http://www.lovullo.com/rater/preproc">
|
||||
|
||||
|
||||
<template match="lv:package" mode="preproc:compile-fragments">
|
||||
<template mode="preproc:compile-fragments" priority="9"
|
||||
match="lv:package">
|
||||
<variable name="symtable-map" as="map( xs:string, element( preproc:sym ) )"
|
||||
select="map:merge(
|
||||
for $sym in preproc:symtable/preproc:sym
|
||||
return map{ string( $sym/@name ) : $sym } )" />
|
||||
|
||||
<copy>
|
||||
<sequence select="@*, *" />
|
||||
|
||||
<!-- compile each fragment in the symbol table -->
|
||||
<preproc:fragments>
|
||||
<for-each select="preproc:symtable/preproc:sym">
|
||||
<variable name="result">
|
||||
<apply-templates select="." mode="preproc:compile-fragments" />
|
||||
</variable>
|
||||
|
||||
<if test="$result != ''">
|
||||
<preproc:fragment id="{@name}">
|
||||
<value-of select="$result" />
|
||||
</preproc:fragment>
|
||||
</if>
|
||||
</for-each>
|
||||
<apply-templates mode="preproc:compile-fragments">
|
||||
<with-param name="symtable-map" select="$symtable-map"
|
||||
tunnel="yes" />
|
||||
</apply-templates>
|
||||
</preproc:fragments>
|
||||
</copy>
|
||||
</template>
|
||||
|
||||
|
||||
<template match="preproc:sym[ @src ]" mode="preproc:compile-fragments" priority="9">
|
||||
<!-- do not compile external symbols -->
|
||||
</template>
|
||||
<template mode="preproc:compile-fragments" priority="5"
|
||||
match="lv:rate">
|
||||
<preproc:fragment id="{@yields}">
|
||||
<apply-templates mode="compile" select="." />
|
||||
</preproc:fragment>
|
||||
|
||||
<template match="preproc:sym" mode="preproc:compile-fragments" priority="1">
|
||||
<message terminate="yes">
|
||||
<text>[jsc] fatal: unknown symbol type for `</text>
|
||||
<value-of select="@name" />
|
||||
<text>': </text>
|
||||
<value-of select="@type" />
|
||||
</message>
|
||||
<apply-templates mode="preproc:compile-fragments" />
|
||||
</template>
|
||||
|
||||
|
||||
<template match="preproc:sym[ @type='rate' ]" mode="preproc:compile-fragments" priority="5">
|
||||
<template mode="preproc:compile-fragments" priority="5"
|
||||
match="lv:classify">
|
||||
<preproc:fragment id=":class:{@as}">
|
||||
<apply-templates select="." mode="compile" />
|
||||
</preproc:fragment>
|
||||
|
||||
<apply-templates mode="preproc:compile-fragments" />
|
||||
</template>
|
||||
|
||||
|
||||
<template mode="preproc:compile-fragments" priority="5"
|
||||
match="lv:function">
|
||||
<preproc:fragment id="{@name}">
|
||||
<apply-templates select="." mode="compile" />
|
||||
</preproc:fragment>
|
||||
|
||||
<apply-templates mode="preproc:compile-fragments" />
|
||||
</template>
|
||||
|
||||
<template mode="preproc:compile-fragments" priority="7"
|
||||
match="lv:function/lv:param">
|
||||
<!-- ignore -->
|
||||
</template>
|
||||
|
||||
|
||||
<template mode="preproc:compile-fragments" priority="5"
|
||||
match="lv:param">
|
||||
<variable name="name" select="@name" />
|
||||
<variable name="pkg" as="element( lv:package )"
|
||||
select="root(.)" />
|
||||
|
||||
<!-- could be one of two places -->
|
||||
<apply-templates mode="compile" select="
|
||||
$pkg/lv:rate[ @yields=$name ]
|
||||
, $pkg/lv:rate-group/lv:rate[ @yields=$name ]
|
||||
" />
|
||||
</template>
|
||||
<template match="preproc:sym[ @type='gen' ]" mode="preproc:compile-fragments" priority="5">
|
||||
<!-- compiled by above -->
|
||||
<preproc:fragment id="{@name}">
|
||||
<apply-templates select="." mode="compile" />
|
||||
</preproc:fragment>
|
||||
</template>
|
||||
|
||||
<template match="preproc:sym[ @type='class' ]" mode="preproc:compile-fragments" priority="5">
|
||||
<!-- name is prefixed with :class: -->
|
||||
<variable name="as" select="substring-after( @name, ':class:' )" />
|
||||
<variable name="pkg" as="element( lv:package )"
|
||||
select="root(.)" />
|
||||
|
||||
<apply-templates select="$pkg/lv:classify[ @as=$as ]" mode="compile" />
|
||||
</template>
|
||||
<template match="preproc:sym[ @type='cgen' ]" mode="preproc:compile-fragments" priority="5">
|
||||
<!-- compiled by above -->
|
||||
<template mode="preproc:compile-fragments" priority="5"
|
||||
match="lv:typedef">
|
||||
<preproc:fragment id="{@name}">
|
||||
<apply-templates mode="compile" select="." />
|
||||
</preproc:fragment>
|
||||
|
||||
<apply-templates mode="preproc:compile-fragments" />
|
||||
</template>
|
||||
|
||||
<template match="preproc:sym[ @type='func' ]" mode="preproc:compile-fragments" priority="5">
|
||||
<variable name="name" select="@name" />
|
||||
<variable name="pkg" as="element( lv:package )"
|
||||
select="root(.)" />
|
||||
|
||||
<apply-templates select="$pkg/lv:function[ @name=$name ]" mode="compile" />
|
||||
<template mode="preproc:compile-fragments" priority="5"
|
||||
match="lv:const|lv:item">
|
||||
<preproc:fragment id="{@name}">
|
||||
<apply-templates mode="compile" select=".">
|
||||
<with-param name="as-const" select="true()" />
|
||||
</apply-templates>
|
||||
</preproc:fragment>
|
||||
|
||||
<apply-templates mode="preproc:compile-fragments" />
|
||||
</template>
|
||||
|
||||
<template match="preproc:sym[ @type='param' ]" mode="preproc:compile-fragments" priority="5">
|
||||
<variable name="name" select="@name" />
|
||||
<variable name="pkg" as="element( lv:package )"
|
||||
select="root(.)" />
|
||||
|
||||
<apply-templates select="$pkg/lv:param[ @name=$name ]" mode="compile" />
|
||||
<template mode="preproc:compile-fragments" priority="5"
|
||||
match="lv:meta/lv:prop">
|
||||
<preproc:fragment id=":meta:{@name}">
|
||||
<apply-templates mode="compile" select="." />
|
||||
</preproc:fragment>
|
||||
|
||||
<apply-templates mode="preproc:compile-fragments" />
|
||||
</template>
|
||||
|
||||
<template match="preproc:sym[ @type='type' ]" mode="preproc:compile-fragments" priority="5">
|
||||
<variable name="name" select="@name" />
|
||||
<variable name="pkg" as="element( lv:package )"
|
||||
select="root(.)" />
|
||||
|
||||
<!-- a typedef can stand on its own or exist within another typedef -->
|
||||
<apply-templates mode="compile" select="
|
||||
$pkg/lv:typedef[ @name=$name ]
|
||||
, $pkg//lv:typedef//lv:typedef[ @name=$name ]
|
||||
" />
|
||||
<template mode="preproc:compile-fragments" priority="7"
|
||||
match="lv:template">
|
||||
<!-- don't process template bodies, since they are not yet expanded -->
|
||||
</template>
|
||||
|
||||
<template match="preproc:sym[ @type='const' ]" mode="preproc:compile-fragments" priority="5">
|
||||
<variable name="name" select="@name" />
|
||||
<variable name="pkg" as="element( lv:package )"
|
||||
select="root(.)" />
|
||||
|
||||
<apply-templates mode="compile"
|
||||
select="$pkg/lv:const[ @name=$name ],
|
||||
$pkg/lv:typedef//lv:item[ @name=$name ]">
|
||||
<with-param name="as-const" select="true()" />
|
||||
</apply-templates>
|
||||
<template mode="preproc:compile-fragments" priority="7"
|
||||
match="preproc:*">
|
||||
<!-- we don't compile this stuff -->
|
||||
</template>
|
||||
|
||||
<template match="preproc:sym[ @type='tpl' ]" mode="preproc:compile-fragments" priority="5">
|
||||
<!-- templates are for the preprocessor only -->
|
||||
</template>
|
||||
|
||||
<template match="preproc:sym[ @type='lparam' ]" mode="preproc:compile-fragments" priority="5">
|
||||
<!-- they're local and therefore compiled as part of the containing block -->
|
||||
</template>
|
||||
|
||||
<template match="preproc:sym[ @type='meta' ]"
|
||||
mode="preproc:compile-fragments" priority="5">
|
||||
<variable name="name" select="substring-after( @name, ':meta:' )" />
|
||||
<variable name="pkg" as="element( lv:package )"
|
||||
select="root(.)" />
|
||||
|
||||
<variable name="node" as="element( lv:prop )"
|
||||
select="$pkg/lv:meta/lv:prop[ @name=$name ]" />
|
||||
<apply-templates mode="compile"
|
||||
select="$node" />
|
||||
<template mode="preproc:compile-fragments" priority="1"
|
||||
match="node()">
|
||||
<apply-templates mode="preproc:compile-fragments" />
|
||||
</template>
|
||||
|
||||
</stylesheet>
|
||||
|
|
|
@ -551,6 +551,7 @@
|
|||
@return generated classification expression
|
||||
-->
|
||||
<template match="lv:classify" mode="compile">
|
||||
<param name="symtable-map" as="map(*)" tunnel="yes" />
|
||||
<param name="noclass" />
|
||||
<param name="result-set" />
|
||||
<param name="ignores" />
|
||||
|
@ -569,7 +570,7 @@
|
|||
<text>'] = (function(){var result,tmp; </text>
|
||||
</if>
|
||||
|
||||
<!-- locate classification criteria (since lv:any and lv:all are split
|
||||
<!-- locate classification predicates (since lv:any and lv:all are split
|
||||
into their own classifications, matching on any depth ensures we get
|
||||
into any preproc:* nodes as well) -->
|
||||
<variable name="criteria" as="element( lv:match )*"
|
||||
|
@ -578,8 +579,8 @@
|
|||
or not( @on=$ignores/@ref ) ]" />
|
||||
|
||||
<variable name="criteria-syms" as="element( preproc:sym )*"
|
||||
select="root(.)/preproc:symtable/preproc:sym[
|
||||
@name = $criteria/@on ]" />
|
||||
select="for $match in $criteria
|
||||
return $symtable-map( $match/@on )" />
|
||||
|
||||
<variable name="dest">
|
||||
<choose>
|
||||
|
@ -674,7 +675,7 @@
|
|||
</if>
|
||||
|
||||
<variable name="sym"
|
||||
select="root(.)/preproc:symtable/preproc:sym[ @name=$self/@yields ]" />
|
||||
select="$symtable-map( $self/@yields )" />
|
||||
|
||||
<!-- if we are not any type of set, then yield the value of the first
|
||||
index (note the $criteria check; see above); note that we do not do
|
||||
|
@ -733,6 +734,8 @@
|
|||
@return generated match code
|
||||
-->
|
||||
<template match="lv:match" mode="compile" priority="1">
|
||||
<param name="symtable-map" as="map(*)" tunnel="yes" />
|
||||
|
||||
<!-- default to all matches being required -->
|
||||
<param name="operator" select="'&&'" />
|
||||
<param name="yields" select="../@yields" />
|
||||
|
@ -741,7 +744,7 @@
|
|||
<variable name="name" select="@on" />
|
||||
|
||||
<variable name="sym-on" as="element( preproc:sym )"
|
||||
select="root(.)/preproc:symtable/preproc:sym[ @name = $name ]" />
|
||||
select="$symtable-map( $name )" />
|
||||
|
||||
<text> tmp = </text>
|
||||
|
||||
|
@ -837,8 +840,8 @@
|
|||
<choose>
|
||||
<when test="@value">
|
||||
<variable name="value" select="@value" />
|
||||
<variable name="sym"
|
||||
select="root(.)/preproc:symtable/preproc:sym[ @name=$value ]" />
|
||||
<variable name="sym" as="element( preproc:sym )?"
|
||||
select="$symtable-map( $value )" />
|
||||
|
||||
<choose>
|
||||
<!-- value unavailable (TODO: vector/matrix support) -->
|
||||
|
@ -1191,6 +1194,8 @@
|
|||
</template>
|
||||
|
||||
<template match="lv:rate" mode="compile-class-condition">
|
||||
<param name="symtable-map" as="map(*)" tunnel="yes" />
|
||||
|
||||
<variable name="rate" select="." />
|
||||
|
||||
<!-- Generate expression for class list (leave the @no check to the cmatch
|
||||
|
@ -1220,11 +1225,8 @@
|
|||
|
||||
<variable name="ref" select="@ref" />
|
||||
|
||||
<if test="
|
||||
root(.)/preproc:symtable/preproc:sym[
|
||||
@name=concat( ':class:', $ref )
|
||||
]/@preproc:generated='true'
|
||||
">
|
||||
<if test="$symtable-map( concat( ':class:', $ref ) )
|
||||
/@preproc:generated='true'">
|
||||
<text>gen</text>
|
||||
</if>
|
||||
|
||||
|
@ -1244,6 +1246,8 @@
|
|||
|
||||
|
||||
<template match="lv:rate" mode="compile-cmatch">
|
||||
<param name="symtable-map" as="map(*)" tunnel="yes" />
|
||||
|
||||
<variable name="root" select="root(.)" />
|
||||
|
||||
<!-- generate cmatch call that will generate the cmatch set -->
|
||||
|
@ -1255,6 +1259,7 @@
|
|||
|
||||
<text>args['</text>
|
||||
<call-template name="compiler:get-class-yield">
|
||||
<with-param name="symtable-map" select="$symtable-map" />
|
||||
<with-param name="name" select="@ref" />
|
||||
<with-param name="search" select="$root" />
|
||||
</call-template>
|
||||
|
@ -1268,6 +1273,7 @@
|
|||
|
||||
<text>args['</text>
|
||||
<call-template name="compiler:get-class-yield">
|
||||
<with-param name="symtable-map" select="$symtable-map" />
|
||||
<with-param name="name" select="@ref" />
|
||||
<with-param name="search" select="$root" />
|
||||
</call-template>
|
||||
|
@ -1278,16 +1284,13 @@
|
|||
|
||||
|
||||
<template name="compiler:get-class-yield">
|
||||
<param name="symtable-map" as="map(*)" />
|
||||
<param name="name" />
|
||||
<param name="search" />
|
||||
|
||||
<variable name="yields">
|
||||
<value-of select="
|
||||
root(.)/preproc:symtable/preproc:sym[
|
||||
@name=concat( ':class:', $name )
|
||||
]/@yields
|
||||
" />
|
||||
</variable>
|
||||
<variable name="yields"
|
||||
select="$symtable-map(
|
||||
concat( ':class:', $name ) )/@yields" />
|
||||
|
||||
<choose>
|
||||
<when test="$yields != ''">
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
-->
|
||||
<stylesheet version="2.0"
|
||||
xmlns="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:lv="http://www.lovullo.com/rater"
|
||||
xmlns:c="http://www.lovullo.com/calc"
|
||||
|
@ -57,12 +58,19 @@
|
|||
<variable name="l:orig-root" as="document-node( element( lv:package ) )"
|
||||
select="/" />
|
||||
|
||||
<variable name="l:orig-package" as="element( lv:package )"
|
||||
select="$l:orig-root/lv:package" />
|
||||
|
||||
<variable name="l:process-empty" as="element( preproc:sym )*"
|
||||
select="()" />
|
||||
|
||||
<variable name="l:stack-empty" as="element( preproc:sym )*"
|
||||
select="()" />
|
||||
|
||||
<variable name="l:root-symtable-map" as="map( xs:string, element( preproc:sym ) )"
|
||||
select="map:merge( for $sym in $l:orig-package/preproc:symtable/preproc:sym
|
||||
return map{ string( $sym/@name ) : $sym } )" />
|
||||
|
||||
|
||||
<template match="*" mode="l:link" priority="1">
|
||||
<call-template name="log:error">
|
||||
|
@ -106,7 +114,7 @@
|
|||
<call-template name="log:debug">
|
||||
<with-param name="name" select="'link'" />
|
||||
<with-param name="msg">
|
||||
<text>building dependency tree...</text>
|
||||
<text>building dependency graph...</text>
|
||||
</with-param>
|
||||
</call-template>
|
||||
|
||||
|
@ -124,7 +132,7 @@
|
|||
<call-template name="log:debug">
|
||||
<with-param name="name" select="'link'" />
|
||||
<with-param name="msg">
|
||||
<text>resolving dependency tree...</text>
|
||||
<text>resolving dependency graph...</text>
|
||||
</with-param>
|
||||
</call-template>
|
||||
|
||||
|
@ -134,7 +142,7 @@
|
|||
<copy>
|
||||
<copy-of select="@*" />
|
||||
|
||||
<!-- copy the dependency tree -->
|
||||
<!-- copy the dependency graph -->
|
||||
<copy-of select="$deps" />
|
||||
|
||||
<!-- if map data was provided, generate the map -->
|
||||
|
@ -203,7 +211,7 @@
|
|||
</variable>
|
||||
|
||||
<!-- start at the top of the table and begin processing each symbol
|
||||
individually, generating a dependency tree as we go -->
|
||||
individually, generating a dependency graph as we go -->
|
||||
<variable name="result" as="element()+">
|
||||
<call-template name="l:depgen-sym">
|
||||
<with-param name="pending" select="$yields" />
|
||||
|
@ -308,12 +316,8 @@
|
|||
<!-- there is no reason (in the current implementation) that this
|
||||
should _not_ have already been resolved in the package being
|
||||
linked -->
|
||||
<variable name="pkg" as="element( lv:package )" select="
|
||||
$l:orig-root/lv:package" />
|
||||
|
||||
<variable name="resolv" as="element( preproc:sym )?"
|
||||
select="$pkg/preproc:symtable/preproc:sym[
|
||||
@name=$name ]" />
|
||||
select="$l:root-symtable-map( $name )" />
|
||||
|
||||
<choose>
|
||||
<!-- if this symbol is not external, then we have found it -->
|
||||
|
@ -449,7 +453,7 @@
|
|||
select="." />
|
||||
|
||||
<!-- perform circular dependency check and blow up if found (we cannot choose
|
||||
a proper linking order without a correct dependency tree); the only
|
||||
a proper linking order without a correct dependency graph); the only
|
||||
exception is if the circular dependency is a function, since that simply
|
||||
implies recursion, which we can handle just fine -->
|
||||
<variable name="circ" as="element( preproc:sym )*"
|
||||
|
@ -670,7 +674,7 @@
|
|||
if ( @src and not( @src='' ) ) then
|
||||
document( concat( @src, '.xmlo' ), $l:orig-root )/lv:*
|
||||
else
|
||||
$l:orig-root/lv:package
|
||||
$l:orig-package
|
||||
" />
|
||||
|
||||
<variable name="name" as="xs:string" select="@name" />
|
||||
|
@ -1048,7 +1052,7 @@
|
|||
if ( @src and not( @src='' ) ) then
|
||||
document( concat( @src, '.xmlo' ), $l:orig-root )/lv:*
|
||||
else
|
||||
$l:orig-root/lv:package
|
||||
$l:orig-package
|
||||
" />
|
||||
|
||||
<variable name="name" select="@name" />
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
-->
|
||||
<stylesheet version="1.0"
|
||||
xmlns="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
|
||||
xmlns:lv="http://www.lovullo.com/rater"
|
||||
xmlns:ext="http://www.lovullo.com/ext"
|
||||
xmlns:c="http://www.lovullo.com/calc"
|
||||
|
@ -68,6 +70,11 @@
|
|||
<template match="lv:package" mode="lvv:validate" priority="9">
|
||||
<param name="symbol-map" />
|
||||
|
||||
<variable name="symtable-map" as="map( xs:string, element( preproc:sym ) )"
|
||||
select="map:merge(
|
||||
for $sym in preproc:symtable/preproc:sym
|
||||
return map{ string( $sym/@name ) : $sym } )" />
|
||||
|
||||
<choose>
|
||||
<when test="$prohibit-validation = 'true'">
|
||||
<message>
|
||||
|
@ -89,7 +96,10 @@
|
|||
</message>
|
||||
|
||||
<!-- validate -->
|
||||
<apply-templates mode="lvv:validate" />
|
||||
<apply-templates mode="lvv:validate">
|
||||
<with-param name="symtable-map" select="$symtable-map"
|
||||
tunnel="yes" />
|
||||
</apply-templates>
|
||||
</otherwise>
|
||||
</choose>
|
||||
</template>
|
||||
|
@ -119,6 +129,7 @@
|
|||
</template>
|
||||
|
||||
|
||||
<!-- XXX: Nothing is calling this! -->
|
||||
<template name="lvv:symbol-chk">
|
||||
<param name="root" />
|
||||
<param name="symbol-map" />
|
||||
|
@ -171,14 +182,13 @@
|
|||
|
||||
|
||||
<template match="c:apply[@name]" mode="lvv:validate" priority="5">
|
||||
<param name="symtable-map" as="map(*)" tunnel="yes" />
|
||||
|
||||
<variable name="name" select="@name" />
|
||||
<variable name="self" select="." />
|
||||
<variable name="fsym" select="
|
||||
root(.)/preproc:symtable/preproc:sym[
|
||||
@type='func'
|
||||
and @name=$name
|
||||
]
|
||||
" />
|
||||
|
||||
<variable name="fsym" as="element( preproc:sym )"
|
||||
select="$symtable-map( $name )" />
|
||||
|
||||
<!-- ensure that a function is being applied -->
|
||||
<if test="not( $fsym )">
|
||||
|
@ -230,7 +240,12 @@
|
|||
Validate that match @on's exist
|
||||
-->
|
||||
<template match="lv:classify[ @as ]//lv:match" mode="lvv:validate" priority="9">
|
||||
<if test="not( @on=root(.)/preproc:symtable/preproc:sym[ @type ]/@name )">
|
||||
<param name="symtable-map" as="map(*)" tunnel="yes" />
|
||||
|
||||
<variable name="sym" as="element( preproc:sym )?"
|
||||
select="$symtable-map( @on )" />
|
||||
|
||||
<if test="not( $sym )">
|
||||
<call-template name="lvv:error">
|
||||
<with-param name="desc" select="'Unknown match @on'" />
|
||||
<with-param name="refnode" select="." />
|
||||
|
@ -256,14 +271,13 @@
|
|||
Validate that non-numeric value matches actually exist and are constants
|
||||
-->
|
||||
<template match="lv:match[@value]" mode="lvv:validate-match" priority="5">
|
||||
<if test="
|
||||
not( number( @value ) = @value )
|
||||
and not(
|
||||
@value=root(.)/preproc:symtable/preproc:sym[
|
||||
@type='const'
|
||||
]/@name
|
||||
)
|
||||
">
|
||||
<param name="symtable-map" as="map(*)" tunnel="yes" />
|
||||
|
||||
<variable name="sym" as="element( preproc:sym )?"
|
||||
select="$symtable-map( @value )" />
|
||||
|
||||
<if test="not( number( @value ) = @value )
|
||||
and not( $sym )">
|
||||
|
||||
<call-template name="lvv:error">
|
||||
<with-param name="desc" select="'Unknown match value'" />
|
||||
|
@ -338,6 +352,8 @@
|
|||
</template>
|
||||
|
||||
<template match="c:*[@name or @of]" mode="lvv:validate" priority="2">
|
||||
<param name="symtable-map" as="map(*)" tunnel="yes" />
|
||||
|
||||
<variable name="name">
|
||||
<choose>
|
||||
<when test="@of">
|
||||
|
@ -350,19 +366,6 @@
|
|||
</choose>
|
||||
</variable>
|
||||
|
||||
<!-- XXX: have to maintain this list! -->
|
||||
<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 -->
|
||||
<variable name="fname" select="
|
||||
ancestor::lv:function[
|
||||
|
@ -385,16 +388,11 @@
|
|||
<!-- 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) -->
|
||||
<variable name="sym" select="
|
||||
if ( $fname ) then
|
||||
root(.)/preproc:symtable/preproc:sym[
|
||||
@name=concat( ':', $fname, ':', $name )
|
||||
]
|
||||
else
|
||||
root(.)/preproc:symtable/preproc:sym[
|
||||
@name=$name
|
||||
]
|
||||
" />
|
||||
<variable name="sym" as="element( preproc:sym )?"
|
||||
select="if ( $fname ) then
|
||||
$symtable-map( concat( ':', $fname, ':', $name ) )
|
||||
else
|
||||
$symtable-map( $name )" />
|
||||
|
||||
<variable name="type" select="$sym/@dtype" />
|
||||
|
||||
|
@ -581,15 +579,12 @@
|
|||
|
||||
|
||||
<template match="c:apply/c:arg[@name]" mode="lvv:validate" priority="5">
|
||||
<param name="symtable-map" as="map(*)" tunnel="yes" />
|
||||
|
||||
<!-- merely validate its existence -->
|
||||
<variable name="fname" select="parent::c:apply/@name" />
|
||||
<if test="not(
|
||||
concat( ':', $fname, ':', @name ) = root(.)/preproc:symtable/preproc:sym[
|
||||
@type='lparam'
|
||||
and @parent=$fname
|
||||
]/@name
|
||||
)">
|
||||
|
||||
<if test="not( $symtable-map( concat( ':', $fname, ':', @name ) ) )">
|
||||
<call-template name="lvv:error">
|
||||
<with-param name="desc" select="'Unknown argument'" />
|
||||
<with-param name="refnode" select="." />
|
||||
|
@ -641,20 +636,21 @@
|
|||
Checks for use of undefined classifications
|
||||
-->
|
||||
<template mode="lvv:validate" priority="2"
|
||||
match="lv:rate/lv:class[
|
||||
not( concat( ':class:', @ref ) = root(.)/preproc:symtable/preproc:sym[ @type='class' ]/@name )
|
||||
]">
|
||||
match="lv:rate/lv:class">
|
||||
<param name="symtable-map" as="map(*)" tunnel="yes" />
|
||||
|
||||
<call-template name="lvv:error">
|
||||
<with-param name="desc" select="'Unknown classification'" />
|
||||
<with-param name="refnode" select="." />
|
||||
<with-param name="content">
|
||||
<text>unknown classification '</text>
|
||||
<if test="not( $symtable-map( concat( ':class:', @ref ) ) )">
|
||||
<call-template name="lvv:error">
|
||||
<with-param name="desc" select="'Unknown classification'" />
|
||||
<with-param name="refnode" select="." />
|
||||
<with-param name="content">
|
||||
<text>unknown classification '</text>
|
||||
<value-of select="@ref" />
|
||||
<text>' referenced by </text>
|
||||
<value-of select="ancestor::lv:rate/@yields" />
|
||||
</with-param>
|
||||
</call-template>
|
||||
<text>' referenced by </text>
|
||||
<value-of select="ancestor::lv:rate/@yields" />
|
||||
</with-param>
|
||||
</call-template>
|
||||
</if>
|
||||
</template>
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
-->
|
||||
<stylesheet version="1.0"
|
||||
xmlns="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
|
||||
xmlns:preproc="http://www.lovullo.com/rater/preproc"
|
||||
xmlns:lv="http://www.lovullo.com/rater"
|
||||
xmlns:t="http://www.lovullo.com/rater/apply-template"
|
||||
|
@ -565,6 +567,16 @@
|
|||
<param name="orig-root" as="element()" />
|
||||
<param name="rpcount" select="0" />
|
||||
|
||||
<variable name="symtable-map" as="map( xs:string, element( preproc:sym ) )"
|
||||
select="map:merge(
|
||||
for $sym in preproc:symtable/preproc:sym
|
||||
return map{ string( $sym/@name ) : $sym } )" />
|
||||
|
||||
<variable name="symdep-map" as="map( xs:string, element( preproc:sym-dep ) )"
|
||||
select="map:merge(
|
||||
for $sym-dep in preproc:sym-deps/preproc:sym-dep
|
||||
return map{ string( $sym-dep/@name ) : $sym-dep } )" />
|
||||
|
||||
<!-- arbitrary; intended to prevent infinite recursion -->
|
||||
<!-- TODO: same method as for templates; ensure changes, but do not create
|
||||
arbitrary limit -->
|
||||
|
@ -588,6 +600,8 @@
|
|||
|
||||
<apply-templates mode="preproc:resolv-syms">
|
||||
<with-param name="orig-root" select="$orig-root" />
|
||||
<with-param name="symtable-map" select="$symtable-map" tunnel="yes" />
|
||||
<with-param name="symdep-map" select="$symdep-map" tunnel="yes" />
|
||||
</apply-templates>
|
||||
</copy>
|
||||
</variable>
|
||||
|
@ -637,67 +651,39 @@
|
|||
</template>
|
||||
|
||||
|
||||
<!--
|
||||
Calculate symbol dimensions by taking the highest dimension of its
|
||||
dependencies
|
||||
|
||||
If all dependencies are not yet resolved, then schedule a repass.
|
||||
-->
|
||||
<template match="preproc:sym[ not( @src ) and @dim='?' ]" mode="preproc:resolv-syms" priority="5">
|
||||
<param name="orig-root" as="element()" />
|
||||
<param name="symtable-map" as="map(*)" tunnel="yes" />
|
||||
<param name="symdep-map" as="map(*)" tunnel="yes" />
|
||||
|
||||
<variable name="name" select="@name" />
|
||||
<variable name="pkg" as="element( lv:package )"
|
||||
select="root(.)" />
|
||||
|
||||
<variable name="deps" as="element( preproc:sym-dep )*" select="
|
||||
$pkg/preproc:sym-deps/preproc:sym-dep[ @name=$name ]
|
||||
" />
|
||||
<variable name="deps" as="element( preproc:sym-dep )?"
|
||||
select="$symdep-map( $name )" />
|
||||
|
||||
<variable name="depsyms-unresolv" as="element( preproc:sym )*" select="
|
||||
$pkg/preproc:symtable/preproc:sym[
|
||||
@name=$deps/preproc:sym-ref/@name
|
||||
]
|
||||
" />
|
||||
<!-- TODO: make this fatal -->
|
||||
<if test="empty( $deps ) and not( @no-deps = 'true' )">
|
||||
<message select="concat( 'internal: failed to located dependencies for `',
|
||||
$name, '''' )" />
|
||||
</if>
|
||||
|
||||
<variable name="depsyms-resolv">
|
||||
<for-each select="$depsyms-unresolv">
|
||||
<choose>
|
||||
<when test="not( @src )">
|
||||
<sequence select="." />
|
||||
</when>
|
||||
|
||||
<!-- look up complete symbol -->
|
||||
<otherwise>
|
||||
<variable name="name" select="@name" />
|
||||
<variable name="sym" select="
|
||||
document( concat( @src, '.xmlo' ), $orig-root )
|
||||
/lv:package/preproc:symtable/preproc:sym[
|
||||
@name=$name
|
||||
]
|
||||
" />
|
||||
|
||||
<if test="not( $sym )">
|
||||
<message terminate="yes">
|
||||
<text>[preproc] !!! failed to look up symbol `</text>
|
||||
<value-of select="$name" />
|
||||
<text>'</text>
|
||||
</message>
|
||||
</if>
|
||||
|
||||
<sequence select="$sym" />
|
||||
</otherwise>
|
||||
</choose>
|
||||
</for-each>
|
||||
</variable>
|
||||
|
||||
<variable name="depsyms" select="$depsyms-resolv/preproc:sym" />
|
||||
<variable name="depsyms" as="element( preproc:sym )*"
|
||||
select="for $ref in $deps/preproc:sym-ref
|
||||
return $symtable-map( $ref/@name )" />
|
||||
|
||||
<choose>
|
||||
<!-- unresolved dependency dimensions; defer until next pass -->
|
||||
<when test="
|
||||
$depsyms/@dim = '?'
|
||||
">
|
||||
<message>
|
||||
<text>[preproc] deferring `</text>
|
||||
<value-of select="$name" />
|
||||
<text>' dimensions with unresolved dependencies</text>
|
||||
</message>
|
||||
|
||||
<!-- schedule repass :x -->
|
||||
<sequence select="." />
|
||||
<preproc:repass src="preproc:sym resolv-syms"
|
||||
|
@ -706,38 +692,12 @@
|
|||
|
||||
<!-- all dependencies are resolved; calculate dimensions -->
|
||||
<otherwise>
|
||||
<!-- sort dependencies so that the largest dimension is at the top -->
|
||||
<variable name="maxset">
|
||||
<for-each select="$depsyms">
|
||||
<sort select="@dim" data-type="number" order="descending" />
|
||||
<sequence select="." />
|
||||
</for-each>
|
||||
</variable>
|
||||
<variable name="max" as="xs:double"
|
||||
select="if ( empty( $depsyms ) ) then
|
||||
0
|
||||
else
|
||||
max( $depsyms/@dim )" />
|
||||
|
||||
<variable name="max">
|
||||
<choose>
|
||||
<when test="count( $deps/preproc:sym-ref ) = 0">
|
||||
<!-- no dependencies, unknown size, so it's a scalar -->
|
||||
<text>0</text>
|
||||
</when>
|
||||
|
||||
<otherwise>
|
||||
<!-- largest value -->
|
||||
<value-of select="$maxset/preproc:sym[1]/@dim" />
|
||||
</otherwise>
|
||||
</choose>
|
||||
</variable>
|
||||
|
||||
<!-- failure? -->
|
||||
<if test="not( $max ) or $max = ''">
|
||||
<message terminate="yes">
|
||||
<text>[preproc] !!! failed to determine dimensions of `</text>
|
||||
<value-of select="$name" />
|
||||
<text>'</text>
|
||||
</message>
|
||||
</if>
|
||||
|
||||
<!-- copy, substituting calculated dimensions -->
|
||||
<copy>
|
||||
<sequence select="@*" />
|
||||
<attribute name="dim" select="$max" />
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
<stylesheet version="2.0"
|
||||
xmlns="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
|
||||
xmlns:symtable="http://www.lovullo.com/tame/symtable"
|
||||
xmlns:preproc="http://www.lovullo.com/rater/preproc"
|
||||
xmlns:lv="http://www.lovullo.com/rater"
|
||||
|
@ -247,12 +248,12 @@
|
|||
</variable>
|
||||
|
||||
<!-- remove duplicates (if any) -->
|
||||
<sequence select="
|
||||
$extresults/preproc:sym[
|
||||
not( @name=preceding-sibling::preproc:sym/@name )
|
||||
]
|
||||
, $extresults//preproc:error
|
||||
" />
|
||||
<for-each-group select="$extresults/preproc:sym"
|
||||
group-by="@name">
|
||||
<sequence select="current-group()[ 1 ]" />
|
||||
</for-each-group>
|
||||
|
||||
<sequence select="$extresults//preproc:error" />
|
||||
|
||||
<!-- process symbols (except imported externs) -->
|
||||
<variable name="newresult" as="element( preproc:syms )">
|
||||
|
@ -263,6 +264,24 @@
|
|||
</call-template>
|
||||
</variable>
|
||||
|
||||
<!-- contains duplicates -->
|
||||
<variable name="new-seq-map" as="map( xs:string, element( preproc:sym )+ )"
|
||||
select="map:merge(
|
||||
for $sym in $newresult/preproc:sym
|
||||
return map{ string( $sym/@name ) : $sym },
|
||||
map{ 'duplicates' : 'combine' } )" />
|
||||
|
||||
<variable name="new-typed-map" as="map( xs:string, element( preproc:sym ) )"
|
||||
select="map:merge(
|
||||
for $sym in $newresult/preproc:sym[ @type ]
|
||||
return map{ string( $sym/@name ) : $sym } )" />
|
||||
|
||||
<variable name="nonlocals-map" as="map( xs:string, element( preproc:sym ) )"
|
||||
select="map:merge(
|
||||
for $sym in $newresult/preproc:sym[ not( @local = 'true' ) ]
|
||||
return map{ string( $sym/@name ) : $sym } )" />
|
||||
|
||||
<!-- TODO: revisit this logic -->
|
||||
<variable name="dedup" as="element( preproc:sym )*"
|
||||
select="$newresult/preproc:sym[
|
||||
not(
|
||||
|
@ -270,29 +289,27 @@
|
|||
@pollute='true'
|
||||
and not( @type )
|
||||
and (
|
||||
@name=preceding-sibling::preproc:sym/@name
|
||||
or @name=$newresult/preproc:sym[ @type ]/@name
|
||||
(
|
||||
( count( $new-seq-map( @name ) ) gt 1 )
|
||||
and @name=preceding-sibling::preproc:sym/@name
|
||||
)
|
||||
or exists( $new-typed-map( @name ) )
|
||||
)
|
||||
)
|
||||
or (
|
||||
@local = 'true'
|
||||
and @name = following-sibling::preproc:sym[
|
||||
not( @local = 'true' )
|
||||
]/@name
|
||||
and exists( $nonlocals-map( @name ) )
|
||||
)
|
||||
)
|
||||
]" />
|
||||
|
||||
|
||||
<apply-templates mode="preproc:symtable-complete"
|
||||
select="$dedup">
|
||||
<with-param name="syms" select="$dedup" />
|
||||
</apply-templates>
|
||||
</preproc:symtable>
|
||||
|
||||
<message>
|
||||
<text>[preproc/symtable] done.</text>
|
||||
</message>
|
||||
<message select="'[preproc/symtable] done.'" />
|
||||
|
||||
<!-- 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
|
||||
|
@ -433,42 +450,59 @@
|
|||
</function>
|
||||
|
||||
|
||||
<!-- TODO: revisit this mess -->
|
||||
<template name="preproc:symtable-process-symbols">
|
||||
<param name="extresults" as="element( preproc:syms )" />
|
||||
<param name="new" as="element( preproc:syms )" />
|
||||
<param name="this-pkg" as="element( lv:package )" />
|
||||
|
||||
<message>
|
||||
<text>[preproc/symtable] processing symbol table...</text>
|
||||
</message>
|
||||
|
||||
<variable name="cursym" as="element( preproc:sym )*"
|
||||
select="preproc:symtable/preproc:sym[
|
||||
not( @held = 'true' ) ]" />
|
||||
|
||||
<variable name="cursym-map" as="map( xs:string, element( preproc:sym ) )"
|
||||
select="map:merge(
|
||||
for $sym in $cursym
|
||||
return map{ string( $sym/@name ) : $sym } )" />
|
||||
|
||||
<variable name="extresults-map" as="map( xs:string, element( preproc:sym ) )"
|
||||
select="map:merge(
|
||||
for $sym in $extresults/preproc:sym
|
||||
return map{ string( $sym/@name ) : $sym } )" />
|
||||
|
||||
<!-- contains duplicates -->
|
||||
<variable name="new-seq-map" as="map( xs:string, element( preproc:sym )+ )"
|
||||
select="map:merge(
|
||||
for $sym in $new/preproc:sym
|
||||
return map{ string( $sym/@name ) : $sym },
|
||||
map{ 'duplicates' : 'combine' } )" />
|
||||
|
||||
<variable name="new-overrides-map" as="map( xs:string, element( preproc:sym ) )"
|
||||
select="map:merge(
|
||||
for $sym in $new/preproc:sym[ @override = 'true' ]
|
||||
return map{ string( $sym/@name ) : $sym } )" />
|
||||
|
||||
<preproc:syms>
|
||||
<variable name="cursym" as="element( preproc:sym )*"
|
||||
select="preproc:symtable/preproc:sym[
|
||||
not( @held = 'true' ) ]" />
|
||||
|
||||
<sequence select="$cursym" />
|
||||
|
||||
<message>
|
||||
<text>[preproc/symtable] processing symbol table...</text>
|
||||
</message>
|
||||
|
||||
<for-each select="$new/preproc:sym[ not( @extern='true' and @src ) ]">
|
||||
<variable name="name" select="@name" />
|
||||
<variable name="src" select="@src" />
|
||||
<variable name="dupall" select="
|
||||
(
|
||||
preceding-sibling::preproc:sym,
|
||||
$cursym,
|
||||
$extresults/preproc:sym
|
||||
)[
|
||||
@name=$name
|
||||
]
|
||||
" />
|
||||
<variable name="dup" select="
|
||||
$dupall[
|
||||
not(
|
||||
@src=$src
|
||||
or ( not( @src ) and not( $src ) )
|
||||
)
|
||||
]
|
||||
" />
|
||||
|
||||
<variable name="dupall" as="element( preproc:sym )*"
|
||||
select="$cursym-map( $name ),
|
||||
$extresults-map( $name ),
|
||||
if ( count( $new-seq-map( $name ) ) gt 1 ) then
|
||||
preceding-sibling::preproc:sym[ @name = $name ]
|
||||
else
|
||||
()" />
|
||||
|
||||
<variable name="override" as="element( preproc:sym )?"
|
||||
select="$new-overrides-map( @name )" />
|
||||
|
||||
<choose>
|
||||
<when test="@pollute='true' and not( @type )">
|
||||
|
@ -476,9 +510,7 @@
|
|||
<sequence select="." />
|
||||
</when>
|
||||
|
||||
<!-- note that dupall uses preceding-sibling, which will catch
|
||||
duplicates in that case even if @override is not set -->
|
||||
<when test="following-sibling::preproc:sym[ @name=$name and @override='true' ]">
|
||||
<when test="exists( $override ) and not( $override is . )">
|
||||
<!-- overridden; we're obsolete :( -->
|
||||
</when>
|
||||
|
||||
|
@ -509,6 +541,8 @@
|
|||
</choose>
|
||||
</for-each>
|
||||
</preproc:syms>
|
||||
|
||||
<message select="'[preproc/symtable] done processing symbol table.'" />
|
||||
</template>
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue