<
xsl:
stylesheet xmlns:src="
http://www.sdml.info/srcML/src"
xmlns:cpp="
http://www.sdml.info/srcML/cpp"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform"
xmlns:saxon="
http://saxon.sf.net/"
xmlns:xd="
http://www.pnp-software.com/XSLTdoc"
xmlns:util="
http://www.pnp-software.com/util"
xmlns:ax="
http://control.ee.ethz.ch/XWeaver/AspectX"
xmlns:xslt="
http://xslt"
version="
2.0"
exclude-result-prefixes="
xsl">
<
xd:
doc type="
stylesheet">
<
xd:
short>
AspectX Compiler</
xd:
short>
<
xd:
detail>
This XSL stylesheet compiles a program written in
<
a href="
../AspectX/LanguageGuide.html">
AspectX</
a>
into an XSL stylesheet.
The resulting stylesheet is able to add advice elements to
<
a href="
http://www.sdml.info/projects/srcml/">
srcML</
a>
base
code. See templates documentation (especially the root template) for a more detailed description.</
xd:
detail>
<
xd:
cvsId>
$Id: axc.xsl 138 2005-07-27 09:14:07Z ibirrer $</
xd:
cvsId>
<
xd:
author>
ibirrer</
xd:
author>
<
xd:
copyright>
2005, P&P Software GmbH</
xd:
copyright>
</
xd:
doc>
<!---->
<
xsl:
output method="
xml"
indent="
no" />
<
xsl:
preserve-space elements="
xsl:text" />
<
xsl:
strip-space elements="
*" />
<!---->
<
xsl:
include href="
util.xsl" />
<!---->
<
xsl:
namespace-alias stylesheet-prefix="
xslt"
result-prefix="
xsl" />
<!---->
<
xd:
doc>
<
xd:
short>
Main Root template</
xd:
short>
<
xd:
detail>
Resolves any includes and hands the resulting file to the templates with mode <
code>
compiler</
code>
.
Resolving includes is done by templates with mode <
code>
resolveIncludes</
code>
.
</
xd:
detail>
</
xd:
doc>
<
xsl:
template match="
/">
<!---->
<
xsl:
variable name="
resolvedAspect">
<
xsl:
apply-templates select="
."
mode="
resolveIncludes" />
</
xsl:
variable>
<
xsl:
apply-templates select="
$resolvedAspect"
mode="
compiler" />
</
xsl:
template>
<
xd:
doc>
Default copy template to resolve Includes in aspects.
</
xd:
doc>
<
xsl:
template match="
*"
mode="
resolveIncludes">
<
xsl:
copy>
<
xsl:
copy-of select="
@*" />
<
xsl:
apply-templates mode="
resolveIncludes" />
</
xsl:
copy>
</
xsl:
template>
<
xd:
doc>
Resolve includes. Replaces include elements by all contents (pointcuts, advices) of the aspect it refers to.
</
xd:
doc>
<
xsl:
template match="
ax:include"
mode="
resolveIncludes">
<
xsl:
apply-templates select="
document(@href)/ax:aspect/*"
mode="
resolveIncludes" />
</
xsl:
template>
<
xd:
doc>
Add apspect attribute to named pointcut elements and pointcutRef elements. If an aspect attribute already exists
it is not replaces.
</
xd:
doc>
<
xsl:
template match="
ax:pointcut[@name] | ax:pointcutRef"
mode="
resolveIncludes">
<
xsl:
copy>
<
xsl:
copy-of select="
@*" />
<
xsl:
if test="
not(@aspect)">
<
xsl:
attribute name="
aspect"
select="
/ax:aspect/@name" />
</
xsl:
if>
<
xsl:
apply-templates mode="
resolveIncludes" />
</
xsl:
copy>
</
xsl:
template>
<!---->
<
xd:
doc>
<
xd:
short>
Builds the general structure of the locator stylesheet.
</
xd:
short>
<
xd:
detail>
Procedure:
<
ul>
<
li>
1. Find all anonymous pointcut and pointcutRef elements used for advices.
These are all pointcut and pointcutRef elements definded as a direct child
of an advice. Descendants of these are not inlcuded, neither are named pointcuts.
</
li>
<
li>
2. Group the elements found by the type attribute. This means that a group consists of
pointcut or pointcutRef elements which have the same value for the type attribute. Then iterate through the
groups (Each group is processed once).</
li>
<
ul>
<
li>
2.1 Build an unnamed template for each group. The match attribute value is set to the common type
attribute value of the group.</
li>
<
li>
2.2 Iterate through all distinct pointcutRef (a pointcutRef element is equal
with another if their ref attribute value is equal) elements and all pointcut elements
in the group.</
li>
<
ul>
<
li>
2.2.1 Build an if statement for each group</
li>
<
li>
2.2.2 Generate the XPath expression from the pointcut (Using the first pointcut in the group).
This uses templates with mode <
code>
pointcutXPath</
code>
. PoinctutRef elements are translated to
their corresponding pointcut element in a template with mode <
code>
pointcutXPath</
code>
.</
li>
<
li>
2.2.3 Find all advices which use any of the pointcuts or pointcutRef's in the group and copy them.
(These are the advices which are direct parents of a pointcut or pointcutRef)</
li>
</
ul>
</
ul>
</
ul>
A pointcut type always directly refers to a specific srcML element. Therefore a template generated for a pointuct of type <
code>
src:class</
code>
,
is processed for each <
code>
src:class</
code>
element in the srcML base code. Because all <
code>
src:class</
code>
elements are processed
by this template the template logic needs to decide if an advice should be added to a specific <
code>
src:class</
code>
element. This is achieved
by generating several <
code>
xsl:if</
code>
clauses inside the template. Each <
code>
xsl:if</
code>
tests if a pointcut matches the srcML element currently
processed. Note that <
code>
xsl:choose</
code>
would not work for this purpose as it would only allow one pointcut to match one srcML element but of course there can be several pointcuts that match one
srcML element (=pointcut type). Generating the test attribute of the <
code>
xsl:if</
code>
clause is done by several templates with the mode pointcutXPath (See also
stylesheets in compilerRules/restrictions).
</
xd:
detail>
</
xd:
doc>
<
xsl:
template match="
/"
mode="
compiler">
<
xslt:
stylesheet version="
2.0">
<
xslt:
include href="
util.xsl" />
<
xslt:
preserve-space elements="
*" />
<!---->
<
xslt:
template match="
*">
<
xslt:
copy>
<
xslt:
copy-of select="
@*" />
<
xslt:
apply-templates />
</
xslt:
copy>
</
xslt:
template>
<!---->
<
xsl:
for-each-group select="
ax:aspect/ax:advice/ax:pointcut | ax:aspect/ax:advice/ax:pointcutRef"
group-by="
@type">
<
xsl:
comment><
xsl:
value-of select="
@type" /></
xsl:
comment>
<!---->
<
xslt:
template match="
{@type}">
<!---->
<
xsl:
variable name="
srcMLElement">
<
xsl:
element name="
{@type}" />
</
xsl:
variable>
<
xsl:
apply-templates select="
$srcMLElement"
mode="
commonVariableDeclarations" />
<
xsl:
apply-templates select="
$srcMLElement"
mode="
variableDeclarations" />
<
xslt:
copy>
<
xslt:
copy-of select="
@*" />
<!---->
<
xsl:
for-each-group select="
current-group()"
group-by="
concat(@ref, generate-id(self::ax:pointcut))">
<
xsl:
comment><
xsl:
value-of select="
concat(' ', name(),' ', @type, ', ' , @ref )" /></
xsl:
comment>
<!---->
<
xslt:
if>
<
xsl:
attribute name="
test">
<!---->
<
xsl:
variable name="
xpath">
<
xsl:
apply-templates select="
current-group()[1]"
mode="
pointcutXPath" />
</
xsl:
variable>
<!---->
<
xsl:
choose>
<
xsl:
when test="
normalize-space($xpath) != ''">
<
xsl:
value-of select="
$xpath" />
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
text>
true()</
xsl:
text>
</
xsl:
otherwise>
</
xsl:
choose>
</
xsl:
attribute>
<!---->
<!---->
<
xsl:
for-each select="
current-group()">
<
xsl:
comment><
xsl:
value-of select="
concat(' ', name(parent::ax:advice),' ', parent::ax:advice/@type, ', ' , parent::ax:advice/@name )" /></
xsl:
comment>
<
ax:
advice>
<
xsl:
attribute name="
line"
select="
'{saxon:line-number() - 1}'" />
<
xsl:
copy-of select="
parent::ax:advice/@*" />
<
xsl:
apply-templates select="
parent::ax:advice/node()"
mode="
replaceDollarVariables" />
</
ax:
advice>
</
xsl:
for-each>
</
xslt:
if>
</
xsl:
for-each-group>
<
xslt:
apply-templates />
</
xslt:
copy>
</
xslt:
template>
</
xsl:
for-each-group>
</
xslt:
stylesheet>
</
xsl:
template>
<!---->
<
xd:
doc>
element: ax:pointcut
parent: none
constraint: none or empty
</
xd:
doc>
<
xsl:
template match="
ax:pointcut[not(parent::ax:restriction) and ( not(@constraint) or string-length(replace(@constraint, '^[ \t]+|[ \t]+$', '')) = 0 )]"
mode="
pointcutXPath">
<
xsl:
choose>
<
xsl:
when test="
*[not(self::ax:description)]">
<!---->
<
xsl:
apply-templates mode="
pointcutXPath" />
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
text>
true()</
xsl:
text>
</
xsl:
otherwise>
</
xsl:
choose>
</
xsl:
template>
<
xd:
doc>
element: ax:pointcut
parent: none
constraint: yes (not empty)
</
xd:
doc>
<
xsl:
template match="
ax:pointcut[not(parent::ax:restriction) and @constraint and string-length(replace(@constraint, '^[ \t]+|[ \t]+$', '')) != 0]"
mode="
pointcutXPath">
<!---->
<
xsl:
value-of select="
concat('(', @constraint, ')')" />
<!---->
<
xsl:
choose>
<
xsl:
when test="
*[not(self::ax:description)]">
<!---->
<
xsl:
text>
and (</
xsl:
text><
xsl:
apply-templates mode="
pointcutXPath" /><
xsl:
text>
)</
xsl:
text>
</
xsl:
when>
</
xsl:
choose>
</
xsl:
template>
<
xd:
doc>
Empty template to exclude description and text elements from the XPath creation for pointcuts.</
xd:
doc>
<
xsl:
template match="
ax:description | text()"
mode="
pointcutXPath" />
<
xd:
doc>
element: ax:pointcut
parent: yes
constraint: none or empty
</
xd:
doc>
<
xsl:
template match="
ax:pointcut[parent::ax:restriction and ( not(@constraint) or string-length(replace(@constraint, '^[ \t]+|[ \t]+$', '')) = 0 )]"
mode="
pointcutXPath">
<!---->
<
xsl:
value-of select="
@type" />
<
xsl:
choose>
<
xsl:
when test="
*[not(self::ax:description)]">
<!---->
<
xsl:
text>
[</
xsl:
text><
xsl:
apply-templates mode="
pointcutXPath" /><
xsl:
text>
]</
xsl:
text>
</
xsl:
when>
</
xsl:
choose>
</
xsl:
template>
<
xd:
doc>
element: ax:pointcut
parent: yes
constraint: yes (not empty)
</
xd:
doc>
<
xsl:
template match="
ax:pointcut[parent::ax:restriction and @constraint and string-length(replace(@constraint, '^[ \t]+|[ \t]+$', '')) != 0]"
mode="
pointcutXPath">
<!---->
<
xsl:
value-of select="
@type" />
<
xsl:
text>
[(</
xsl:
text><
xsl:
value-of select="
@constraint" /><
xsl:
text>
)</
xsl:
text>
<
xsl:
choose>
<
xsl:
when test="
*[not(self::ax:description)]">
<!---->
<
xsl:
text>
and (</
xsl:
text><
xsl:
apply-templates select="
*[not(self::ax:description)]"
mode="
pointcutXPath" /><
xsl:
text>
)</
xsl:
text>
</
xsl:
when>
</
xsl:
choose>
<
xsl:
text>
]</
xsl:
text>
</
xsl:
template>
<
xd:
doc>
A reference to a pointcut is resolved to the corresponding
pointcut. This pointcut is then again applied to the templates
taking a pointcut to generate the XPath expression.
In this case the parent element is a restriction and therefore
the type of the pointcut needs to be output.
</
xd:
doc>
<
xsl:
template match="
ax:pointcutRef[parent::ax:restriction]"
mode="
pointcutXPath">
<
xsl:
variable name="
aspectRef"
select="
@aspect" />
<
xsl:
variable name="
pointcutRef"
select="
@ref" />
<
xsl:
variable name="
pointcut"
select="
/ax:aspect/ax:pointcut[@name=$pointcutRef and @aspect = $aspectRef]" />
<
xsl:
if test="
count($pointcut) <=0">
<
xsl:
message terminate="
yes">
[ERROR] Cannot find pointcut with name <
xsl:
value-of select="
@ref" />
in aspect <
xsl:
value-of select="
@aspect" />
.</
xsl:
message>
</
xsl:
if>
<
xsl:
value-of select="
@type" />
<
xsl:
text>
[</
xsl:
text><
xsl:
apply-templates select="
$pointcut"
mode="
pointcutXPath" /><
xsl:
text>
]</
xsl:
text>
</
xsl:
template>
<
xd:
doc>
A reference to a pointcut is resolved to the corresponding
pointcut. This pointcut is then again applied to the templates
taking a pointcut to generate the XPath expression.
</
xd:
doc>
<
xsl:
template match="
ax:pointcutRef[not(parent::ax:restriction)]"
mode="
pointcutXPath">
<
xsl:
variable name="
aspectRef"
select="
@aspect" />
<
xsl:
variable name="
pointcutRef"
select="
@ref" />
<
xsl:
variable name="
pointcut"
select="
/ax:aspect/ax:pointcut[@name=$pointcutRef and @aspect = $aspectRef]" />
<
xsl:
if test="
count($pointcut) <=0">
<
xsl:
message terminate="
yes">
[ERROR] Cannot find pointcut with name <
xsl:
value-of select="
@ref" />
in aspect <
xsl:
value-of select="
@aspect" />
.</
xsl:
message>
</
xsl:
if>
<
xsl:
apply-templates select="
$pointcut"
mode="
pointcutXPath" />
</
xsl:
template>
<
xd:
doc>
Template rule for not
</
xd:
doc>
<
xsl:
template match="
ax:not"
mode="
pointcutXPath">
<
xsl:
text>
not( </
xsl:
text>
<
xsl:
variable name="
xpath">
<
xsl:
apply-templates select="
*"
mode="
pointcutXPath" />
</
xsl:
variable>
<
xsl:
choose>
<
xsl:
when test="
normalize-space($xpath) != ''">
<
xsl:
text>
(</
xsl:
text><
xsl:
value-of select="
$xpath" /><
xsl:
text>
)</
xsl:
text>
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
text>
(true())</
xsl:
text>
</
xsl:
otherwise>
</
xsl:
choose>
<
xsl:
text>
)</
xsl:
text>
</
xsl:
template>
<
xd:
doc>
Template rule for and
</
xd:
doc>
<
xsl:
template match="
ax:and"
mode="
pointcutXPath">
<
xsl:
for-each select="
*">
<
xsl:
if test="
position() > 1">
<
xsl:
text>
and </
xsl:
text>
</
xsl:
if>
<
xsl:
variable name="
xpath">
<
xsl:
apply-templates select="
."
mode="
pointcutXPath" />
</
xsl:
variable>
<
xsl:
choose>
<
xsl:
when test="
normalize-space($xpath) != ''">
<
xsl:
text>
(</
xsl:
text><
xsl:
value-of select="
$xpath" /><
xsl:
text>
)</
xsl:
text>
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
text>
(true())</
xsl:
text>
</
xsl:
otherwise>
</
xsl:
choose>
</
xsl:
for-each>
</
xsl:
template>
<
xd:
doc>
Template rule for or
</
xd:
doc>
<
xsl:
template match="
ax:or"
mode="
pointcutXPath">
<
xsl:
for-each select="
*">
<
xsl:
if test="
position() > 1">
<
xsl:
text>
or </
xsl:
text>
</
xsl:
if>
<
xsl:
variable name="
xpath">
<
xsl:
apply-templates select="
."
mode="
pointcutXPath" />
</
xsl:
variable>
<
xsl:
choose>
<
xsl:
when test="
normalize-space($xpath) != ''">
<
xsl:
text>
(</
xsl:
text><
xsl:
value-of select="
$xpath" /><
xsl:
text>
)</
xsl:
text>
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
text>
(true())</
xsl:
text>
</
xsl:
otherwise>
</
xsl:
choose>
</
xsl:
for-each>
</
xsl:
template>
<
xd:
doc>
If an unsupported element is encountered, the program aborts and outputs an errror message.
</
xd:
doc>
<
xsl:
template match="
*"
mode="
pointcutXPath">
<
xsl:
choose>
<
xsl:
when test="
self::ax:restriction">
<
xsl:
message terminate="
yes">
ERROR: Restriction elements of type '<
xsl:
value-of select="
@type" />
' are not supported. ( File: <
xsl:
value-of select="
base-uri(.)" />
)</
xsl:
message>
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
message terminate="
yes">
ERROR: '<
xsl:
value-of select="
name(.)" />
' elements are not supported. ( File: <
xsl:
value-of select="
base-uri(.)" />
) </
xsl:
message>
</
xsl:
otherwise>
</
xsl:
choose>
</
xsl:
template>
<!---->
<
xd:
doc>
Removing xsl elements. children of xsl elements are processed further.
</
xd:
doc>
<
xsl:
template match="
ax:xsl"
mode="
replaceDollarVariables">
<
ax:
text>
<
xsl:
copy-of select="
child::node()" />
</
ax:
text>
</
xsl:
template>
<
xd:
doc>
Removing description elements completely
</
xd:
doc>
<
xsl:
template match="
ax:description"
mode="
replaceDollarVariables">
</
xsl:
template>
<
xd:
doc>
<
xd:
short>
Replaces variables used in codeModifiers (format: ${VariableName})with the <xsl:value-of .../> equivalent. </
xd:
short>
<
xd:
detail>
This template uses regular expression of XSLT 2.0. Using <
code>
<![[CDATA[</
code>
sections makes it possible to generate new xsl elements.
If a dollarVariable is written in the form ${ var}, the space between the opening curly brace and the
closing curly brace is added to variable as indentation. This is especially useful for the dollar variables
$functionBody in an 'around' advice.
</
xd:
detail>
</
xd:
doc>
<
xsl:
template match="
ax:text/text()"
mode="
replaceDollarVariables">
<
xsl:
variable name="
string"
select="
." />
<
xsl:
variable name="
startCData"><
xsl:
text disable-output-escaping="
yes">
<xsl:text><![CDATA[</
xsl:
text></
xsl:
variable>
<
xsl:
variable name="
endCData"><
xsl:
text disable-output-escaping="
yes">
]]></xsl:text></
xsl:
text></
xsl:
variable>
<
xsl:
variable name="
regexp"
select="
'\$\{(\s*)([^$^\{^\}^\s]*)\}'" />
<
xsl:
variable name="
replacedString">
<
xsl:
analyze-string select="
$string"
regex="
{$regexp}">
<
xsl:
matching-substring>
<
xsl:
variable name="
str1"
select="
regex-group(1)" />
<
xsl:
variable name="
str2"
select="
regex-group(2)" />
<
xsl:
value-of select="
$endCData" />
<
xsl:
text>
<xsl:value-of select="util:indentText( $</
xsl:
text>
<
xsl:
value-of select="
$str2" />
<
xsl:
text>
, '</
xsl:
text>
<
xsl:
value-of select="
replace( $str1, ' ', '&#x9;' )" />
<
xsl:
text>
' )"/></
xsl:
text>
<
xsl:
value-of select="
$startCData" />
</
xsl:
matching-substring>
<
xsl:
non-matching-substring>
<
xsl:
value-of select="
." />
</
xsl:
non-matching-substring>
</
xsl:
analyze-string>
</
xsl:
variable>
<
xsl:
value-of disable-output-escaping="
yes"
select="
$startCData" />
<
xsl:
value-of disable-output-escaping="
yes"
select="
$replacedString" />
<
xsl:
value-of disable-output-escaping="
yes"
select="
$endCData" />
</
xsl:
template>
<
xd:
doc>
Standard template for replacing dollar variables.
</
xd:
doc>
<
xsl:
template match="
*"
mode="
replaceDollarVariables">
<
xsl:
copy>
<
xsl:
copy-of select="
@*" />
<
xsl:
apply-templates mode="
replaceDollarVariables" />
</
xsl:
copy>
</
xsl:
template>
<
xd:
doc>
Do not do anything, as there are maybe no variable declaration for a particular srcML element.
</
xd:
doc>
<
xsl:
template match="
node()"
mode="
variableDeclarations">
<!---->
</
xsl:
template>
</
xsl:
stylesheet>
v