From eed76ac07af232adad7c9b5168b0e76be08f202e Mon Sep 17 00:00:00 2001 From: atheate Date: Wed, 9 Sep 2026 14:25:53 +0200 Subject: [PATCH 1/3] [Add] Arrowhead Framework Example to textual-notation validation corpus Registers AHFNorwayTopics as a validation test case, alongside its AHFCoreLib/AHFProfileLib library dependencies which supply imports but have no round-trip baseline of their own. --- .../AHFNorwayTopics.sysml | 129 ++ .../AHFCoreLib.sysmlx | 273 +++ .../AHFNorwayTopics.sysmlx | 1640 +++++++++++++++++ .../AHFProfileLib.sysmlx | 558 ++++++ .../TextualNotationValidationTestFixture.cs | 1 + 5 files changed, 2601 insertions(+) create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Expected/Arrowhead Framework Example/AHFNorwayTopics.sysml create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFCoreLib.sysmlx create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFNorwayTopics.sysmlx create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFProfileLib.sysmlx diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Arrowhead Framework Example/AHFNorwayTopics.sysml b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Arrowhead Framework Example/AHFNorwayTopics.sysml new file mode 100644 index 00000000..d9aea63a --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Arrowhead Framework Example/AHFNorwayTopics.sysml @@ -0,0 +1,129 @@ +package AHFNorway { + doc + /* This is the Norwegian use-case for Arrowhead Framework */ + private import AHFProfileLib::*; + private import AHFProfileMetadata::*; + private import AHFCoreLib::**; + private import ScalarValues::*; + #service def APISService { + doc + /* Service design */ + attribute :>> SD::serviceDefinition = "APISPullService"; + attribute :>> SD::intrfce_protocol = "{JSON}"; + attribute :>> SD::serviceURL = "pull"; + } + #servicedd port def APIS_DD :> APISService { + doc + /* Service design description with nested protocol-specific ports */ + #idd port APIS_HTTP { + out cll: CallGiveItems; + in retrn: ResultGiveItems; + } + #idd port APIS_MQTT { + out pub: Publish; + out retall: Return_AllItems; + in subscr: Subscribe; + } + } + attribute def Publish { + ref nametopic: String; + } + attribute def Subscribe { + ref nametopic: String; + } + attribute def Return_AllItems { + ref itms: String; + } + attribute def Subscribe_giveItems { + ref itms: String; + } + attribute def Return_Ack { + ref ack: Boolean; + } + attribute def CallGiveItems { + ref itms: String; + } + attribute def ResultGiveItems { + ref ack: Boolean; + } + #clouddd AHFNorway_LocalCloudDD :> ArrowheadCore { + #systemdd TellUConsumer { + #servicedd serviceDiscovery: ~ServiceDiscoveryDD; + #servicedd apisp: APIS_DD; + attribute :>> SysD::systemname = "UngerApisClient"; + attribute :>> SysD::address = "Unger_network_ip"; + attribute :>> SysD::portno = 0; + state TellUbehavior { + entry send new CallGiveItems("All the items") via apisp.APIS_HTTP; + then Wait; + state Wait; + accept rs: ResultGiveItems then Wait; + } + } + #systemdd APISProducer { + #servicedd serviceDiscovery: ~ServiceDiscoveryDD; + #servicedd tellu: ~APIS_DD; + #servicedd apisc: APIS_DD; + :>> SysD::systemname = "PrediktorApisServer"; + :>> SysD::address = "Prediktor_network_ip"; + :>> SysD::portno = 6565; + attribute x: Boolean; + action giveItems :> SysDD::ServiceMethod { + in itms: String; + out ack: Boolean; + /* Forward itms and return an ack */ + first start; + then send new Return_AllItems() via apisc.APIS_MQTT; + ref success = true; + bind ack = success; + } + state APISPbehavior { + entry send new Publish("Return_AllItems") via apisc.APIS_MQTT; + then WaitOnData; + state WaitOnData; + accept cl: CallGiveItems via tellu.APIS_HTTP do action { + first start; + then action giveItems { + in itms = cl.itms; + out ack = x; + } + then send new ResultGiveItems(x) via tellu.APIS_HTTP; + } + then WaitOnData; + } + } + #systemdd APISConsumer { + #servicedd serviceDiscovery: ~ServiceDiscovery; + #servicedd apisp: ~APIS_DD; + :>> SysD::systemname = "TellUClient"; + :>> SysD::address = "Prediktor_network_ip"; + :>> SysD::portno = 1; + state MQTT_APISP { + entry send new Subscribe("Return_AllItems") via apisp.APIS_MQTT; + then Idle; + state Idle; + accept Return_AllItems via apisp.APIS_MQTT then Idle; + } + } + part MQTTServer { + port getTopic: ~APIS_DD; + port giveTopic: APIS_DD; + state Serve { + entry; + then Publ; + state Publ; + accept pub: Publish via getTopic.APIS_MQTT then Subsr; + state Subsr; + accept Subscribe via giveTopic.APIS_MQTT then Idle; + state Idle; + accept retrnall: Return_AllItems via getTopic.APIS_MQTT do send retrnall via giveTopic.APIS_MQTT then Idle; + } + } + connect APISProducer.apisc to MQTTServer.getTopic; + connect MQTTServer.giveTopic to APISConsumer.apisp; + connect TellUConsumer.apisp to APISProducer.tellu; + connect APISProducer.serviceDiscovery to service_registry.serviceDiscovery; + connect TellUConsumer.serviceDiscovery to service_registry.serviceDiscovery; + connect APISConsumer.serviceDiscovery to service_registry.serviceDiscovery; + } +} diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFCoreLib.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFCoreLib.sysmlx new file mode 100644 index 00000000..a614ca0f --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFCoreLib.sysmlx @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFNorwayTopics.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFNorwayTopics.sysmlx new file mode 100644 index 00000000..a9eb8796 --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFNorwayTopics.sysmlx @@ -0,0 +1,1640 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFProfileLib.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFProfileLib.sysmlx new file mode 100644 index 00000000..8a864d47 --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Arrowhead Framework Example/AHFProfileLib.sysmlx @@ -0,0 +1,558 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Writers/TextualNotationValidationTestFixture.cs b/SysML2.NET.Serializer.TextualNotation.Tests/Writers/TextualNotationValidationTestFixture.cs index 4071f116..527100b6 100644 --- a/SysML2.NET.Serializer.TextualNotation.Tests/Writers/TextualNotationValidationTestFixture.cs +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Writers/TextualNotationValidationTestFixture.cs @@ -170,6 +170,7 @@ public void OneTimeTearDown() [TestCase("Simple Tests", "ParameterTest.sysmlx")] [TestCase("Simple Tests", "UseCaseTest.sysmlx")] [TestCase("Simple Tests", "VariabilityTest.sysmlx")] + [TestCase("Arrowhead Framework Example", "AHFNorwayTopics.sysmlx")] public async Task VerifyValidationTextualNotationXmi(string folderName, string fileName) { var loggerFactory = LoggerFactory.Create(builder => From 9c2572528ebdee631ae6cfdfcb06680b53796078 Mon Sep 17 00:00:00 2001 From: atheate Date: Wed, 9 Sep 2026 14:26:11 +0200 Subject: [PATCH 2/3] [Add] GrammarUnreachable attribute for grammar-dead textual-notation rules Computes reachability from RootNamespace over the merged KerML+SysML KEBNF grammar (SysML definitions override same-named KerML ones) and decorates every generated Build{Rule} method whose production has no incoming reference with [GrammarUnreachable], so a HandCoded companion that turns out to still call it stays consistent by explicit exclusion. --- .../UmlCoreTextualNotationBuilderGenerator.cs | 18 +++- .../Grammar/Model/TextualNotationRule.cs | 83 +++++++++++++++++++ .../Model/TextualNotationSpecification.cs | 24 ++++++ .../HandleBarHelpers/RulesHelper.cs | 28 +++++++ ...core-textual-notation-builder-template.hbs | 3 + ...xtual-notation-shared-builder-template.hbs | 3 + .../ElementTextualNotationBuilder.cs | 1 + ...FeatureMembershipTextualNotationBuilder.cs | 2 + .../FeatureTextualNotationBuilder.cs | 2 + .../FeatureValueTextualNotationBuilder.cs | 1 + .../MembershipTextualNotationBuilder.cs | 1 + .../MetadataFeatureTextualNotationBuilder.cs | 1 + .../MetadataUsageTextualNotationBuilder.cs | 2 + ...MultiplicityRangeTextualNotationBuilder.cs | 2 + .../ReferenceUsageTextualNotationBuilder.cs | 1 + .../RelationshipTextualNotationBuilder.cs | 1 + .../Writers/GrammarUnreachableAttribute.cs | 47 +++++++++++ 17 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 SysML2.NET.Serializer.TextualNotation/Writers/GrammarUnreachableAttribute.cs diff --git a/SysML2.NET.CodeGenerator/Generators/UmlHandleBarsGenerators/UmlCoreTextualNotationBuilderGenerator.cs b/SysML2.NET.CodeGenerator/Generators/UmlHandleBarsGenerators/UmlCoreTextualNotationBuilderGenerator.cs index 29812bdb..c8fb6061 100644 --- a/SysML2.NET.CodeGenerator/Generators/UmlHandleBarsGenerators/UmlCoreTextualNotationBuilderGenerator.cs +++ b/SysML2.NET.CodeGenerator/Generators/UmlHandleBarsGenerators/UmlCoreTextualNotationBuilderGenerator.cs @@ -59,6 +59,12 @@ public class UmlCoreTextualNotationBuilderGenerator: UmlHandleBarsGenerator /// private const string SharedBuilderTemplateName = "core-textual-notation-shared-builder-template"; + /// + /// The root rule from which grammar reachability is computed to flag + /// methods. + /// + private const string RootRuleName = "RootNamespace"; + /// /// Register the custom helpers /// @@ -173,6 +179,10 @@ private async Task GenerateBuilderClassesInternal(XmiReaderResult xmiReaderResul { var template = this.Templates[BuilderTemplateName]; + var unreachableRuleNames = textualNotationSpecification.ComputeUnreachableRuleNames(RootRuleName) + .Except(RulesHelper.HandCodedReachableRuleNames) + .ToHashSet(); + var namedElements = xmiReaderResult.QueryContainedAndImported("SysML") .SelectMany(x => x.PackagedElement.OfType()) .ToList(); @@ -202,7 +212,7 @@ private async Task GenerateBuilderClassesInternal(XmiReaderResult xmiReaderResul { var targetClassContext = namedElements.Single(x => x.Name == rulesPerType.Key); - var generatedBuilder = template(new {Context = targetClassContext, Rules = rulesPerType.Value, AllRules = textualNotationSpecification.Rules}); + var generatedBuilder = template(new {Context = targetClassContext, Rules = rulesPerType.Value, AllRules = textualNotationSpecification.Rules, UnreachableRuleNames = unreachableRuleNames}); generatedBuilder = this.CodeCleanup(generatedBuilder); var fileName = $"{targetClassContext.Name.CapitalizeFirstLetter()}TextualNotationBuilder.cs"; @@ -282,7 +292,11 @@ private async Task GenerateSharedBuilderInternal(XmiReaderResult xmiReaderResult return; } - var generatedBuilder = template(new { Entries = entries, AllRules = textualNotationSpecification.Rules }); + var unreachableRuleNames = textualNotationSpecification.ComputeUnreachableRuleNames(RootRuleName) + .Except(RulesHelper.HandCodedReachableRuleNames) + .ToHashSet(); + + var generatedBuilder = template(new { Entries = entries, AllRules = textualNotationSpecification.Rules, UnreachableRuleNames = unreachableRuleNames }); generatedBuilder = this.CodeCleanup(generatedBuilder); await WriteAsync(generatedBuilder, outputDirectory, $"{RulesHelper.SharedBuilderClassName}.cs"); diff --git a/SysML2.NET.CodeGenerator/Grammar/Model/TextualNotationRule.cs b/SysML2.NET.CodeGenerator/Grammar/Model/TextualNotationRule.cs index c20e2533..bee5175a 100644 --- a/SysML2.NET.CodeGenerator/Grammar/Model/TextualNotationRule.cs +++ b/SysML2.NET.CodeGenerator/Grammar/Model/TextualNotationRule.cs @@ -359,5 +359,88 @@ when string.Equals(assignmentElement.Property, propertyName, StringComparison.Or } } } + + /// + /// Recursively resolves the names of all rules transitively reachable from this rule via + /// NonTerminal references, including this rule itself. + /// + /// All available rules for resolving NonTerminal references + /// The set of reachable rule names + public IReadOnlySet QueryReachableRuleNames(IReadOnlyList allRules) + { + var visited = new HashSet(); + CollectReachableRuleNames(this, allRules, visited); + return visited; + } + + /// + /// Recursively collects the names of rules reachable from + /// + /// The rule to inspect + /// All available rules for resolving NonTerminal references + /// The accumulated set of reachable rule names + private static void CollectReachableRuleNames(TextualNotationRule rule, IReadOnlyList allRules, HashSet visited) + { + if (!visited.Add(rule.RuleName)) + { + return; + } + + foreach (var alternative in rule.Alternatives) + { + CollectReachableRuleNamesFromElements(alternative.Elements, allRules, visited); + } + } + + /// + /// Recursively collects reachable rule names from a list of + /// + /// The elements to inspect + /// All available rules for resolving NonTerminal references + /// The accumulated set of reachable rule names + private static void CollectReachableRuleNamesFromElements(IEnumerable elements, IReadOnlyList allRules, HashSet visited) + { + foreach (var element in elements) + { + switch (element) + { + case AssignmentElement { Value: NonTerminalElement valueNonTerminal }: + var valueRule = allRules.SingleOrDefault(x => x.RuleName == valueNonTerminal.Name); + + if (valueRule != null) + { + CollectReachableRuleNames(valueRule, allRules, visited); + } + + break; + + case AssignmentElement { Value: GroupElement valueGroupElement }: + foreach (var valueGroupAlternative in valueGroupElement.Alternatives) + { + CollectReachableRuleNamesFromElements(valueGroupAlternative.Elements, allRules, visited); + } + + break; + + case NonTerminalElement nonTerminalElement: + var referencedRule = allRules.SingleOrDefault(x => x.RuleName == nonTerminalElement.Name); + + if (referencedRule != null) + { + CollectReachableRuleNames(referencedRule, allRules, visited); + } + + break; + + case GroupElement groupElement: + foreach (var groupAlternative in groupElement.Alternatives) + { + CollectReachableRuleNamesFromElements(groupAlternative.Elements, allRules, visited); + } + + break; + } + } + } } } diff --git a/SysML2.NET.CodeGenerator/Grammar/Model/TextualNotationSpecification.cs b/SysML2.NET.CodeGenerator/Grammar/Model/TextualNotationSpecification.cs index affae75c..96465421 100644 --- a/SysML2.NET.CodeGenerator/Grammar/Model/TextualNotationSpecification.cs +++ b/SysML2.NET.CodeGenerator/Grammar/Model/TextualNotationSpecification.cs @@ -20,7 +20,9 @@ namespace SysML2.NET.CodeGenerator.Grammar.Model { + using System; using System.Collections.Generic; + using System.Linq; /// /// Provides access to all defined into the textual notation specification @@ -31,5 +33,27 @@ public class TextualNotationSpecification /// Gets the collection of all /// public List Rules { get; } = []; + + /// + /// Computes the names of rules that have no incoming reference — directly or transitively — + /// from the rule named , and are therefore unreachable when + /// generating from that root. + /// + /// The name of the root rule (e.g. RootNamespace) + /// The set of unreachable rule names + /// If no rule named exists + public IReadOnlySet ComputeUnreachableRuleNames(string rootRuleName) + { + var rootRule = this.Rules.SingleOrDefault(x => x.RuleName == rootRuleName); + + if (rootRule == null) + { + throw new ArgumentException($"No rule named '{rootRuleName}' exists in this specification.", nameof(rootRuleName)); + } + + var reachableRuleNames = rootRule.QueryReachableRuleNames(this.Rules); + + return this.Rules.Select(x => x.RuleName).Where(name => !reachableRuleNames.Contains(name)).ToHashSet(); + } } } diff --git a/SysML2.NET.CodeGenerator/HandleBarHelpers/RulesHelper.cs b/SysML2.NET.CodeGenerator/HandleBarHelpers/RulesHelper.cs index bbeb610f..0636da97 100644 --- a/SysML2.NET.CodeGenerator/HandleBarHelpers/RulesHelper.cs +++ b/SysML2.NET.CodeGenerator/HandleBarHelpers/RulesHelper.cs @@ -51,6 +51,23 @@ public static void RegisterRulesHelper(this IHandlebars handlebars) { var processor = new RuleProcessor(); + handlebars.RegisterHelper("RulesHelper.IsRuleUnreachable", (_, arguments) => + { + if (arguments.Length != 2) + { + throw new ArgumentException("RulesHelper.IsRuleUnreachable expects to have 2 arguments"); + } + + if (arguments[0] is not string ruleName) + { + throw new ArgumentException("RulesHelper.IsRuleUnreachable expects a rule name string as first argument"); + } + + return arguments[1] is not IReadOnlySet unreachableRuleNames + ? throw new ArgumentException("RulesHelper.IsRuleUnreachable expects a set of unreachable rule names as second argument") + : unreachableRuleNames.Contains(ruleName); + }); + handlebars.RegisterHelper("RulesHelper.ContainsAnyDispatcherRules", (_, arguments) => { if (arguments.Length != 1) @@ -183,6 +200,17 @@ private static bool RequiresHandCodedBody(string ruleName) return string.Equals(ruleName, "FunctionOperationExpression", StringComparison.Ordinal) ; } + /// + /// Rule names the KEBNF-text-only reachability walk cannot see being reached, because the + /// only remaining reference to them lives in a hand-coded Build{Rule}HandCoded companion + /// rather than in the merged grammar. PayloadFeatureMember is called from + /// SharedTextualNotationBuilder.BuildFlowDeclarationHandCoded, which reimplements KerML's + /// FlowDeclaration : Flow - a rule the SysML-overrides-KerML merge (keyed on bare rule name) + /// drops in favour of SysML's unrelated FlowDeclaration : FlowUsage, taking with it the + /// merged grammar's only textual reference to PayloadFeatureMember. + /// + public static readonly IReadOnlySet HandCodedReachableRuleNames = new HashSet { "PayloadFeatureMember" }; + /// /// Determines whether targets an IOperatorExpression /// (or any of its subclasses) as the rule's effective metaclass. Used by diff --git a/SysML2.NET.CodeGenerator/Templates/Uml/core-textual-notation-builder-template.hbs b/SysML2.NET.CodeGenerator/Templates/Uml/core-textual-notation-builder-template.hbs index 9707f02a..4116fefb 100644 --- a/SysML2.NET.CodeGenerator/Templates/Uml/core-textual-notation-builder-template.hbs +++ b/SysML2.NET.CodeGenerator/Templates/Uml/core-textual-notation-builder-template.hbs @@ -41,6 +41,9 @@ namespace SysML2.NET.Serializer.TextualNotation.Writers /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + {{#if (RulesHelper.IsRuleUnreachable rule.RuleName ../this.UnreachableRuleNames)}} + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] + {{/if}} public static void Build{{rule.RuleName}}({{ #NamedElement.WriteFullyQualifiedTypeName ../this.Context }} poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { {{RulesHelper.WriteRule rule ../this.Context ../this.AllRules}} diff --git a/SysML2.NET.CodeGenerator/Templates/Uml/core-textual-notation-shared-builder-template.hbs b/SysML2.NET.CodeGenerator/Templates/Uml/core-textual-notation-shared-builder-template.hbs index 943e07b8..f8251592 100644 --- a/SysML2.NET.CodeGenerator/Templates/Uml/core-textual-notation-shared-builder-template.hbs +++ b/SysML2.NET.CodeGenerator/Templates/Uml/core-textual-notation-shared-builder-template.hbs @@ -44,6 +44,9 @@ namespace SysML2.NET.Serializer.TextualNotation.Writers /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + {{#if (RulesHelper.IsRuleUnreachable entry.Rule.RuleName ../this.UnreachableRuleNames)}} + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] + {{/if}} public static void Build{{entry.Rule.RuleName}}({{ #NamedElement.WriteFullyQualifiedTypeName entry.TargetClass }} poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { {{RulesHelper.WriteRule entry.Rule entry.TargetClass ../this.AllRules}} diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ElementTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ElementTextualNotationBuilder.cs index 51c24382..5b4669d8 100644 --- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ElementTextualNotationBuilder.cs +++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ElementTextualNotationBuilder.cs @@ -172,6 +172,7 @@ public static void BuildDefinitionElement(SysML2.NET.Core.POCO.Root.Elements.IEl /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildOwnedRelatedElement(SysML2.NET.Core.POCO.Root.Elements.IElement poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { switch (poco) diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureMembershipTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureMembershipTextualNotationBuilder.cs index b0621295..753cb918 100644 --- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureMembershipTextualNotationBuilder.cs +++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureMembershipTextualNotationBuilder.cs @@ -478,6 +478,7 @@ public static void BuildOwnedFeatureMember(SysML2.NET.Core.POCO.Core.Types.IFeat /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildOwnedExpressionReferenceMember(SysML2.NET.Core.POCO.Core.Types.IFeatureMembership poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship); @@ -601,6 +602,7 @@ public static void BuildPayloadFeatureMember(SysML2.NET.Core.POCO.Core.Types.IFe /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildMetadataBodyFeatureMember(SysML2.NET.Core.POCO.Core.Types.IFeatureMembership poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { var effectiveOwnedMemberFeature = SysML2.NET.Serializer.TextualNotation.Writers.SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature(poco); diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureTextualNotationBuilder.cs index ad7952f8..600345ce 100644 --- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureTextualNotationBuilder.cs +++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureTextualNotationBuilder.cs @@ -894,6 +894,7 @@ public static void BuildPrimaryArgument(SysML2.NET.Core.POCO.Core.Features.IFeat /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildNonFeatureChainPrimaryArgument(SysML2.NET.Core.POCO.Core.Features.IFeature poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship); @@ -1133,6 +1134,7 @@ public static void BuildNamedArgument(SysML2.NET.Core.POCO.Core.Features.IFeatur /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildMetadataBodyFeature(SysML2.NET.Core.POCO.Core.Features.IFeature poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship); diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureValueTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureValueTextualNotationBuilder.cs index 4744e113..d52da19d 100644 --- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureValueTextualNotationBuilder.cs +++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureValueTextualNotationBuilder.cs @@ -197,6 +197,7 @@ public static void BuildPrimaryArgumentValue(SysML2.NET.Core.POCO.Kernel.Feature /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildNonFeatureChainPrimaryArgumentValue(SysML2.NET.Core.POCO.Kernel.FeatureValues.IFeatureValue poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MembershipTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MembershipTextualNotationBuilder.cs index c5b5e01f..c73fdf2d 100644 --- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MembershipTextualNotationBuilder.cs +++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MembershipTextualNotationBuilder.cs @@ -181,6 +181,7 @@ public static void BuildInstantiatedTypeMember(SysML2.NET.Core.POCO.Root.Namespa /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildMetadataBodyElement(SysML2.NET.Core.POCO.Root.Namespaces.IMembership poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { switch (poco) diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MetadataFeatureTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MetadataFeatureTextualNotationBuilder.cs index 7e31719e..24b45700 100644 --- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MetadataFeatureTextualNotationBuilder.cs +++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MetadataFeatureTextualNotationBuilder.cs @@ -40,6 +40,7 @@ public static partial class MetadataFeatureTextualNotationBuilder /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildPrefixMetadataFeature(SysML2.NET.Core.POCO.Kernel.Metadata.IMetadataFeature poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship); diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MetadataUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MetadataUsageTextualNotationBuilder.cs index 8552cb0f..0d4f3d65 100644 --- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MetadataUsageTextualNotationBuilder.cs +++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MetadataUsageTextualNotationBuilder.cs @@ -64,6 +64,7 @@ public static void BuildPrefixMetadataUsage(SysML2.NET.Core.POCO.Systems.Metadat /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildMetadataUsageDeclaration(SysML2.NET.Core.POCO.Systems.Metadata.IMetadataUsage poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship); @@ -96,6 +97,7 @@ public static void BuildMetadataUsageDeclaration(SysML2.NET.Core.POCO.Systems.Me /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildMetadataUsage(SysML2.NET.Core.POCO.Systems.Metadata.IMetadataUsage poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship); diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MultiplicityRangeTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MultiplicityRangeTextualNotationBuilder.cs index 1935d7c4..a8ec4d34 100644 --- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MultiplicityRangeTextualNotationBuilder.cs +++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MultiplicityRangeTextualNotationBuilder.cs @@ -40,6 +40,7 @@ public static partial class MultiplicityRangeTextualNotationBuilder /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildOwnedMultiplicityRange(SysML2.NET.Core.POCO.Kernel.Multiplicities.IMultiplicityRange poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { BuildMultiplicityBounds(poco, writerContext, stringBuilder); @@ -53,6 +54,7 @@ public static void BuildOwnedMultiplicityRange(SysML2.NET.Core.POCO.Kernel.Multi /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildMultiplicityBounds(SysML2.NET.Core.POCO.Kernel.Multiplicities.IMultiplicityRange poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship); diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ReferenceUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ReferenceUsageTextualNotationBuilder.cs index fc3da35b..2eb3c5be 100644 --- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ReferenceUsageTextualNotationBuilder.cs +++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ReferenceUsageTextualNotationBuilder.cs @@ -256,6 +256,7 @@ public static void BuildAssignmentTargetParameter(SysML2.NET.Core.POCO.Systems.D /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildForVariableDeclaration(SysML2.NET.Core.POCO.Systems.DefinitionAndUsage.IReferenceUsage poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { UsageTextualNotationBuilder.BuildUsageDeclaration(poco, writerContext, stringBuilder); diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/RelationshipTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/RelationshipTextualNotationBuilder.cs index 5741eac6..15bedd8d 100644 --- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/RelationshipTextualNotationBuilder.cs +++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/RelationshipTextualNotationBuilder.cs @@ -80,6 +80,7 @@ public static void BuildRelationshipBody(SysML2.NET.Core.POCO.Root.Elements.IRel /// The from which the rule should be build /// The providing the serialization context for the current /// The that accumulates the entire textual notation with indentation + [GrammarUnreachable("No production in the effective SysML v2 textual grammar (SysML definitions override same-named KerML ones) references this rule, so it can never be reached from RootNamespace.")] public static void BuildRelationshipOwnedElement(SysML2.NET.Core.POCO.Root.Elements.IRelationship poco, TextualNotationWriterContext writerContext, IndentedStringBuilder stringBuilder) { BuildRelationshipOwnedElementHandCoded(poco, writerContext, stringBuilder); diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/GrammarUnreachableAttribute.cs b/SysML2.NET.Serializer.TextualNotation/Writers/GrammarUnreachableAttribute.cs new file mode 100644 index 00000000..a187d7bb --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation/Writers/GrammarUnreachableAttribute.cs @@ -0,0 +1,47 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright 2022-2026 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ------------------------------------------------------------------------------------------------ + +namespace SysML2.NET.Serializer.TextualNotation.Writers +{ + using System; + + /// + /// Marks a generated Build{Rule} method whose grammar rule has no incoming reference, + /// directly or transitively, from any other production in the effective SysML v2 textual + /// grammar rooted at RootNamespace. + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public sealed class GrammarUnreachableAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + /// Why the grammar rule this method implements cannot be reached. + public GrammarUnreachableAttribute(string reason) + { + this.Reason = reason; + } + + /// + /// Gets why the grammar rule this method implements cannot be reached. + /// + public string Reason { get; } + } +} From 673237f5e47e99c068817423b8a47ec997fde41e Mon Sep 17 00:00:00 2001 From: atheate Date: Wed, 9 Sep 2026 16:12:22 +0200 Subject: [PATCH 3/3] [Add] Five pilot-implementation examples to textual-notation validation corpus Redefinition, Generalization, Flow Usage, Binding Connectors, and Interface examples, converted from the SysML v2 pilot implementation's training corpus via its own SysML2XMI tool. Each closes coverage gaps on grammar-reachable rules (Redefinition, Subclassification, Flow, BindingConnector, binary Connector) identified as exercised by no existing test case. Expected/*.sysml baselines are the writer's own captured output, not the pilot's literal source text, since the two differ only in the documented ACCEPT categories (redefines/:>> and specializes/:> keyword aliases, formatting) per CLAUDE.md. PortExample.sysmlx is a shared library dependency for three of the five (Flow Usage, Binding Connectors, Interface), following the same no-baseline-of-its-own pattern as AHFCoreLib/AHFProfileLib. --- .../BindingConnectorsExample.sysml | 24 +++ .../Flow Usage Example/FlowUsageExample.sysml | 10 + .../GeneralizationExample.sysml | 12 ++ .../Interface Example/InterfaceExample.sysml | 13 ++ .../RedefinitionExample.sysml | 21 +++ .../BindingConnectorsExample.sysmlx | 171 ++++++++++++++++++ .../PortExample.sysmlx | 103 +++++++++++ .../FlowUsageExample.sysmlx | 136 ++++++++++++++ .../Flow Usage Example/PortExample.sysmlx | 103 +++++++++++ .../GeneralizationExample.sysmlx | 48 +++++ .../Interface Example/InterfaceExample.sysmlx | 97 ++++++++++ .../Interface Example/PortExample.sysmlx | 103 +++++++++++ .../RedefinitionExample.sysmlx | 97 ++++++++++ .../TextualNotationValidationTestFixture.cs | 5 + 14 files changed, 943 insertions(+) create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Expected/Binding Connectors Example/BindingConnectorsExample.sysml create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Expected/Flow Usage Example/FlowUsageExample.sysml create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Expected/Generalization Example/GeneralizationExample.sysml create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Expected/Interface Example/InterfaceExample.sysml create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Expected/Redefinition Example/RedefinitionExample.sysml create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Validation/Binding Connectors Example/BindingConnectorsExample.sysmlx create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Validation/Binding Connectors Example/PortExample.sysmlx create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Validation/Flow Usage Example/FlowUsageExample.sysmlx create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Validation/Flow Usage Example/PortExample.sysmlx create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Validation/Generalization Example/GeneralizationExample.sysmlx create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Validation/Interface Example/InterfaceExample.sysmlx create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Validation/Interface Example/PortExample.sysmlx create mode 100644 SysML2.NET.Serializer.TextualNotation.Tests/Validation/Redefinition Example/RedefinitionExample.sysmlx diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Binding Connectors Example/BindingConnectorsExample.sysml b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Binding Connectors Example/BindingConnectorsExample.sysml new file mode 100644 index 00000000..015e486a --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Binding Connectors Example/BindingConnectorsExample.sysml @@ -0,0 +1,24 @@ +package 'Binding Connectors Example-1' { + private import 'Port Example'::*; + part def Vehicle; + part def FuelPump; + part def FuelTank; + part vehicle: Vehicle { + part tank: FuelTankAssembly { + port :>> fuelTankPort { + out item :>> fuelSupply; + in item :>> fuelReturn; + } + bind fuelTankPort.fuelSupply = pump.pumpOut; + bind fuelTankPort.fuelReturn = tank.fuelIn; + part pump: FuelPump { + out item pumpOut: Fuel; + in item pumpIn: Fuel; + } + part tank: FuelTank { + out item fuelOut: Fuel; + in item fuelIn: Fuel; + } + } + } +} diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Flow Usage Example/FlowUsageExample.sysml b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Flow Usage Example/FlowUsageExample.sysml new file mode 100644 index 00000000..6f9e4a07 --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Flow Usage Example/FlowUsageExample.sysml @@ -0,0 +1,10 @@ +package 'Flow Usage Example' { + private import 'Port Example'::*; + part def Vehicle; + part vehicle: Vehicle { + part tankAssy: FuelTankAssembly; + part eng: Engine; + flow of Fuel from tankAssy.fuelTankPort.fuelSupply to eng.engineFuelPort.fuelSupply; + flow of Fuel from eng.engineFuelPort.fuelReturn to tankAssy.fuelTankPort.fuelReturn; + } +} diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Generalization Example/GeneralizationExample.sysml b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Generalization Example/GeneralizationExample.sysml new file mode 100644 index 00000000..b59839f6 --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Generalization Example/GeneralizationExample.sysml @@ -0,0 +1,12 @@ +package 'Generalization Example' { + abstract part def Vehicle; + part def HumanDrivenVehicle :> Vehicle { + ref part driver: Person; + } + part def PoweredVehicle :> Vehicle { + part eng: Engine; + } + part def HumanDrivenPoweredVehicle :> HumanDrivenVehicle, PoweredVehicle; + part def Engine; + part def Person; +} diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Interface Example/InterfaceExample.sysml b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Interface Example/InterfaceExample.sysml new file mode 100644 index 00000000..42a99cac --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Interface Example/InterfaceExample.sysml @@ -0,0 +1,13 @@ +package 'Interface Example' { + private import 'Port Example'::*; + part def Vehicle; + interface def FuelInterface { + end supplierPort: FuelOutPort; + end consumerPort: FuelInPort; + } + part vehicle: Vehicle { + part tankAssy: FuelTankAssembly; + part eng: Engine; + interface : FuelInterface connect supplierPort ::> tankAssy.fuelTankPort to consumerPort ::> eng.engineFuelPort; + } +} diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Redefinition Example/RedefinitionExample.sysml b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Redefinition Example/RedefinitionExample.sysml new file mode 100644 index 00000000..a4641e69 --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Expected/Redefinition Example/RedefinitionExample.sysml @@ -0,0 +1,21 @@ +package 'Redefinition Example' { + part def Vehicle { + part eng: Engine; + } + part def SmallVehicle :> Vehicle { + part smallEng: SmallEngine :>> eng; + } + part def BigVehicle :> Vehicle { + part bigEng: BigEngine :>> eng; + } + part def Engine { + part cyl: Cylinder[4..6]; + } + part def SmallEngine :> Engine { + part :>> cyl[4]; + } + part def BigEngine :> Engine { + part :>> cyl[6]; + } + part def Cylinder; +} diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Binding Connectors Example/BindingConnectorsExample.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Binding Connectors Example/BindingConnectorsExample.sysmlx new file mode 100644 index 00000000..6c0ec311 --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Binding Connectors Example/BindingConnectorsExample.sysmlx @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Binding Connectors Example/PortExample.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Binding Connectors Example/PortExample.sysmlx new file mode 100644 index 00000000..12369ac6 --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Binding Connectors Example/PortExample.sysmlx @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Flow Usage Example/FlowUsageExample.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Flow Usage Example/FlowUsageExample.sysmlx new file mode 100644 index 00000000..f5886142 --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Flow Usage Example/FlowUsageExample.sysmlx @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Flow Usage Example/PortExample.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Flow Usage Example/PortExample.sysmlx new file mode 100644 index 00000000..12369ac6 --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Flow Usage Example/PortExample.sysmlx @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Generalization Example/GeneralizationExample.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Generalization Example/GeneralizationExample.sysmlx new file mode 100644 index 00000000..8e78644f --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Generalization Example/GeneralizationExample.sysmlx @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Interface Example/InterfaceExample.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Interface Example/InterfaceExample.sysmlx new file mode 100644 index 00000000..cf19cf4a --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Interface Example/InterfaceExample.sysmlx @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Interface Example/PortExample.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Interface Example/PortExample.sysmlx new file mode 100644 index 00000000..12369ac6 --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Interface Example/PortExample.sysmlx @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Redefinition Example/RedefinitionExample.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Redefinition Example/RedefinitionExample.sysmlx new file mode 100644 index 00000000..3022643f --- /dev/null +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/Redefinition Example/RedefinitionExample.sysmlx @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Writers/TextualNotationValidationTestFixture.cs b/SysML2.NET.Serializer.TextualNotation.Tests/Writers/TextualNotationValidationTestFixture.cs index 527100b6..b3f60384 100644 --- a/SysML2.NET.Serializer.TextualNotation.Tests/Writers/TextualNotationValidationTestFixture.cs +++ b/SysML2.NET.Serializer.TextualNotation.Tests/Writers/TextualNotationValidationTestFixture.cs @@ -171,6 +171,11 @@ public void OneTimeTearDown() [TestCase("Simple Tests", "UseCaseTest.sysmlx")] [TestCase("Simple Tests", "VariabilityTest.sysmlx")] [TestCase("Arrowhead Framework Example", "AHFNorwayTopics.sysmlx")] + [TestCase("Redefinition Example", "RedefinitionExample.sysmlx")] + [TestCase("Generalization Example", "GeneralizationExample.sysmlx")] + [TestCase("Flow Usage Example", "FlowUsageExample.sysmlx")] + [TestCase("Binding Connectors Example", "BindingConnectorsExample.sysmlx")] + [TestCase("Interface Example", "InterfaceExample.sysmlx")] public async Task VerifyValidationTextualNotationXmi(string folderName, string fileName) { var loggerFactory = LoggerFactory.Create(builder =>