fragment: Iterate over document and use symtable map
Same concept as previous commits: rather than iterating over the symbol table and scanning the tree for the matching node, iterate over the document and look up from a symbol map: O(n²) => O(n). This gives a respectable performance boost to compilation of certain packages (best improving packages with many classifications or rate blocks). * src/current/compiler/fragments.xsl (@xmlns:xs, @xmlns:map): New namespace declarations. (preproc:compile-fragments): Generate `preproc:fragment' nodes and match on document rather than symbols. [lv:package]: Generate map and tunnel it. * src/current/compiler/js.xsl (compile)[lv:classify, lv:match]: Use symtable-map. (compile-class-condition)[lv:rate]: Likewise. (compile-cmatch)[lv:rate]: Likewise.master
parent
dae1990a00
commit
16749a9a45
|
@ -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 != ''">
|
||||
|
|
Loading…
Reference in New Issue