Return map symbol support

This is a backwards-incompatible change that, like the input map,
requires the use of symbols in the return map.  This will allow us to
forego the use of @keep and will have the return map be the authority
of what gets linked (all of its dependencies).

* src/current/compiler/map.xsl: Add symbol support to return-map.
master
Mike Gerwitz 2017-07-12 14:23:26 -04:00
parent 5b9cfaec31
commit 7472cb882c
1 changed files with 122 additions and 61 deletions

View File

@ -27,6 +27,9 @@
When linking, the special head and tail fragments of the topmost map should be When linking, the special head and tail fragments of the topmost map should be
used (that is, if A includes B and C, use A). used (that is, if A includes B and C, use A).
TODO: Just generate a normal package and use the package system;
this duplicates a lot of logic, and does so piecemeal and poorly.
XXX: This is tightly coupled with the Program UI; refactor to support any type XXX: This is tightly coupled with the Program UI; refactor to support any type
of source. of source.
--> -->
@ -91,10 +94,15 @@
consistently with the rest of the system --> consistently with the rest of the system -->
<variable name="pkg"> <variable name="pkg">
<lv:package name="{$__srcpkg}" lvmc:type="map"> <lv:package name="{$__srcpkg}" lvmc:type="map">
<!-- XXX: copied from expand.xsl! -->
<attribute name="name" select="$__srcpkg" />
<attribute name="__rootpath" select="$__relroot" />
<attribute name="preproc:name" select="$__srcpkg" />
<!-- initial symbol table; full table will be generated below --> <!-- initial symbol table; full table will be generated below -->
<call-template name="lvmc:stub-symtable"> <call-template name="lvmc:stub-symtable">
<with-param name="type-prefix" select="'map'" /> <with-param name="type-prefix" select="'map'" />
</call-template> </call-template>
<!-- copy all source nodes --> <!-- copy all source nodes -->
<sequence select="node()" /> <sequence select="node()" />
@ -145,6 +153,8 @@
<!-- <!--
Generate a function that maps a set of rater outputs Generate a function that maps a set of rater outputs
TODO: This is essentailly the same as the input map; refactor.
--> -->
<template match="lvm:return-map" mode="lvmc:compile" priority="8"> <template match="lvm:return-map" mode="lvmc:compile" priority="8">
<param name="rater" /> <param name="rater" />
@ -157,46 +167,60 @@
<variable name="pkg"> <variable name="pkg">
<lv:package name="{$__srcpkg}" lvmc:type="retmap"> <lv:package name="{$__srcpkg}" lvmc:type="retmap">
<!-- XXX: copied from expand.xsl! -->
<attribute name="name" select="$__srcpkg" />
<attribute name="__rootpath" select="$__relroot" />
<attribute name="preproc:name" select="$__srcpkg" />
<!-- initial symbol table; full table will be generated below --> <!-- initial symbol table; full table will be generated below -->
<call-template name="lvmc:stub-symtable"> <call-template name="lvmc:stub-symtable">
<with-param name="type-prefix" select="'retmap'" /> <with-param name="type-prefix" select="'retmap'" />
</call-template> </call-template>
<!-- copy source data --> <!-- copy source nodes -->
<copy-of select="*" /> <apply-templates mode="preproc:expand" select="node()" />
<preproc:fragments>
<!-- special fragment to be output as the head -->
<preproc:fragment id=":retmap:___head">
<!-- use a callback just in case we need to make portions of this async in the
future -->
<text>function ( input, callback ) {</text>
<text>var output = {};</text>
</preproc:fragment>
<apply-templates select="./lvm:*" mode="lvmc:compile">
<with-param name="symtable" select="$dummy-symtable" />
<with-param name="rater" select="$rater" />
<with-param name="type" select="'retmap'" />
</apply-templates>
<!-- special fragment to be output as the foot -->
<preproc:fragment id=":retmap:___tail">
<text>callback(output);</text>
<text>}</text>
</preproc:fragment>
</preproc:fragments>
</lv:package> </lv:package>
</variable> </variable>
<!-- output the result after symbol processing --> <!-- process symbol table -->
<call-template name="preproc:gen-deps"> <variable name="pkg-with-symtable" as="element( lv:package )">
<with-param name="pkg" as="element( lv:package )"> <call-template name="preproc:gen-deps">
<apply-templates select="$pkg" mode="preproc:sym-discover"> <with-param name="pkg" as="element( lv:package )">
<with-param name="orig-root" select="." /> <apply-templates select="$pkg" mode="preproc:sym-discover">
<with-param name="orig-root" select="." />
</apply-templates>
</with-param>
</call-template>
</variable>
<!-- final result with compiled fragments -->
<lv:package>
<sequence select="$pkg-with-symtable/@*,
$pkg-with-symtable/node()" />
<preproc:fragments>
<!-- special fragment to be output as the head -->
<preproc:fragment id=":retmap:___head">
<!-- use a callback just in case we need to make portions of this async in the
future -->
<text>function( input, callback ) {</text>
<text>var output = {};</text>
</preproc:fragment>
<!-- compile mapped -->
<apply-templates select="./lvm:*" mode="lvmc:compile">
<with-param name="symtable" select="$pkg-with-symtable/preproc:symtable" />
<with-param name="rater" select="$rater" />
<with-param name="type" select="'retmap'" />
</apply-templates> </apply-templates>
</with-param>
</call-template> <!-- special fragment to be output as the foot -->
<preproc:fragment id=":retmap:___tail">
<text>callback(output);</text>
<text>};</text>
</preproc:fragment>
</preproc:fragments>
</lv:package>
</template> </template>
@ -210,6 +234,7 @@
same (future bug pending!) --> same (future bug pending!) -->
<preproc:sym name=":{$type-prefix}:___head" <preproc:sym name=":{$type-prefix}:___head"
type="{$type-prefix}:head" type="{$type-prefix}:head"
pollute="true"
ignore-dup="true" /> ignore-dup="true" />
<preproc:sym name=":{$type-prefix}:___tail" <preproc:sym name=":{$type-prefix}:___tail"
type="{$type-prefix}:tail" type="{$type-prefix}:tail"
@ -248,15 +273,15 @@
--> -->
<template match="lvm:pass" mode="lvmc:compile" priority="5"> <template match="lvm:pass" mode="lvmc:compile" priority="5">
<param name="symtable" as="element( preproc:symtable )" /> <param name="symtable" as="element( preproc:symtable )" />
<param name="type" /> <param name="type" as="xs:string" />
<preproc:fragment id=":{$type}:{@name}"> <preproc:fragment id=":{$type}:{@name}">
<text>output['</text> <text>output['</text>
<value-of select="@name" /> <value-of select="@name" />
<text>']=</text> <text>']=</text>
<call-template name="lvmc:gen-input-default"> <call-template name="lvmc:gen-input-default">
<with-param name="symtable" select="$symtable" /> <with-param name="sym"
<with-param name="to" select="@name" /> select="lvmc:get-symbol( $symtable, $type, @name, @name )" />
<with-param name="from" select="@name" /> <with-param name="from" select="@name" />
</call-template> </call-template>
<text>;</text> <text>;</text>
@ -303,8 +328,8 @@
<value-of select="@to" /> <value-of select="@to" />
<text>']=</text> <text>']=</text>
<call-template name="lvmc:gen-input-default"> <call-template name="lvmc:gen-input-default">
<with-param name="symtable" select="$symtable" /> <with-param name="sym"
<with-param name="to" select="@to" /> select="lvmc:get-symbol( $symtable, $type, @to, @from )" />
<with-param name="from" select="@from" /> <with-param name="from" select="@from" />
</call-template> </call-template>
<text>;</text> <text>;</text>
@ -324,14 +349,14 @@
</template> </template>
<template match="lvm:map[ @from <template match="lvm:map[ @from
and root(.)/@lvmc:type = 'map' ]" and root(.)/@lvmc:type = 'map' ]"
mode="preproc:depgen" priority="5"> mode="preproc:depgen" priority="5">
<!-- to the DSL --> <!-- to the DSL -->
<preproc:sym-ref name="{@to}" lax="true" /> <preproc:sym-ref name="{@to}" lax="true" />
</template> </template>
<template match="lvm:map[ @from <template match="lvm:map[ @from
and root(.)/@lvmc:type = 'retmap' ]" and root(.)/@lvmc:type = 'retmap' ]"
mode="preproc:depgen" priority="5"> mode="preproc:depgen" priority="5">
<!-- from the DSL --> <!-- from the DSL -->
<preproc:sym-ref name="{@from}" lax="true" /> <preproc:sym-ref name="{@from}" lax="true" />
@ -403,28 +428,48 @@
</template> </template>
<!--
Attempt to locate the expected symbol, and blow up otherwise.
TODO: The retmap distinction muddies this; refactor to be agnostic
(onus on caller perhaps).
-->
<function name="lvmc:get-symbol" as="element( preproc:sym )?">
<param name="symtable" as="element( preproc:symtable )" />
<param name="type" as="xs:string" />
<param name="to" as="xs:string" />
<param name="from" as="xs:string?" />
<variable name="symname" as="xs:string?"
select="if ( $type = 'retmap' ) then $from else $to" />
<variable name="sym" as="element( preproc:sym )?"
select="$symtable/preproc:sym[ @name=$symname and @src ]" />
<!-- for error message display -->
<variable name="srcdest" as="xs:string"
select="if ( $type = 'retmap' ) then 'source' else 'destination'" />
<if test="$symname and not( $sym ) and not( $symtable/@lvmc:sym-ignore )">
<message terminate="yes"
select="concat(
'error: unknown ', $srcdest, ' identifier `',
string( $symname ),
''' (did you import the package?)' )" />
</if>
</function>
<!-- <!--
Generate a direct input mapping or, if a default exists for the field, use the Generate a direct input mapping or, if a default exists for the field, use the
default if the input is an empty string default if the input is an empty string.
--> -->
<template name="lvmc:gen-input-default"> <template name="lvmc:gen-input-default">
<param name="symtable" as="element( preproc:symtable )" /> <param name="sym" as="element( preproc:sym )?" />
<param name="to" />
<!-- use one or the other; latter takes precedence --> <!-- use one or the other; latter takes precedence -->
<param name="from" /> <param name="from" />
<param name="from-str" /> <param name="from-str" />
<variable name="sym" as="element( preproc:sym )?"
select="$symtable/preproc:sym[ @name=$to and @src ]" />
<if test="not( $sym ) and not( $symtable/@lvmc:sym-ignore )">
<message terminate="yes"
select="concat(
'error: unknown destination identifier `',
string( $to ),
''' (did you import the package?)' )" />
</if>
<variable name="from-var"> <variable name="from-var">
<choose> <choose>
<when test="$from-str"> <when test="$from-str">
@ -459,7 +504,7 @@
Maps a static value to the output Maps a static value to the output
--> -->
<template match="lvm:map[ @value ]" mode="lvmc:compile" priority="5"> <template match="lvm:map[ @value ]" mode="lvmc:compile" priority="5">
<param name="type" /> <param name="type" as="xs:string" />
<preproc:fragment id=":{$type}:{@to}"> <preproc:fragment id=":{$type}:{@to}">
<text>output['</text> <text>output['</text>
@ -483,7 +528,7 @@
<template match="lvm:map[*]" mode="lvmc:compile" priority="5"> <template match="lvm:map[*]" mode="lvmc:compile" priority="5">
<param name="symtable" as="element( preproc:symtable )" /> <param name="symtable" as="element( preproc:symtable )" />
<param name="rater" /> <param name="rater" />
<param name="type" /> <param name="type" as="xs:string"/>
<preproc:fragment id=":{$type}:{@to}"> <preproc:fragment id=":{$type}:{@to}">
<text>output['</text> <text>output['</text>
@ -493,6 +538,7 @@
<apply-templates select="./lvm:*" mode="lvmc:compile"> <apply-templates select="./lvm:*" mode="lvmc:compile">
<with-param name="symtable" select="$symtable" /> <with-param name="symtable" select="$symtable" />
<with-param name="rater" select="$rater" /> <with-param name="rater" select="$rater" />
<with-param name="type" select="$type" />
</apply-templates> </apply-templates>
<text>;</text> <text>;</text>
@ -606,12 +652,21 @@
<template match="lvm:map//lvm:from[*]" mode="lvmc:compile" priority="5"> <template match="lvm:map//lvm:from[*]" mode="lvmc:compile" priority="5">
<param name="symtable" as="element( preproc:symtable )" /> <param name="symtable" as="element( preproc:symtable )" />
<param name="type" as="xs:string" />
<variable name="to" select="ancestor::lvm:map/@to" /> <variable name="to" select="ancestor::lvm:map/@to" />
<variable name="nested" as="xs:boolean" <variable name="nested" as="xs:boolean"
select="exists( ancestor::lvm:from )" /> select="exists( ancestor::lvm:from )" />
<!-- XXX: we rely on the side-effect of this blowing up if the
symbol does not exist -->
<variable name="sym" as="element( preproc:sym )?"
select="lvmc:get-symbol( $symtable, $type, $to, @name )" />
<!-- kluge to force function call (it's lazy) -->
<if test="not( $sym )" />
<!-- oval = orig val --> <!-- oval = orig val -->
<text>(function(oval){</text> <text>(function(oval){</text>
<text>var val = ( (oval||'').length ) ? oval : [oval]; </text> <text>var val = ( (oval||'').length ) ? oval : [oval]; </text>
@ -631,6 +686,7 @@
<text>switch(''+val[i]){</text> <text>switch(''+val[i]){</text>
<apply-templates mode="lvmc:compile"> <apply-templates mode="lvmc:compile">
<with-param name="symtable" select="$symtable" /> <with-param name="symtable" select="$symtable" />
<with-param name="type" select="$type" />
</apply-templates> </apply-templates>
<if test="not( lvm:default )"> <if test="not( lvm:default )">
@ -646,8 +702,7 @@
<!-- otherwise, generate one --> <!-- otherwise, generate one -->
<otherwise> <otherwise>
<call-template name="lvmc:gen-input-default"> <call-template name="lvmc:gen-input-default">
<with-param name="symtable" select="$symtable" /> <with-param name="sym" select="$sym" />
<with-param name="to" select="$to" />
<with-param name="from-str"> <with-param name="from-str">
<text>''+val[i]</text> <text>''+val[i]</text>
</with-param> </with-param>
@ -706,11 +761,12 @@
<template match="lvm:from/lvm:default" <template match="lvm:from/lvm:default"
mode="lvmc:compile" priority="5"> mode="lvmc:compile" priority="5">
<param name="symtable" as="element( preproc:symtable )" /> <param name="symtable" as="element( preproc:symtable )" />
<param name="type" as="xs:string" />
<sequence select="concat( <sequence select="concat(
'default:ret.push(', 'default:ret.push(',
string-join( string-join(
lvmc:concat-compile( element(), (), $symtable ), lvmc:concat-compile( element(), (), $symtable, $type),
'' ), '' ),
');' )" /> ');' )" />
</template> </template>
@ -724,12 +780,14 @@
<template match="lvm:map//lvm:from/lvm:translate" mode="lvmc:compile" priority="5"> <template match="lvm:map//lvm:from/lvm:translate" mode="lvmc:compile" priority="5">
<param name="symtable" as="element( preproc:symtable )" /> <param name="symtable" as="element( preproc:symtable )" />
<param name="type" as="xs:string" />
<text>case '</text> <text>case '</text>
<value-of select="@key" /> <value-of select="@key" />
<text>':</text> <text>':</text>
<apply-templates select="." mode="lvmc:compile-translate"> <apply-templates select="." mode="lvmc:compile-translate">
<with-param name="symtable" select="$symtable" /> <with-param name="symtable" select="$symtable" />
<with-param name="type" select="$type" />
</apply-templates> </apply-templates>
<text> break;</text> <text> break;</text>
</template> </template>
@ -738,11 +796,12 @@
<template match="lvm:translate[ element() ]" <template match="lvm:translate[ element() ]"
mode="lvmc:compile-translate" priority="5"> mode="lvmc:compile-translate" priority="5">
<param name="symtable" as="element( preproc:symtable )" /> <param name="symtable" as="element( preproc:symtable )" />
<param name="type" as="xs:string" />
<sequence select="concat( <sequence select="concat(
'ret.push(', 'ret.push(',
string-join( string-join(
lvmc:concat-compile( element(), @empty, $symtable ), lvmc:concat-compile( element(), @empty, $symtable, $type ),
'' ), '' ),
');' )" /> ');' )" />
</template> </template>
@ -752,6 +811,7 @@
<param name="children" as="element()+" /> <param name="children" as="element()+" />
<param name="default" as="xs:string?" /> <param name="default" as="xs:string?" />
<param name="symtable" as="element( preproc:symtable )" /> <param name="symtable" as="element( preproc:symtable )" />
<param name="type" as="xs:string" />
<text>(function(){</text> <text>(function(){</text>
<!-- end result should compile into a (dynamic) string --> <!-- end result should compile into a (dynamic) string -->
@ -763,6 +823,7 @@
<apply-templates mode="lvmc:compile" select="."> <apply-templates mode="lvmc:compile" select=".">
<with-param name="symtable" select="$symtable" /> <with-param name="symtable" select="$symtable" />
<with-param name="type" select="$type" />
</apply-templates> </apply-templates>
</for-each> </for-each>
<text>;</text> <text>;</text>