changeset 1:7f803979305f

improved cs-dom generation, added getMember, getKeyMember templates
author cin
date Thu, 22 Feb 2018 19:14:00 +0300
parents cbdada054b4a
children 035de8b7b18e
files .project data/model.xml xslt/model.xslt xslt/text-tools.xsl
diffstat 4 files changed, 176 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.project	Thu Feb 22 19:14:00 2018 +0300
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>ModelGenerator</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+	</buildSpec>
+	<natures>
+	</natures>
+</projectDescription>
--- a/data/model.xml	Wed Feb 21 03:01:53 2018 +0300
+++ b/data/model.xml	Thu Feb 22 19:14:00 2018 +0300
@@ -33,7 +33,7 @@
 			<description>Район проведения операции, в котором будет работать
 				данная единица.
 			</description>
-			<thisKey name="RegionId" matches="Id" />
+			<thisKey name="RegionId"/>
 		</hasA>
 		<hasA name="Operation" type="Operation" optional="true">
 			<description>Идентификатор операции, используется для фильтрации
@@ -79,8 +79,8 @@
 		</property>
 		<hasMany name="Regions" type="Region">
 			<description>Список районов поиска</description>
-			<otherKey name="OperationId" />
-			<clr:association>
+			<otherKey name="Operation" />
+			<clr:association otherKey="OperationId"> <!-- explicit otherKey for code generation -->
 				<clr:type ref="listOf">
 					<clr:type ref="Region" />
 				</clr:type>
--- a/xslt/model.xslt	Wed Feb 21 03:01:53 2018 +0300
+++ b/xslt/model.xslt	Thu Feb 22 19:14:00 2018 +0300
@@ -5,6 +5,8 @@
 	xmlns:cs="http://implab.org/schemas/code-dom/csharp.v1.xsd" xmlns:sql="http://implab.org/schemas/data-model/sql.v1.xsd"
 	xmlns:t="http://implab.org/schemas/temp" xmlns:exsl="http://exslt.org/common"
 	exclude-result-prefixes="clr m xsl exsl sql">
+	<xsl:include href="text-tools.xsl"/>
+	
 	<xsl:output method="xml" indent="yes" />
 
 	<xsl:key name="type" match="m:package/m:*" use="@name" />
@@ -257,30 +259,51 @@
 	<xsl:template match="m:hasA/clr:association" mode="property-attributes">
 		<cs:attribute>
 			<cs:type name="Association" namespace="Linq2Db"/>
-			<cs:parameter name="thisKey">nameof(<xsl:apply-templates select="../m:thisKey" mode="property-name"/>)</cs:parameter>
-			<cs:parameter name="otherKey">nameof(<cs:typeName>
-				<xsl:apply-templates select="." mode="property-type"/>
-			</cs:typeName>.<xsl:call-template name="getKeyName">
-				<xsl:with-param name="type" select="../@type"/>
-			</xsl:call-template>)</cs:parameter>
+			<cs:parameter name="thisKey">
+				<cs:nameOf>
+					<xsl:call-template name="getMember">
+						<xsl:with-param name="memberName" select="../@name"/>
+						<xsl:with-param name="explicitMemberName" select="@thisKey"/>
+						<xsl:with-param name="type" select="../../@name"/>
+						<xsl:with-param name="short" select="true()"/>
+					</xsl:call-template>
+				</cs:nameOf>
+			</cs:parameter>
+			<cs:parameter name="otherKey">
+				<cs:nameOf>
+					<xsl:call-template name="getKeyMember">
+						<xsl:with-param name="explicitMemberName" select="@thisKey"/>
+						<xsl:with-param name="type" select="../@type"/>
+					</xsl:call-template>
+				</cs:nameOf>
+			</cs:parameter>
 		</cs:attribute>
 	</xsl:template>
 	
+	
+	
 	<xsl:template match="m:hasMany/clr:association" mode="property-attributes">
 		<cs:attribute>
 			<cs:type name="Association" namespace="Linq2Db"/>
 			<!-- thisKey points to own primaryKey which may be inherited, using getKeyName to address such cases -->
-			<cs:parameter name="thisKey">nameof(<xsl:call-template name="getKeyName">
-					<xsl:with-param name="type" select="../../@name"/>
-				</xsl:call-template>)</cs:parameter>
-			<cs:parameter name="otherKey">nameof(<cs:typeName>
-					<xsl:call-template name="getClrType">
+			<cs:parameter name="thisKey">
+				<cs:nameOf>
+					<xsl:call-template name="getKeyMember">
+						<xsl:with-param name="type" select="../../@name"/>
+						<xsl:with-param name="explicitMemberName" select="@thisKey"/>
+						<xsl:with-param name="short" select="true()"/>
+					</xsl:call-template>
+				</cs:nameOf>
+			</cs:parameter>
+			<cs:parameter name="otherKey">
+				<cs:nameOf>	
+					<xsl:call-template name="getMember">
 						<xsl:with-param name="type" select="../@type"/>
+						<xsl:with-param name="memberName" select="../m:otherKey/@name"/>
+						<xsl:with-param name="explicitMemberName" select="@otherKey"/>
 					</xsl:call-template>
-				</cs:typeName>.<xsl:call-template name="getClrPropertyName">
-					<xsl:with-param name="member" select="../m:otherKey/@name"/>
-					<xsl:with-param name="type" select="../@type"/>
-				</xsl:call-template>)</cs:parameter>
+				</cs:nameOf>
+			</cs:parameter>
 		</cs:attribute>
 	</xsl:template>
 	
@@ -520,11 +543,13 @@
 	<xsl:template name="getClrPropertyName">
 		<xsl:param name="type"/>
 		<xsl:param name="member"/>
-		<trace msg="getClrPropertyName {$type}.{$member}"/>
+		<!-- prevents cyclic references -->
+		<xsl:param name="seen" select="/.."/>
 		<xsl:for-each select="exsl:node-set($fragment)">
 			<xsl:apply-templates select="key('type', $type)"
 				mode="member-lookup">
 				<xsl:with-param name="member" select="$member"/>
+				<xsl:with-param name="seen" select="$seen"/>
 			</xsl:apply-templates>
 		</xsl:for-each>
 	</xsl:template>
@@ -533,18 +558,36 @@
 	
 	<xsl:template match="m:entity" mode="member-lookup">
 		<xsl:param name="member"/>
-		<xsl:variable name="match" select="*[@name=$member]"/>
-		<xsl:choose>
-			<xsl:when test="$match">
-				<xsl:apply-templates select="$match" mode="member-lookup"/>
-			</xsl:when>
-			<xsl:when test="m:extends">
-				<xsl:call-template name="getClrPropertyName">
-					<xsl:with-param name="type" select="m:extends/@type"/>
-					<xsl:with-param name="member" select="$member"/>
-				</xsl:call-template>
-			</xsl:when>
-		</xsl:choose>
+		<xsl:param name="seen"/>
+		<xsl:variable name="self" select="."/>
+		
+		<xsl:if test="not($seen[generate-id() = generate-id($self)])">
+			<xsl:variable name="match" select="*[@name=$member]"/>
+			<xsl:choose>
+				<xsl:when test="$match">
+					<xsl:apply-templates select="$match" mode="member-lookup"/>
+				</xsl:when>
+				<xsl:when test="m:extends">
+					<xsl:call-template name="getClrPropertyName">
+						<xsl:with-param name="type" select="m:extends/@type"/>
+						<xsl:with-param name="member" select="$member"/>
+						<xsl:with-param name="seen" select="$seen | $self"/>
+					</xsl:call-template>
+				</xsl:when>
+				<xsl:otherwise>
+					<xsl:call-template name="warn">
+						<xsl:with-param name="msg">
+							<t:trace msg="failed to resolve {$member}"/>
+							<t:trace msg="inspected classes">
+							<xsl:for-each select="$seen | $self">
+								<t:trace msg="{name()} {@name}"/>
+							</xsl:for-each>
+							</t:trace>
+						</xsl:with-param>
+					</xsl:call-template>
+				</xsl:otherwise>
+			</xsl:choose>
+		</xsl:if>
 	</xsl:template>
 	
 	<xsl:template match="m:property | m:primaryKey" mode="member-lookup">
@@ -554,5 +597,63 @@
 	<xsl:template match="m:hasA" mode="member-lookup">
 		<xsl:apply-templates select="m:thisKey" mode="property-name"/>
 	</xsl:template>
-
+	
+	<xsl:template name="getKeyMember">
+		<xsl:param name="explicitMemberName" select="''"/>
+		<xsl:param name="type"/>
+		<xsl:param name="short" select="false()"/>
+		<cs:member>
+			<xsl:choose>
+				<xsl:when test="$explicitMemberName">
+					<xsl:attribute name="name">
+						<xsl:value-of select="$explicitMemberName"/>
+					</xsl:attribute>
+				</xsl:when>
+				<xsl:otherwise>
+					<xsl:attribute name="name">
+						<xsl:call-template name="getKeyName">
+							<xsl:with-param name="type" select="$type"/>
+						</xsl:call-template>
+					</xsl:attribute>
+				</xsl:otherwise>
+			</xsl:choose>
+			<xsl:if test="not($short)">
+				<xsl:call-template name="getClrType">
+					<xsl:with-param name="type" select="$type"/>
+				</xsl:call-template>
+			</xsl:if>
+		</cs:member>
+	</xsl:template>
+	
+	<xsl:template name="getMember">
+		<xsl:param name="memberName"/>
+		<xsl:param name="type"/>
+		<xsl:param name="explicitMemberName" select="''"/>
+		<xsl:param name="short" select="false()"/>
+		<cs:member>
+			<xsl:choose>
+				<xsl:when test="$explicitMemberName">
+					<xsl:attribute name="name">
+						<xsl:value-of select="$explicitMemberName"/>
+					</xsl:attribute>
+				</xsl:when>
+				<xsl:otherwise>
+					<xsl:attribute name="name">
+						<xsl:call-template name="getClrPropertyName">
+							<xsl:with-param name="member" select="$memberName"/>
+							<xsl:with-param name="type" select="$type"/>
+						</xsl:call-template>
+					</xsl:attribute>
+				</xsl:otherwise>
+			</xsl:choose>
+			<xsl:if test="not($short)">
+				<xsl:call-template name="getClrType">
+					<xsl:with-param name="type" select="$type"/>
+				</xsl:call-template>
+			</xsl:if>
+		</cs:member>
+	</xsl:template>
+	
+	
+	
 </xsl:stylesheet>
--- a/xslt/text-tools.xsl	Wed Feb 21 03:01:53 2018 +0300
+++ b/xslt/text-tools.xsl	Thu Feb 22 19:14:00 2018 +0300
@@ -1,8 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <xsl:stylesheet version="1.0"
-	xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="http://implab.org/schemas/temp"
+	xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl">
 	<!-- TEXT ROUTINES -->
-	<xsl:template name="write-line">
+	<xsl:template name="writeLine">
 		<xsl:param name="level" select="0" />
 		<xsl:param name="text" />
 		<xsl:call-template name="indent">
@@ -22,7 +23,7 @@
 		</xsl:if>
 	</xsl:template>
 
-	<xsl:template name="to-lower-first">
+	<xsl:template name="toLowerFirst">
 		<xsl:param name="value" />
 		<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
 		<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
@@ -32,10 +33,37 @@
 			select="concat(translate($before,$uppercase,$smallcase), $after)" />
 	</xsl:template>
 
-	<xsl:template name="to-lower">
+	<xsl:template name="toLower">
 		<xsl:param name="value" />
 		<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
 		<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
 		<xsl:value-of select="translate($value,$uppercase,$smallcase)" />
 	</xsl:template>
+
+	<xsl:template name="warn">
+		<xsl:param name="msg" />
+		<xsl:message terminate="no">
+			<xsl:apply-templates select="exsl:node-set($msg)"
+				mode="trace" />
+		</xsl:message>
+	</xsl:template>
+
+	<xsl:template name="error">
+		<xsl:param name="msg" />
+		<xsl:message terminate="no">
+			<xsl:apply-templates select="exsl:node-set($msg)"
+				mode="trace" />
+		</xsl:message>
+	</xsl:template>
+
+	<xsl:template match="t:trace" mode="trace">
+		<xsl:param name="level" select="0" />
+		<xsl:call-template name="writeLine">
+			<xsl:with-param name="text" select="@msg" />
+			<xsl:with-param name="level" select="$level" />
+		</xsl:call-template>
+		<xsl:apply-templates mode="trace">
+			<xsl:with-param name="level" select="$level + 1" />
+		</xsl:apply-templates>
+	</xsl:template>
 </xsl:stylesheet>
\ No newline at end of file