Properly resolve paths of symbols of imports

This solves a long-standing problem whereby relative paths are not
properly resolved, leading to incorrect symbol conflicts when relative
paths to the same package vary between two imports.

See doc/notes/path-processing for an illustration.

* src/current/include/preproc/path.xsl
  (preproc:resolve-relative-import): Add function.
  (preproc:resolv-path, preproc:resolve-path, preproc:get-path): Add
  functions to invoke existing templates.
* src/current/include/preproc/symtable.xsl (preproc:symimport): Use
  `preproc:resolve-relative-import'.
* doc/notes/path-processing: Add notes.
master
Mike Gerwitz 2017-07-12 14:26:30 -04:00
parent 7472cb882c
commit 52c1bb5ebe
3 changed files with 149 additions and 27 deletions

View File

@ -0,0 +1,65 @@
Path processing
---------------
Need rules that will work for both the existing scenario (B) and the new
scenario (A):
_
/ \
/ _ \
/ ___ \
/_/ \_\
---------
root = ../
package = suppliers/colony <--- /suppliers/colony
import = ../map/return/colony <--- /map/return/colony
mapimport = ../../suppliers/colony/gl <-- /suppliers/colony/gl
this is the root
/ \
v v
1) <..>/map/return/ | <..>/../suppliers/colony/gl
= ../suppliers/colony/gl
^^^^^^^^^^^^^^^^
\ /
package name
2) strip root||(package base) from package import
= ../map/return | <../suppliers/>colony/gl
= colony/gl
^^^^^^^^^
` The relative path from package
____
| __ )
| _ \
| |_) |
|____/
-------
what about normal includes?
root = ../
package = suppliers/colony <--- /suppliers/colony
import = ../common/foo <--- /common/foo
subimport = bar/baz <--- /common/foo/bar/baz
one has root, other does not
/
v
1) <..>/common/ | bar/baz
= ../common/bar/baz
2) strip root||(package base) from package import
= ../common/bar/baz
^^^^^^^^^^^^^^^^^
` no such prefix,
so this is the relative path

View File

@ -22,6 +22,7 @@
-->
<stylesheet version="2.0"
xmlns="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:preproc="http://www.lovullo.com/rater/preproc">
@ -59,6 +60,15 @@
</template>
<function name="preproc:get-path" as="xs:string">
<param name="path" />
<call-template name="preproc:get-path">
<with-param name="path" select="$path" />
</call-template>
</function>
<!-- FIXME: duplicate code with above -->
<template name="preproc:get-basename">
<param name="path" />
@ -94,6 +104,7 @@
</template>
<!-- TODO: rename to preproc:resolve-path -->
<template name="preproc:resolv-path">
<param name="path" />
@ -112,6 +123,26 @@
</template>
<function name="preproc:resolv-path" as="xs:string">
<param name="path" />
<variable name="result" as="xs:string*">
<call-template name="preproc:resolv-path">
<with-param name="path" select="$path" />
</call-template>
</variable>
<sequence select="string-join( $result, '' )" />
</function>
<!-- alias to the above -->
<function name="preproc:resolve-path" as="xs:string">
<param name="path" />
<sequence select="preproc:resolv-path( $path )" />
</function>
<!-- XXX: warning, this won't like 'foo../' -->
<template name="preproc:resolv-rel-path">
<param name="path" />
@ -244,4 +275,44 @@
</choose>
</template>
<!--
Resolve relative package imports
This situation arises when a source package (src) imports another
package (src-import) that has a reference to an external symbol
(sub-import).
See /doc/notes/path-processing for an illustration.
-->
<function name="preproc:resolve-relative-import" as="xs:string">
<param name="src-root" as="xs:string" />
<param name="src-name" as="xs:string" />
<param name="src-import" as="xs:string" />
<param name="sub-import" as="xs:string" />
<variable name="src-prefix" as="xs:string"
select="concat( $src-root, '/', $src-name )" />
<!-- Step 1: resolve relative paths from sub-import -->
<variable name="src-import-dir" as="xs:string"
select="preproc:get-path( $src-import )" />
<variable name="sub-concat" as="xs:string"
select="if ( $src-import-dir ) then
preproc:resolve-path(
concat( $src-import-dir, '/', $sub-import ) )
else
$sub-import" />
<!-- Step 2: remove package name prefix, if present -->
<variable name="src-name-base" as="xs:string"
select="preproc:get-path( $src-name )" />
<variable name="src-prefix" as="xs:string"
select="concat( $src-root, $src-name-base, '/' )" />
<variable name="suffix" as="xs:string"
select="substring-after( $sub-concat, $src-prefix )" />
<sequence select="if ( $suffix ) then $suffix else $sub-concat" />
</function>
</stylesheet>

View File

@ -521,12 +521,18 @@
<xsl:param name="no-extclass" select="@no-extclass" />
<xsl:param name="keep-classes" select="@keep-classes" />
<xsl:variable name="path" select="concat( $package, '.xmlo' )" />
<xsl:variable name="path" as="xs:string"
select="concat( $package, '.xmlo' )" />
<xsl:variable name="syms"
select="document( $path, $orig-root )/lv:*/preproc:symtable" />
select="document( $path, $orig-root )/lv:*/preproc:symtable" />
<xsl:variable name="import-path" select="$package" />
<xsl:variable name="src-root" as="xs:string"
select="ancestor::lv:package/@__rootpath" />
<xsl:variable name="src-name" as="xs:string"
select="ancestor::lv:package/@name" />
<!-- if they're including a program package, do they realize what they're
doing!? -->
<!-- FIXME: @allow-nonpkg is no longer accurate terminology; change to
@ -542,14 +548,6 @@
</xsl:message>
</xsl:if>
<!-- determine our path from our name -->
<xsl:variable name="our-path">
<xsl:call-template name="preproc:get-path">
<xsl:with-param name="path"
select="ancestor::lv:package/@name" />
</xsl:call-template>
</xsl:variable>
<!-- to keep everything consistent and to simplify package equality
assertions, resolve relative paths -->
<xsl:variable name="import-default-path" select="$import-path" />
@ -626,23 +624,11 @@
itself) onto the existing relative path and resolving relative
paths -->
<xsl:otherwise>
<xsl:call-template name="preproc:resolv-path">
<xsl:with-param name="path">
<!-- get the path of the import, sans package name -->
<xsl:variable name="path">
<xsl:call-template name="preproc:get-path">
<xsl:with-param name="path" select="$import-path" />
</xsl:call-template>
</xsl:variable>
<!-- concatenate it with the existing relative path -->
<xsl:if test="not( $path = '' )">
<xsl:value-of select="concat( $path, '/' )" />
</xsl:if>
<xsl:value-of select="@src" />
</xsl:with-param>
</xsl:call-template>
<xsl:sequence select="preproc:resolve-relative-import(
$src-root,
$src-name,
$import-path,
@src )" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>