Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,47 @@
* SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
* SPDX-License-Identifier: MIT
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:eo="https://www.eolang.org" exclude-result-prefixes="eo" id="classes" version="2.0">
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:eo="https://www.eolang.org" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="eo xs" id="classes" version="2.0">
<xsl:import href="/org/eolang/parser/_funcs.xsl"/>
<xsl:output encoding="UTF-8" method="xml"/>
<xsl:template name="serialize">
<xsl:param name="node"/>
<xsl:param name="indent"/>
<xsl:variable name="name" select="name($node)"/>
<xsl:value-of select="$indent"/>
<xsl:text>&lt;</xsl:text>
<xsl:value-of select="$name"/>
<xsl:for-each select="$node/@*">
<xsl:text> </xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>="</xsl:text>
<xsl:value-of select="."/>
<xsl:text>"</xsl:text>
</xsl:for-each>
<xsl:variable name="content" select="normalize-space(string(text()[1]))"/>
<xsl:if test="$content = '' and not($node/element())">
<xsl:text>/</xsl:text>
</xsl:if>
<xsl:text>&gt;</xsl:text>
<xsl:value-of select="$content"/>
<xsl:if test="$node/element()">
<xsl:for-each select="$node/element()">
<xsl:value-of select="'&#10;'"/>
<xsl:call-template name="serialize">
<xsl:with-param name="node" select="."/>
<xsl:with-param name="indent" select="concat($indent, ' ')"/>
</xsl:call-template>
</xsl:for-each>
<xsl:value-of select="'&#10;'"/>
<xsl:value-of select="$indent"/>
</xsl:if>
<xsl:if test="$content != '' or $node/element()">
<xsl:text>&lt;/</xsl:text>
<xsl:value-of select="$name"/>
<xsl:text>&gt;</xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="object/o[not(eo:atom(.)) or (eo:atom(.) and count(./o[eo:test-attr(.)])&gt;0)]" priority="1">
<!--
The XMIR of an object, indented, as the text that "to-java" turns into the
Javadoc of the generated class. It is one function returning one string,
rather than a template writing many small pieces of text, because the result
tree we write into is a DOM: every "xsl:text" or "xsl:value-of" a template
executes becomes a separate DOM text node, and a template that spelled a
start tag out piece by piece - indent, "&lt;", name, then five pieces per
attribute - left tens of thousands of them behind for a single object. Both
building that many nodes and later reading them back (the DOM has to merge
adjacent text nodes to answer "text()") cost far more than the string
concatenation itself, so serializing the biggest objects of "eo-runtime"
took seconds each and this pass alone was two fifths of the whole transpile
train (#6664).

Nesting the recursive call inside the enclosing "concat" means the string of
a subtree is copied once per level of depth above it, which for the depth of
a real XMIR is far cheaper than the per-node bookkeeping it replaces:
returning a sequence of pieces and joining them at the end, instead, is
three times slower here.
-->
<xsl:function name="eo:serialize" as="xs:string">
<xsl:param name="node" as="element()"/>
<xsl:param name="indent" as="xs:string"/>
<xsl:variable name="name" as="xs:string" select="name($node)"/>
<xsl:variable name="kids" as="element()*" select="$node/*"/>
<xsl:variable name="content" as="xs:string" select="normalize-space(string($node/text()[1]))"/>
<!-- An object with neither data nor children is written as a single self-closing tag. -->
<xsl:variable name="void" as="xs:boolean" select="$content = '' and empty($kids)"/>
Comment on lines +35 to +36

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping it, since the convention it appeals to isn't the one in this codebase: _funcs.xsl — the library this stylesheet imports — carries ten inline comments inside function bodies (<!-- 2-byte sequence: 110xxxxx 10xxxxxx -->, <!-- 55296 = 0xD800 --> and so on), all of them annotating a single line the way this one does.

The line above $void explains what the variable means — that an object with neither data nor children is written as a self-closing tag — while the doc comment above the function is about why the function has this shape at all (DOM text nodes, and the two slower shapes that were measured and rejected). Folding a one-line note about output format into that paragraph would bury it, and it belongs next to the variable it names.


Generated by Claude Code

<xsl:variable name="deeper" as="xs:string" select="concat($indent, ' ')"/>
<xsl:sequence select="concat($indent, '&lt;', $name, string-join(for $a in $node/@* return concat(' ', name($a), '=&quot;', $a, '&quot;'), ''), if ($void) then '/&gt;' else '&gt;', $content, string-join(for $k in $kids return concat('&#10;', eo:serialize($k, $deeper)), ''), if (empty($kids)) then '' else concat('&#10;', $indent), if ($void) then '' else concat('&lt;/', $name, '&gt;'))"/>
</xsl:function>
<!--
An atom is a class only when it holds tests, since it is the tests that need
a Java class of their own - "to-java" writes no ".java" for it, only its
tests. Spelled as "not atom, or has a test attribute", because when it is
not an atom the second half of the question does not need asking.
-->
<xsl:template match="object/o[not(eo:atom(.)) or exists(o[eo:test-attr(.)])]" priority="1">
<xsl:apply-templates select="." mode="class"/>
</xsl:template>
<xsl:template match="object/o[@base and @name]" priority="2">
Expand All @@ -67,10 +67,7 @@
</xsl:otherwise>
</xsl:choose>
<xmir>
<xsl:call-template name="serialize">
<xsl:with-param name="node" select="."/>
<xsl:with-param name="indent" select="''"/>
</xsl:call-template>
<xsl:value-of select="eo:serialize(., '')"/>
</xmir>
</class>
</xsl:template>
Expand Down
Loading