Skip to content

Commit 64d946e

Browse files
[WIP] Supports assigment with groupElement
1 parent d68b54b commit 64d946e

File tree

4 files changed

+113
-44
lines changed

4 files changed

+113
-44
lines changed

SysML2.NET.CodeGenerator/HandleBarHelpers/RulesHelper.cs

Lines changed: 84 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,7 @@ private static void ProcessAlternatives(EncodedTextWriter writer, IClass umlClas
165165

166166
if(types.Count == 1)
167167
{
168-
if (ruleGenerationContext.CallerRule is not AssignmentElement)
169-
{
170-
ProcessUnitypedAlternativesWithOneElement(writer, umlClass, alternatives, ruleGenerationContext);
171-
}
172-
else
173-
{
174-
writer.WriteSafeString($"throw new System.NotSupportedException(\"Multiple alternatives with only not implemented yet for caller as AssignmentElement\");");
175-
}
168+
ProcessUnitypedAlternativesWithOneElement(writer, umlClass, alternatives, ruleGenerationContext);
176169
}
177170
else
178171
{
@@ -186,6 +179,13 @@ private static void ProcessAlternatives(EncodedTextWriter writer, IClass umlClas
186179
}
187180
}
188181

182+
/// <summary>
183+
/// Process multiple <see cref="Alternatives"/> when all of them only have one <see cref="RuleElement"/>
184+
/// </summary>
185+
/// <param name="writer">The <see cref="EncodedTextWriter"/> used to write into output content</param>
186+
/// <param name="umlClass">The related <see cref="IClass"/></param>
187+
/// <param name="alternatives">The collection of alternatives to process</param>
188+
/// <param name="ruleGenerationContext">The current <see cref="RuleGenerationContext"/></param>
189189
private static void ProcessUnitypedAlternativesWithOneElement(EncodedTextWriter writer, IClass umlClass, IReadOnlyCollection<Alternatives> alternatives, RuleGenerationContext ruleGenerationContext)
190190
{
191191
var firstRuleElement = alternatives.ElementAt(0).Elements[0];
@@ -205,15 +205,24 @@ private static void ProcessUnitypedAlternativesWithOneElement(EncodedTextWriter
205205
break;
206206
}
207207

208-
writer.WriteSafeString($"switch(poco){Environment.NewLine}");
208+
var variableName = "poco";
209+
210+
if (ruleGenerationContext.CallerRule is AssignmentElement assignmentElement)
211+
{
212+
var iteratorToUse = ruleGenerationContext.DefinedIterators.Single(x => x.ApplicableRuleElements.Contains(assignmentElement));
213+
variableName = $"{iteratorToUse.IteratorVariableName}.Current";
214+
writer.WriteSafeString($"{iteratorToUse.IteratorVariableName}.MoveNext();{Environment.NewLine}{Environment.NewLine}");
215+
}
216+
217+
writer.WriteSafeString($"switch({variableName}){Environment.NewLine}");
209218
writer.WriteSafeString("{");
210219

211220
foreach (var orderedNonTerminalElement in mappedNonTerminalElements)
212221
{
213222
if (orderedNonTerminalElement.UmlClass == ruleGenerationContext.NamedElementToGenerate)
214223
{
215224
writer.WriteSafeString($"default:{Environment.NewLine}");
216-
ProcessNonTerminalElement(writer, orderedNonTerminalElement.UmlClass, orderedNonTerminalElement.RuleElement, "poco",ruleGenerationContext);
225+
ProcessNonTerminalElement(writer, orderedNonTerminalElement.UmlClass, orderedNonTerminalElement.RuleElement, variableName,ruleGenerationContext);
217226
}
218227
else
219228
{
@@ -233,6 +242,13 @@ private static void ProcessUnitypedAlternativesWithOneElement(EncodedTextWriter
233242
}
234243
}
235244

245+
/// <summary>
246+
/// Orders a collection of <see cref="NonTerminalElement"/> based on the inheritance ordering, to build switch expression
247+
/// </summary>
248+
/// <param name="nonTerminalElements">The collection of <see cref="NonTerminalElement"/> to order</param>
249+
/// <param name="cache">The <see cref="IXmiElementCache"/></param>
250+
/// <param name="ruleGenerationContext">The current <see cref="RuleGenerationContext"/></param>
251+
/// <returns>The collection of ordered <see cref="NonTerminalElement"/> with the associated <see cref="IClass"/></returns>
236252
private static List<(NonTerminalElement RuleElement, IClass UmlClass)> OrderElementsByInheritance(List<NonTerminalElement> nonTerminalElements, IXmiElementCache cache, RuleGenerationContext ruleGenerationContext)
237253
{
238254
var mapping = new List<(NonTerminalElement RuleElement, IClass UmlClass)>();
@@ -580,23 +596,12 @@ private static void DeclareIteratorIfRequired(EncodedTextWriter writer, IClass u
580596
return;
581597
}
582598

583-
if (assignmentElement.Value is GroupElement groupElement)
584-
{
585-
var groupedAssignment = groupElement.Alternatives.SelectMany(x => x.Elements).OfType<AssignmentElement>();
586-
587-
foreach (var assignment in groupedAssignment)
588-
{
589-
DeclareIteratorIfRequired(writer, umlClass, assignment, ruleGenerationContext);
590-
}
591-
592-
return;
593-
}
594-
595599
switch (assignmentElement.Value)
596600
{
597601
case NonTerminalElement nonTerminalElement:
602+
{
598603
var referencedRule = ruleGenerationContext.AllRules.SingleOrDefault(x => x.RuleName == nonTerminalElement.Name);
599-
604+
600605
if (ruleGenerationContext.DefinedIterators.SingleOrDefault(x => x.IsIteratorValidForProperty(targetProperty, referencedRule) || x.ApplicableRuleElements.Contains(assignmentElement)) is { } alreadyDefinedIterator)
601606
{
602607
alreadyDefinedIterator.ApplicableRuleElements.Add(assignmentElement);
@@ -607,14 +612,14 @@ private static void DeclareIteratorIfRequired(EncodedTextWriter writer, IClass u
607612
{
608613
DefinedForProperty = targetProperty
609614
};
610-
615+
611616
iteratorToUse.ApplicableRuleElements.Add(assignmentElement);
612617

613618
string typeTarget;
614-
619+
615620
if (referencedRule == null)
616621
{
617-
typeTarget = umlClass.Name;
622+
typeTarget = umlClass.Name;
618623
}
619624
else
620625
{
@@ -626,18 +631,19 @@ private static void DeclareIteratorIfRequired(EncodedTextWriter writer, IClass u
626631
var targetType = umlClass.Cache.Values.OfType<INamedElement>().SingleOrDefault(x => x.Name == typeTarget);
627632
iteratorToUse.ConstrainedType = targetType;
628633

629-
writer.WriteSafeString(targetType != null
630-
? $"using var {iteratorToUse.IteratorVariableName} = poco.{targetProperty.QueryPropertyNameBasedOnUmlProperties()}.OfType<{targetType.QueryFullyQualifiedTypeName(targetInterface: false)}>().GetEnumerator();"
634+
writer.WriteSafeString(targetType != null
635+
? $"using var {iteratorToUse.IteratorVariableName} = poco.{targetProperty.QueryPropertyNameBasedOnUmlProperties()}.OfType<{targetType.QueryFullyQualifiedTypeName(targetInterface: false)}>().GetEnumerator();"
631636
: $"using var {iteratorToUse.IteratorVariableName} = poco.{targetProperty.QueryPropertyNameBasedOnUmlProperties()}.GetEnumerator();");
632637
}
633638
else
634639
{
635640
writer.WriteSafeString($"using var {iteratorToUse.IteratorVariableName} = poco.{targetProperty.QueryPropertyNameBasedOnUmlProperties()}.GetEnumerator();");
636641
}
637-
642+
638643
writer.WriteSafeString(Environment.NewLine);
639644
ruleGenerationContext.DefinedIterators.Add(iteratorToUse);
640-
break;
645+
break;
646+
}
641647
case ValueLiteralElement:
642648
if (ruleGenerationContext.DefinedIterators.SingleOrDefault(x => x.IsIteratorValidForProperty(targetProperty, null) || x.ApplicableRuleElements.Contains(assignmentElement)) is { } existingValueLiteralIterator)
643649
{
@@ -655,6 +661,54 @@ private static void DeclareIteratorIfRequired(EncodedTextWriter writer, IClass u
655661
writer.WriteSafeString(Environment.NewLine);
656662
ruleGenerationContext.DefinedIterators.Add(valueLiteralIterator);
657663

664+
break;
665+
case AssignmentElement containedAssignment:
666+
DeclareIteratorIfRequired(writer, umlClass, containedAssignment, ruleGenerationContext);
667+
break;
668+
case GroupElement groupElement:
669+
var nonTerminalRules = groupElement.Alternatives.SelectMany(x => x.Elements).OfType<NonTerminalElement>().ToList();
670+
671+
if (ruleGenerationContext.DefinedIterators.Any(x => x.ApplicableRuleElements.Contains(assignmentElement)))
672+
{
673+
return;
674+
}
675+
676+
var referencedTypes = new HashSet<INamedElement>();
677+
678+
foreach (var nonTerminalElement in nonTerminalRules)
679+
{
680+
var referencedRule = ruleGenerationContext.AllRules.SingleOrDefault(x => x.RuleName == nonTerminalElement.Name);
681+
682+
if (ruleGenerationContext.DefinedIterators.SingleOrDefault(x => x.IsIteratorValidForProperty(targetProperty, referencedRule)) is { } alreadyDefined)
683+
{
684+
alreadyDefined.ApplicableRuleElements.Add(assignmentElement);
685+
return;
686+
}
687+
688+
string typeTarget;
689+
690+
if (referencedRule == null)
691+
{
692+
typeTarget = umlClass.Name;
693+
}
694+
else
695+
{
696+
typeTarget = referencedRule.TargetElementName ?? referencedRule.RuleName;
697+
}
698+
699+
referencedTypes.Add(umlClass.Cache.Values.OfType<INamedElement>().Single(x => x.Name == typeTarget));
700+
}
701+
702+
var iteratorToUseForGroup = new IteratorDefinition
703+
{
704+
DefinedForProperty = targetProperty
705+
};
706+
707+
var typesFilter = string.Join(", ", referencedTypes.Select(x => $"typeof({x.QueryFullyQualifiedTypeName(targetInterface: false)})"));
708+
writer.WriteSafeString($"using var {iteratorToUseForGroup.IteratorVariableName} = SysML2.NET.Extensions.EnumerableExtensions.GetElementsOfType(poco.{targetProperty.QueryPropertyNameBasedOnUmlProperties()}, {typesFilter}).GetEnumerator();{Environment.NewLine}");
709+
710+
iteratorToUseForGroup.ApplicableRuleElements.Add(assignmentElement);
711+
ruleGenerationContext.DefinedIterators.Add(iteratorToUseForGroup);
658712
break;
659713
}
660714
}

SysML2.NET/TextualNotation/IfActionUsageTextualNotationBuilder.cs renamed to SysML2.NET/Extensions/EnumerableExtensions.cs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// -------------------------------------------------------------------------------------------------
2-
// <copyright file="IfActionUsageTextualNotationBuilder.cs" company="Starion Group S.A.">
2+
// <copyright file="EnumerableExtensions.cs" company="Starion Group S.A.">
33
//
44
// Copyright 2022-2026 Starion Group S.A.
55
//
@@ -18,26 +18,29 @@
1818
// </copyright>
1919
// ------------------------------------------------------------------------------------------------
2020

21-
namespace SysML2.NET.TextualNotation
21+
namespace SysML2.NET.Extensions
2222
{
23+
using System;
24+
using System.Collections;
25+
using System.Collections.Generic;
2326
using System.Linq;
2427

25-
using SysML2.NET.Core.POCO.Kernel.Behaviors;
26-
using SysML2.NET.Core.POCO.Systems.Actions;
28+
using SysML2.NET.Core.POCO.Root.Elements;
2729

2830
/// <summary>
29-
/// Hand-coded part of the <see cref="IfActionUsageTextualNotationBuilder"/>
31+
/// Extension methods for the <see cref="IEnumerable" /> interface
3032
/// </summary>
31-
public static partial class IfActionUsageTextualNotationBuilder
33+
internal static class EnumerableExtensions
3234
{
3335
/// <summary>
34-
/// Builds the conditional part for the IfNode rule
36+
/// Filters out all <see cref="IElement" /> where the type matches one of the requested
3537
/// </summary>
36-
/// <param name="poco">The <see cref="IIfActionUsage"/></param>
37-
/// <returns>The assertion of the condition</returns>
38-
private static bool BuildGroupConditionForIfNode(IIfActionUsage poco)
38+
/// <param name="collection">The collection to filters</param>
39+
/// <param name="elementTypes">A collection of <see cref="Type" /> that should be used for filtering</param>
40+
/// <returns>A collection of <see cref="IEnumerable{T}" /></returns>
41+
internal static IEnumerable<IElement> GetElementsOfType(this IEnumerable collection, params Type[] elementTypes)
3942
{
40-
return poco.OwnedRelationship.OfType<IParameterMembership>().Count() != 0;
43+
return from object element in collection where elementTypes.Contains(element.GetType()) select element as IElement;
4144
}
4245
}
4346
}

SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/IfActionUsageTextualNotationBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ public static void BuildIfNode(SysML2.NET.Core.POCO.Systems.Actions.IIfActionUsa
5858
ParameterMembershipTextualNotationBuilder.BuildActionBodyParameterMember(ownedRelationshipOfParameterMembershipIterator.Current, stringBuilder);
5959
}
6060

61-
if (BuildGroupConditionForIfNode(poco))
61+
if (ownedRelationshipOfParameterMembershipIterator.MoveNext())
6262
{
6363
stringBuilder.Append("else ");
64-
throw new System.NotSupportedException("Multiple alternatives with only not implemented yet for caller as AssignmentElement");
64+
throw new System.NotSupportedException("Multiple alternatives with same referenced rule type not implemented yet");
6565
stringBuilder.Append(' ');
6666
}
6767

SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/OwningMembershipTextualNotationBuilder.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,19 @@ public static void BuildOwnedMultiplicity(SysML2.NET.Core.POCO.Root.Namespaces.I
131131
/// <param name="stringBuilder">The <see cref="StringBuilder" /> that contains the entire textual notation</param>
132132
public static void BuildMultiplicityExpressionMember(SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership poco, StringBuilder stringBuilder)
133133
{
134-
throw new System.NotSupportedException("Multiple alternatives with only not implemented yet for caller as AssignmentElement");
134+
using var ownedRelatedElementIterator = SysML2.NET.Extensions.EnumerableExtensions.GetElementsOfType(poco.OwnedRelatedElement, typeof(SysML2.NET.Core.POCO.Kernel.Expressions.LiteralExpression), typeof(SysML2.NET.Core.POCO.Kernel.Expressions.FeatureReferenceExpression)).GetEnumerator();
135+
ownedRelatedElementIterator.MoveNext();
136+
137+
switch (ownedRelatedElementIterator.Current)
138+
{
139+
case SysML2.NET.Core.POCO.Kernel.Expressions.LiteralExpression pocoLiteralExpression:
140+
LiteralExpressionTextualNotationBuilder.BuildLiteralExpression(pocoLiteralExpression, stringBuilder);
141+
break;
142+
case SysML2.NET.Core.POCO.Kernel.Expressions.FeatureReferenceExpression pocoFeatureReferenceExpression:
143+
FeatureReferenceExpressionTextualNotationBuilder.BuildFeatureReferenceExpression(pocoFeatureReferenceExpression, stringBuilder);
144+
break;
145+
}
146+
135147

136148
}
137149

0 commit comments

Comments
 (0)