@@ -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 }
0 commit comments