Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@rtspecialty.com>2019-02-20 00:26:32 -0500
committerMike Gerwitz <mike.gerwitz@rtspecialty.com>2019-02-20 00:26:32 -0500
commit16749a9a45cbd9c4e93b6635e1983a927ffd6711 (patch)
treecf4942c292123edc802bc9f39220cd92f948a374 /src
parentdae1990a00add344155d3fd55291a667d311a115 (diff)
downloadtame-16749a9a45cbd9c4e93b6635e1983a927ffd6711.tar.gz
tame-16749a9a45cbd9c4e93b6635e1983a927ffd6711.tar.bz2
tame-16749a9a45cbd9c4e93b6635e1983a927ffd6711.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/current/compiler/fragments.xsl161
-rw-r--r--src/current/compiler/js.xsl41
2 files changed, 98 insertions, 104 deletions
diff --git a/src/current/compiler/fragments.xsl b/src/current/compiler/fragments.xsl
index 6a00e4c..7a4cbad 100644
--- a/src/current/compiler/fragments.xsl
+++ b/src/current/compiler/fragments.xsl
@@ -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">
- <variable name="name" select="@name" />
- <variable name="pkg" as="element( lv:package )"
- select="root(.)" />
+<template mode="preproc:compile-fragments" priority="5"
+ match="lv:classify">
+ <preproc:fragment id=":class:{@as}">
+ <apply-templates select="." mode="compile" />
+ </preproc:fragment>
- <!-- 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 -->
+ <apply-templates mode="preproc:compile-fragments" />
</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 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 match="preproc:sym[ @type='cgen' ]" mode="preproc:compile-fragments" priority="5">
- <!-- compiled by above -->
+
+<template mode="preproc:compile-fragments" priority="7"
+ match="lv:function/lv:param">
+ <!-- ignore -->
</template>
-<template match="preproc:sym[ @type='func' ]" mode="preproc:compile-fragments" priority="5">
+
+<template mode="preproc:compile-fragments" priority="5"
+ match="lv:param">
<variable name="name" select="@name" />
<variable name="pkg" as="element( lv:package )"
select="root(.)" />
- <apply-templates select="$pkg/lv:function[ @name=$name ]" mode="compile" />
+ <preproc:fragment id="{@name}">
+ <apply-templates select="." mode="compile" />
+ </preproc:fragment>
</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:typedef">
+ <preproc:fragment id="{@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="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='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="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='tpl' ]" mode="preproc:compile-fragments" priority="5">
- <!-- templates are for the preprocessor only -->
+
+<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='lparam' ]" mode="preproc:compile-fragments" priority="5">
- <!-- they're local and therefore compiled as part of the containing block -->
+
+<template mode="preproc:compile-fragments" priority="7"
+ match="preproc:*">
+ <!-- we don't compile this stuff -->
</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>
diff --git a/src/current/compiler/js.xsl b/src/current/compiler/js.xsl
index 48ed6bc..d2af0bb 100644
--- a/src/current/compiler/js.xsl
+++ b/src/current/compiler/js.xsl
@@ -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="'&amp;&amp;'" />
<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 != ''">