Skip to content

Commit eeafb02

Browse files
Fix some found issues by reviewer
1 parent 6b86fc8 commit eeafb02

14 files changed

Lines changed: 176 additions & 30 deletions

SysML2.NET.CodeGenerator/HandleBarHelpers/RulesHelper.cs

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,6 +1727,34 @@ private static void ProcessUnitypedAlternativesWithOneElement(EncodedTextWriter
17271727
variableName = $"{cursorToUse.CursorVariableName}.Current";
17281728
}
17291729

1730+
// Detect degenerate switch: if the first non-default case type is a supertype
1731+
// of the generating class, it will always match, making subsequent cases unreachable.
1732+
// This happens when alternatives like (SuperclassingPart | ConjugationPart) both
1733+
// target ancestor types of the POCO — the discriminator should be cursor-based,
1734+
// not POCO-type-based. Fall back to HandCoded in this case.
1735+
var generatingClass = ruleGenerationContext.NamedElementToGenerate as IClass;
1736+
1737+
if (variableName == "poco" && generatingClass != null)
1738+
{
1739+
var firstNonDefault = mappedNonTerminalElements.FirstOrDefault(x =>
1740+
defaultElement.RuleElement == null || x.RuleElement != defaultElement.RuleElement);
1741+
1742+
if (firstNonDefault.UmlClass != null
1743+
&& firstNonDefault.UmlClass != generatingClass
1744+
&& generatingClass.QueryAllGeneralClassifiers().Contains(firstNonDefault.UmlClass)
1745+
&& !whenGuards.Any())
1746+
{
1747+
var handCodedRuleName = alternatives.ElementAt(0).TextualNotationRule?.RuleName ?? "Unknown";
1748+
1749+
if (ruleGenerationContext.EmittedHandCodedCalls.Add(handCodedRuleName))
1750+
{
1751+
writer.WriteSafeString($"Build{handCodedRuleName}HandCoded({ruleGenerationContext.CurrentVariableName ?? "poco"}, cursorCache, stringBuilder);");
1752+
}
1753+
1754+
break;
1755+
}
1756+
}
1757+
17301758
writer.WriteSafeString($"switch({variableName}){Environment.NewLine}");
17311759
writer.WriteSafeString("{");
17321760

@@ -2236,7 +2264,7 @@ private static void ProcessRuleElement(EncodedTextWriter writer, IClass umlClass
22362264
ProcessAlternatives(writer, umlClass, groupElement.Alternatives, ruleGenerationContext);
22372265
}
22382266

2239-
if (!groupElement.IsOptional && !ruleGenerationContext.IsNextElementNewLineTerminal())
2267+
if (!groupElement.IsOptional && !ruleGenerationContext.IsNextElementNewLineTerminal() && !ruleGenerationContext.IsLastElement())
22402268
{
22412269
writer.WriteSafeString($"{Environment.NewLine}stringBuilder.Append(' ');");
22422270
}
@@ -2355,7 +2383,7 @@ private static void ProcessAssignmentElement(EncodedTextWriter writer, IClass um
23552383
{
23562384
if (assignmentElement.Value is TerminalElement terminalElement)
23572385
{
2358-
if (!isPartOfMultipleAlternative && assignmentElement.Container is not GroupElement)
2386+
if (!isPartOfMultipleAlternative && assignmentElement.Container is not GroupElement {IsOptional:true})
23592387
{
23602388
writer.WriteSafeString($"if({targetProperty.QueryIfStatementContentForNonEmpty("poco")}){Environment.NewLine}");
23612389
writer.WriteSafeString($"{{{Environment.NewLine}");
@@ -2621,10 +2649,60 @@ private static void EmitCollectionNonTerminalLoop(EncodedTextWriter writer, ICla
26212649
// e.g., CalculationBodyItem* ResultExpressionMember → while (current is not IResultExpressionMembership)
26222650
var whileTypeExclusion = ResolveCollectionWhileTypeCondition(cursorVariableName, umlClass, referencedRule, ruleGenerationContext);
26232651

2624-
// Build the full while condition: merged pattern to avoid "merge into pattern" warnings
2625-
var whileCondition = string.IsNullOrWhiteSpace(whileTypeExclusion)
2626-
? $"{cursorVariableName}.Current != null"
2627-
: whileTypeExclusion;
2652+
// Build the full while condition: merged pattern to avoid "merge into pattern" warnings.
2653+
// When no sibling-based type exclusion is available, use a positive type guard
2654+
// based on the collection item's assignment target type to prevent consuming
2655+
// elements belonging to subsequent grammar segments (unbounded cursor drain).
2656+
string whileCondition;
2657+
2658+
if (!string.IsNullOrWhiteSpace(whileTypeExclusion))
2659+
{
2660+
whileCondition = whileTypeExclusion;
2661+
}
2662+
else
2663+
{
2664+
// Try to resolve a positive type guard from the referenced rule's assignment targets.
2665+
// Only apply the guard when ALL alternatives are pure += assignments (no bare
2666+
// NonTerminal or Group elements that could match different cursor types).
2667+
var allElements = referencedRule?.Alternatives.SelectMany(alt => alt.Elements).ToList();
2668+
var hasNonAssignmentElements = allElements?.Any(element =>
2669+
element is NonTerminalElement or GroupElement) == true;
2670+
2671+
List<string> assignmentTargetTypes = null;
2672+
2673+
if (!hasNonAssignmentElements)
2674+
{
2675+
assignmentTargetTypes = allElements?
2676+
.OfType<AssignmentElement>()
2677+
.Where(assignmentElement => assignmentElement.Operator == "+=" && assignmentElement.Value is NonTerminalElement)
2678+
.Select(assignmentElement =>
2679+
{
2680+
var valueNonTerminal = (NonTerminalElement)assignmentElement.Value;
2681+
var refRule = ruleGenerationContext.AllRules.SingleOrDefault(x => x.RuleName == valueNonTerminal.Name);
2682+
var targetName = refRule != null ? (refRule.TargetElementName ?? refRule.RuleName) : null;
2683+
2684+
if (targetName != null)
2685+
{
2686+
var targetClass = umlClass.Cache.Values.OfType<INamedElement>().SingleOrDefault(x => x.Name == targetName) as IClass;
2687+
return targetClass?.QueryFullyQualifiedTypeName();
2688+
}
2689+
2690+
return null;
2691+
})
2692+
.Where(typeName => typeName != null)
2693+
.Distinct()
2694+
.ToList();
2695+
}
2696+
2697+
if (assignmentTargetTypes?.Count == 1)
2698+
{
2699+
whileCondition = $"{cursorVariableName}.Current != null && {cursorVariableName}.Current is {assignmentTargetTypes[0]}";
2700+
}
2701+
else
2702+
{
2703+
whileCondition = $"{cursorVariableName}.Current != null";
2704+
}
2705+
}
26282706

26292707
if (perItemCall != null)
26302708
{

SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/ClassifierTextualNotationBuilder.cs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,7 @@ public static void BuildClassifierDeclaration(SysML2.NET.Core.POCO.Core.Classifi
110110
stringBuilder.Append(' ');
111111
}
112112

113-
switch (poco)
114-
{
115-
case SysML2.NET.Core.POCO.Core.Types.IType pocoType:
116-
TypeTextualNotationBuilder.BuildConjugationPart(pocoType, cursorCache, stringBuilder);
117-
break;
118-
default:
119-
BuildSuperclassingPart(poco, cursorCache, stringBuilder);
120-
break;
121-
}
122-
113+
BuildClassifierDeclarationHandCoded(poco, cursorCache, stringBuilder);
123114
while (ownedRelationshipCursor.Current != null)
124115
{
125116
TypeTextualNotationBuilder.BuildTypeRelationshipPart(poco, cursorCache, stringBuilder);

SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/DefinitionTextualNotationBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public static void BuildDefinitionPrefix(SysML2.NET.Core.POCO.Systems.Definition
7373
SharedTextualNotationBuilder.BuildBasicDefinitionPrefix(poco, cursorCache, stringBuilder);
7474
}
7575
var ownedRelationshipCursor = cursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
76-
while (ownedRelationshipCursor.Current != null)
76+
while (ownedRelationshipCursor.Current != null && ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership)
7777
{
7878
BuildDefinitionExtensionKeyword(poco, cursorCache, stringBuilder);
7979
}

SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/FeatureTextualNotationBuilder.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,6 @@ public static void BuildOwnedFeatureChain(SysML2.NET.Core.POCO.Core.Features.IFe
352352
ownedRelationshipCursor.Move();
353353

354354
}
355-
stringBuilder.Append(' ');
356355

357356
}
358357

@@ -730,7 +729,6 @@ public static void BuildChainingPart(SysML2.NET.Core.POCO.Core.Features.IFeature
730729
{
731730
BuildFeatureChain(poco, cursorCache, stringBuilder);
732731
}
733-
stringBuilder.Append(' ');
734732

735733
}
736734

@@ -840,7 +838,6 @@ public static void BuildFeatureChain(SysML2.NET.Core.POCO.Core.Features.IFeature
840838
ownedRelationshipCursor.Move();
841839

842840
}
843-
stringBuilder.Append(' ');
844841

845842
}
846843

SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/LibraryPackageTextualNotationBuilder.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ public static partial class LibraryPackageTextualNotationBuilder
4444
public static void BuildLibraryPackage(SysML2.NET.Core.POCO.Kernel.Packages.ILibraryPackage poco, ICursorCache cursorCache, StringBuilder stringBuilder)
4545
{
4646
var ownedRelationshipCursor = cursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
47-
stringBuilder.Append(" standard ");
47+
if (poco.IsStandard)
48+
{
49+
stringBuilder.Append(" standard ");
50+
}
4851

4952
stringBuilder.Append(' ');
5053
stringBuilder.Append("library ");

SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/MetadataFeatureTextualNotationBuilder.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ public static void BuildMetadataFeatureDeclaration(SysML2.NET.Core.POCO.Kernel.M
7474
ElementTextualNotationBuilder.BuildIdentification(poco, cursorCache, stringBuilder);
7575
stringBuilder.Append(":");
7676
stringBuilder.Append(' ');
77-
stringBuilder.Append(' ');
7877
}
7978

8079

SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/MetadataUsageTextualNotationBuilder.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ public static void BuildMetadataUsageDeclaration(SysML2.NET.Core.POCO.Systems.Me
7474
ElementTextualNotationBuilder.BuildIdentification(poco, cursorCache, stringBuilder);
7575
stringBuilder.Append(":");
7676
stringBuilder.Append(' ');
77-
stringBuilder.Append(' ');
7877
}
7978

8079

SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/OccurrenceDefinitionTextualNotationBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public static void BuildOccurrenceDefinitionPrefix(SysML2.NET.Core.POCO.Systems.
6767
stringBuilder.Append(' ');
6868
}
6969

70-
while (ownedRelationshipCursor.Current != null)
70+
while (ownedRelationshipCursor.Current != null && ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership)
7171
{
7272
DefinitionTextualNotationBuilder.BuildDefinitionExtensionKeyword(poco, cursorCache, stringBuilder);
7373
}

SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/OccurrenceUsageTextualNotationBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public static void BuildOccurrenceUsagePrefix(SysML2.NET.Core.POCO.Systems.Occur
6060
}
6161

6262
var ownedRelationshipCursor = cursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
63-
while (ownedRelationshipCursor.Current != null)
63+
while (ownedRelationshipCursor.Current != null && ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership)
6464
{
6565
UsageTextualNotationBuilder.BuildUsageExtensionKeyword(poco, cursorCache, stringBuilder);
6666
}
@@ -147,7 +147,7 @@ public static void BuildControlNodePrefix(SysML2.NET.Core.POCO.Systems.Occurrenc
147147
}
148148

149149
var ownedRelationshipCursor = cursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
150-
while (ownedRelationshipCursor.Current != null)
150+
while (ownedRelationshipCursor.Current != null && ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership)
151151
{
152152
UsageTextualNotationBuilder.BuildUsageExtensionKeyword(poco, cursorCache, stringBuilder);
153153
}

SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/OwningMembershipTextualNotationBuilder.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ public static void BuildPackageMember(SysML2.NET.Core.POCO.Root.Namespaces.IOwni
8383
ownedRelatedElementCursor.Move();
8484
}
8585

86-
stringBuilder.Append(' ');
8786

8887
}
8988

0 commit comments

Comments
 (0)