From c1c9bad8b98571d1f1291369cd39855867d7efaf Mon Sep 17 00:00:00 2001 From: adriancostin-sd Date: Tue, 4 Nov 2025 09:16:55 +0200 Subject: [PATCH 01/50] Release 7.8.1 - Timing wird dynamisch bestimmt (#27), update nth stream lib test definition --- gradle.properties | 2 +- .../AttributeUsage2PortSymbolAdapter.java | 15 ++++++++++++--- .../resources/cocos/constraints/4_valid.sysml | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index 72d223ad..7f67428c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.0 +version = 7.8.1 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java index d6844f99..4350c499 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java @@ -2,7 +2,9 @@ import de.monticore.lang.componentconnector._symboltable.MildPortSymbol; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; +import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; import de.monticore.symbols.compsymbols._symboltable.ICompSymbolsScope; import de.monticore.symbols.compsymbols._symboltable.Timing; import de.monticore.types.check.SymTypeExpressionFactory; @@ -26,9 +28,7 @@ public AttributeUsage2PortSymbolAdapter( this.adaptee = adaptee; this.incoming = incoming; this.outgoing = !this.incoming; - // TODO Timing aus Komponente frickeln, in der die PortUsage liegt in deren Definition das Attribut liegt - this.timing = Timing.TIMED; - // TODO s.o. + this.timing = determineTiming(container); this.stronglyCausal = container.isStrong(); // Das muss anscheinend gesetzt sein, weil die MC-Interna immer über das Feld herausfinden, ob sie getEnclosingScope @@ -71,6 +71,15 @@ public Timing getTiming() { return timing; } + private Timing determineTiming(PortUsageSymbol container) { + var scope = (ISysMLv2Scope) container.getEnclosingScope(); + + boolean hasTsyn = scope.getLocalStateUsageSymbols().stream() + .anyMatch(sym -> sym.getUserDefinedKeywordsList().contains("tsyn")); + + return hasTsyn ? Timing.TIMED_SYNC : Timing.TIMED; + } + @Override public boolean equals(Object other) { if(other instanceof AttributeUsage2PortSymbolAdapter) { diff --git a/language/src/test/resources/cocos/constraints/4_valid.sysml b/language/src/test/resources/cocos/constraints/4_valid.sysml index ac0d6851..31becb82 100644 --- a/language/src/test/resources/cocos/constraints/4_valid.sysml +++ b/language/src/test/resources/cocos/constraints/4_valid.sysml @@ -7,6 +7,6 @@ part def LogicBasedConstraints { port myPortDef: Integers; constraint constraintName { - myPortDef.natAttr.nth(3).nth(3).get() > 1 + myPortDef.natAttr.nth(3).nth(3) > 1 } } From 228573790b764906016bbc0fa03de0fbbe036919 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Fri, 9 Jan 2026 10:38:56 +0100 Subject: [PATCH 02/50] Backporting typecheck3 to 7.8.x (#40) * TypeCheck3 with Streams (#30) ## Changelog ### Added * TypeCheck3 implementation (Closes #29) * Extended streams compatibility to additionally interpret port usages with one attribute as a C&C ports ### Changed * nat is now a primitive instead of a SymTypeOfObject (for typecheck3 compatibility) * deprecated TypeCheck1, TypeCheck1 CoCos, added TypeCheck3 CoCos ### Fixed * CC Port resolution for FQNs that contain that contain more than two parts * added "::" as potential delimiter for resolution (cherry picked from commit ef2cc5ede0ac1164dde3ecef7e9f8f1c32176968) * #115 version bump to 7.8.2 --------- Co-authored-by: adriancostin-sd --- gradle.properties | 2 +- .../componentconnector/StreamTimingUtil.java | 19 + .../AnonymousUsage2VariableSymbolAdapter.java | 1 - .../AttributeUsage2VariableSymbolAdapter.java | 4 +- .../PortUsage2VariableSymbolAdapter.java | 1 - .../completers/ConvertEnumUsagesToFields.java | 37 +- .../monticore/lang/sysmlv2/SysMLv2Mill.java | 37 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 13 + .../sysmlv2/_symboltable/ISysMLv2Scope.java | 27 +- .../sysmlv2/cocos/AssignActionTypeCheck.java | 1 + .../sysmlv2/cocos/AssignActionTypeCheck3.java | 22 ++ .../sysmlv2/cocos/ConstraintIsBoolean.java | 1 + .../sysmlv2/cocos/ConstraintIsBooleanTC3.java | 41 +++ .../sysmlv2/cocos/SendActionTypeCheck.java | 1 + .../sysmlv2/cocos/SendActionTypeCheck3.java | 21 ++ .../sysmlv2/cocos/SpecializationExists.java | 1 + .../cocos/SpecializationExistsTC3.java | 22 ++ .../cocos/TypeCheck3TransitionGuards.java | 39 +++ .../cocos/TypeCheckTransitionGuards.java | 1 + .../adapters/ConfigurationWrapper.java | 5 +- .../symboltable/adapters/OutputWrapper.java | 1 - .../completers/TypesCompleter.java | 21 +- ...SysMLDeriveSymTypeOfStreamExpressions.java | 1 + .../lang/sysmlv2/types/SysMLDeriver.java | 1 + .../sysmlv2/types/SysMLExressionsDeriver.java | 1 + .../lang/sysmlv2/types/SysMLSynthesizer.java | 1 + ...sMLv2DeriveSymTypeOfCommonExpressions.java | 1 + .../SysMLCommonExpressionsTypeVisitor.java | 326 ++++++++++++++++++ .../types3/SysMLMCBasicTypesTypeVisitor.java | 15 + .../SysMLOCLExpressionsTypeVisitor.java | 13 + .../SysMLSetExpressionsTypeVisitor.java | 23 ++ .../sysmlv2/types3/SysMLSymTypeRelations.java | 28 ++ .../lang/sysmlv2/types3/SysMLTypeCheck3.java | 101 ++++++ .../SysMLTypeVisitorOperatorCalculator.java | 51 +++ .../SysMLWithinScopeBasicSymbolResolver.java | 213 ++++++++++++ .../test/java/cocos/ConstraintCoCoTest.java | 7 +- .../test/java/types3/ConstraintCoCoTest.java | 202 +++++++++++ ...AccessExpressionInConstraintUsageTest.java | 157 +++++++++ ...FieldAccessExpressionInStateUsageTest.java | 251 ++++++++++++++ .../src/test/java/types3/NegationTest.java | 156 +++++++++ .../java/types3/SpecializationExistsTest.java | 111 ++++++ .../StreamConstructorExpressionsTest.java | 186 ++++++++++ .../TC3FieldAccessInteroperabilityTest.java | 200 +++++++++++ .../cocos/constraints/17_invalid.sysml | 15 + .../cocos/constraints/17_valid.sysml | 15 + .../cocos/constraints/18_invalid.sysml | 14 + .../cocos/constraints/18_valid.sysml | 14 + .../implicitFieldAccess/11_invalid.sysml | 12 + .../implicitFieldAccess/11_valid.sysml | 12 + .../implicitFieldAccess/14_invalid.sysml | 14 + .../implicitFieldAccess/14_valid.sysml | 14 + .../implicitFieldAccess/15_invalid.sysml | 12 + .../implicitFieldAccess/15_valid.sysml | 12 + .../implicitFieldAccess/17_invalid.sysml | 14 + .../implicitFieldAccess/17_valid.sysml | 14 + .../implicitFieldAccess/18_invalid.sysml | 14 + .../implicitFieldAccess/18_valid.sysml | 14 + .../implicitFieldAccess/19_invalid.sysml | 12 + .../implicitFieldAccess/19_valid.sysml | 12 + .../implicitFieldAccess/2_invalid.sysml | 17 + .../implicitFieldAccess/2_valid.sysml | 13 + .../implicitFieldAccess/4_invalid.sysml | 12 + .../implicitFieldAccess/4_valid.sysml | 12 + 63 files changed, 2582 insertions(+), 49 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/componentconnector/StreamTimingUtil.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck3.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBooleanTC3.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck3.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExistsTC3.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheck3TransitionGuards.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLMCBasicTypesTypeVisitor.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSetExpressionsTypeVisitor.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSymTypeRelations.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeVisitorOperatorCalculator.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLWithinScopeBasicSymbolResolver.java create mode 100644 language/src/test/java/types3/ConstraintCoCoTest.java create mode 100644 language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java create mode 100644 language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java create mode 100644 language/src/test/java/types3/NegationTest.java create mode 100644 language/src/test/java/types3/SpecializationExistsTest.java create mode 100644 language/src/test/java/types3/StreamConstructorExpressionsTest.java create mode 100644 language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java create mode 100644 language/src/test/resources/cocos/constraints/17_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/17_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/18_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/18_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/11_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/11_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/14_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/14_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/15_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/15_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/17_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/17_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/18_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/18_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/19_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/19_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/2_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/2_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/4_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/4_valid.sysml diff --git a/gradle.properties b/gradle.properties index 7f67428c..cda01f97 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.1 +version = 7.8.2 diff --git a/language/src/main/java/de/monticore/lang/componentconnector/StreamTimingUtil.java b/language/src/main/java/de/monticore/lang/componentconnector/StreamTimingUtil.java new file mode 100644 index 00000000..0482bfd3 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/componentconnector/StreamTimingUtil.java @@ -0,0 +1,19 @@ +package de.monticore.lang.componentconnector; + +import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; +import de.monticore.symbols.compsymbols._symboltable.Timing; + +public class StreamTimingUtil { + public static String mapTimingToStreamType(Timing timing) { + switch (timing) { + case TIMED: + return "EventStream"; + case TIMED_SYNC: + return "SyncStream"; + case UNTIMED: + return "UntimedStream"; + default: + throw new IllegalArgumentException("Unexpected value: " + timing); + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AnonymousUsage2VariableSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AnonymousUsage2VariableSymbolAdapter.java index 8ec62bfd..9c7ec4d0 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AnonymousUsage2VariableSymbolAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AnonymousUsage2VariableSymbolAdapter.java @@ -14,7 +14,6 @@ public class AnonymousUsage2VariableSymbolAdapter extends FieldSymbol { public AnonymousUsage2VariableSymbolAdapter(AnonymousUsageSymbol adaptee) { super(adaptee.getName()); this.adaptee = adaptee; - this.accessModifier = adaptee.getAccessModifier(); } protected AnonymousUsageSymbol getAdaptee() { diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AttributeUsage2VariableSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AttributeUsage2VariableSymbolAdapter.java index ce15c4ff..fc553293 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AttributeUsage2VariableSymbolAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AttributeUsage2VariableSymbolAdapter.java @@ -5,6 +5,7 @@ import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.symbols.oosymbols._symboltable.FieldSymbol; import de.monticore.symbols.oosymbols._symboltable.IOOSymbolsScope; +import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.types.check.SymTypeExpression; import de.se_rwth.commons.SourcePosition; @@ -14,7 +15,8 @@ public class AttributeUsage2VariableSymbolAdapter extends FieldSymbol { public AttributeUsage2VariableSymbolAdapter(AttributeUsageSymbol adaptee) { super(adaptee.getName()); this.adaptee = adaptee; - this.accessModifier = adaptee.getAccessModifier(); + // For the time being field is public for TypeCheck compatibility + this.setIsPublic(true); } protected AttributeUsageSymbol getAdaptee() { diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/PortUsage2VariableSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/PortUsage2VariableSymbolAdapter.java index eaa8bbc0..7bdd4891 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/PortUsage2VariableSymbolAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/PortUsage2VariableSymbolAdapter.java @@ -13,7 +13,6 @@ public class PortUsage2VariableSymbolAdapter extends VariableSymbol { public PortUsage2VariableSymbolAdapter(PortUsageSymbol adaptee) { super(adaptee.getName()); this.adaptee = adaptee; - this.accessModifier = adaptee.getAccessModifier(); } protected PortUsageSymbol getAdaptee() { diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/ConvertEnumUsagesToFields.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/ConvertEnumUsagesToFields.java index 05161f14..477a61aa 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/ConvertEnumUsagesToFields.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/ConvertEnumUsagesToFields.java @@ -1,5 +1,7 @@ package de.monticore.lang.sysmlparts.symboltable.completers; +import de.monticore.lang.sysmlbasis._ast.ASTAnonymousReference; +import de.monticore.lang.sysmlbasis._ast.ASTSysMLTyping; import de.monticore.lang.sysmlparts.SysMLPartsMill; import de.monticore.lang.sysmlparts._ast.ASTEnumDef; import de.monticore.lang.sysmlparts._ast.ASTEnumUsage; @@ -10,7 +12,7 @@ * Enum-Literale sollen sich wie Fields verhalten. Allerdings haben die Dinger nicht immer einen Namen (auf * Lexer/Parser-Ebene). Deswegen kann man nicht einfach "EnumUsage extends Field = ..." in die Grammatik schreiben. Die * empfohlene Lösung des MC-Teams ist es die EnumUsageSymbols einfach duch FieldSymbols auszutauschen bzw. diese - * hinzuzufügen. + * hinzuzufügen. Das gleiche für AnonymousReference. */ public class ConvertEnumUsagesToFields implements SysMLPartsVisitor2 { @@ -20,21 +22,28 @@ public void visit(ASTEnumDef node) { var type = SymTypeExpressionFactory.createTypeObject(node.getName(), node.getEnclosingScope()); for(var elem: node.getSysMLElementList()) { - if(elem instanceof ASTEnumUsage) { - var usage = (ASTEnumUsage) elem; + var baseBuilder = SysMLPartsMill.fieldSymbolBuilder() + .setAstNodeAbsent() + .setIsStatic(true) + .setIsPublic(true) + .setType(type); + + if(elem instanceof ASTEnumUsage && ((ASTEnumUsage)elem).isPresentName()) { // each named enum usage behaves like a static field whose type is the enclosing def - if(usage.isPresentName()) { - var field = SysMLPartsMill.fieldSymbolBuilder() - .setAstNodeAbsent() - .setName(usage.getName()) - .setIsStatic(true) - .setType(type) - .build(); - node.getSpannedScope().add(field); - } + baseBuilder.setName(((ASTEnumUsage)elem).getName()); + node.getSpannedScope().add(baseBuilder.build()); + } + else if (elem instanceof ASTAnonymousReference && + ((ASTAnonymousReference)elem).getSpecializationList() + .stream() + .filter(spec -> spec instanceof ASTSysMLTyping) + .findAny() + .isEmpty()) { + // same for anonymous references in this context that do not have a type + // cannot use completed type because we are in the ordered ST completion phase + baseBuilder.setName(((ASTAnonymousReference) elem).getName()); + node.getSpannedScope().add(baseBuilder.build()); } } - } - } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java index 890c5be2..04fd57b2 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java @@ -31,10 +31,7 @@ public class SysMLv2Mill extends SysMLv2MillTOP { public static void prepareGlobalScope() { SysMLv2Mill.initializePrimitives(); SysMLv2Mill.addStringType(); - // Doppelt gemoppelt? - MCCollectionSymTypeRelations.init(); SysMLv2Mill.addCollectionTypes(); - OCLSymTypeRelations.init(); } /** @@ -71,7 +68,7 @@ protected void _addStringType() { var type = OOSymbolsMill.oOTypeSymbolBuilder() .setName("String") - .setSpannedScope(new OOSymbolsScope()) + .setSpannedScope(scope()) .build(); SysMLv2Mill.globalScope().add(type); @@ -80,14 +77,14 @@ protected void _addStringType() { protected OOTypeSymbol buildOptionalType() { var typeVar = BasicSymbolsMill.typeVarSymbolBuilder().setName("T").build(); - var spannedScope = new OOSymbolsScope(); + var spannedScope = scope(); spannedScope.add(typeVar); spannedScope.add( SysMLv2Mill.functionSymbolBuilder() .setName("get") .setType(SymTypeExpressionFactory.createTypeVariable(typeVar)) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build() ); @@ -123,7 +120,7 @@ protected void _addStreamType() { protected OOTypeSymbol buildStreamType() { var typeVar = BasicSymbolsMill.typeVarSymbolBuilder().setName("E").build(); - var spannedScope = new OOSymbolsScope(); + var spannedScope = scope(); spannedScope.add(typeVar); spannedScope.add(buildSnthFunction(typeVar)); spannedScope.add(buildLengthFunction()); @@ -175,7 +172,7 @@ protected void _addCollectionTypes() { } protected OOTypeSymbol buildCollectionType(String name, String... typeVars) { - var spannedScope = new OOSymbolsScope(); + var spannedScope = scope(); Arrays .stream(typeVars) @@ -200,7 +197,7 @@ protected SymTypePrimitive buildNatType() { } protected FunctionSymbol buildSnthFunction(TypeVarSymbol typeVar) { - var parameterList = new BasicSymbolsScope(); + var parameterList = scope(); VariableSymbol parameter = SysMLv2Mill.variableSymbolBuilder().setName( "n").setType(buildIntType()).build(); @@ -221,7 +218,7 @@ protected FunctionSymbol buildLengthFunction() { return SysMLv2Mill.functionSymbolBuilder() .setName("length") .setType(buildIntType()) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } @@ -229,7 +226,7 @@ protected FunctionSymbol buildCountFunction() { return SysMLv2Mill.functionSymbolBuilder() .setName("count") .setType(buildIntType()) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } @@ -237,7 +234,7 @@ protected FunctionSymbol buildHeadFunction(TypeVarSymbol typeVar) { return SysMLv2Mill.functionSymbolBuilder() .setName("head") .setType(SymTypeExpressionFactory.createTypeVariable(typeVar)) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } @@ -249,13 +246,13 @@ protected FunctionSymbol buildTailFunction(TypeSymbol listSymbol, listSymbol, SymTypeExpressionFactory.createTypeVariable(typeVar)) ) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } protected FunctionSymbol buildAppendFunction(TypeSymbol listSymbol, TypeVarSymbol typeVar) { - var scope = new BasicSymbolsScope(); + var scope = scope(); scope.add(SysMLv2Mill.variableSymbolBuilder() .setName("xs") .setType(SymTypeExpressionFactory.createGenerics( @@ -281,12 +278,12 @@ protected FunctionSymbol buildValuesFunction(TypeVarSymbol typeVar) { listSymbol, SymTypeExpressionFactory.createTypeVariable(typeVar)) ) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } protected FunctionSymbol buildTimesFunction(TypeSymbol streamSymbol, TypeVarSymbol typeVar) { - var parameterList = new BasicSymbolsScope(); + var parameterList = scope(); VariableSymbol parameter = SysMLv2Mill.variableSymbolBuilder().setName( "k").setType(buildNatType()).build(); @@ -304,7 +301,7 @@ protected FunctionSymbol buildTimesFunction(TypeSymbol streamSymbol, TypeVarSymb protected FunctionSymbol buildAtTimeFunction(TypeSymbol streamSymbol, TypeVarSymbol typeVar) { - var scope = new BasicSymbolsScope(); + var scope = scope(); scope.add(SysMLv2Mill.variableSymbolBuilder() .setName("t") .setType(buildNatType()) @@ -328,12 +325,12 @@ protected FunctionSymbol buildMessagesFunction(TypeSymbol streamSymbol, streamSymbol, SymTypeExpressionFactory.createTypeVariable(typeVar)) ) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } protected FunctionSymbol buildTakesFunction(TypeSymbol streamSymbol, TypeVarSymbol typeVar) { - var parameterList = new BasicSymbolsScope(); + var parameterList = scope(); VariableSymbol parameter = SysMLv2Mill.variableSymbolBuilder() .setName("k") @@ -356,7 +353,7 @@ protected FunctionSymbol buildTakesFunction(TypeSymbol streamSymbol, TypeVarSymb } protected FunctionSymbol buildInfTimesFunction(TypeSymbol streamSymbol, TypeVarSymbol typeVar) { - var parameterList = new BasicSymbolsScope(); + var parameterList = scope(); parameterList.add(typeVar); var returnType = SymTypeExpressionFactory.createGenerics( diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index df9e98ae..bb49c544 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -24,7 +24,9 @@ import de.monticore.lang.sysmlv2._symboltable.SysMLv2Symbols2Json; import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck; +import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck3; import de.monticore.lang.sysmlv2.cocos.ConstraintIsBoolean; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; import de.monticore.lang.sysmlv2.cocos.FlowCheckCoCo; import de.monticore.lang.sysmlv2.cocos.NameCompatible4Isabelle; import de.monticore.lang.sysmlv2.cocos.OneCardinality; @@ -32,9 +34,12 @@ import de.monticore.lang.sysmlv2.cocos.PortDefinitionExistsCoCo; import de.monticore.lang.sysmlv2.cocos.RefinementCyclic; import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck; +import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck3; import de.monticore.lang.sysmlv2.cocos.SpecializationExists; +import de.monticore.lang.sysmlv2.cocos.SpecializationExistsTC3; import de.monticore.lang.sysmlv2.cocos.StateSupertypes; import de.monticore.lang.sysmlv2.cocos.TypeCheckTransitionGuards; +import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; import de.monticore.lang.sysmlv2.symboltable.completers.CausalityCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectRefinementCompleter; @@ -46,6 +51,7 @@ import de.monticore.lang.sysmlv2.symboltable.completers.TypesCompleter; import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.lang.sysmlv2.types.SysMLSynthesizer; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; import de.monticore.ocl.oclexpressions.symboltable.OCLExpressionsSymbolTableCompleter; import de.monticore.prettyprint.IndentPrinter; import de.monticore.symbols.oosymbols._symboltable.MethodSymbolDeSer; @@ -79,6 +85,7 @@ public void init() { SysMLv2Mill.globalScope().clear(); SysMLv2Mill.prepareGlobalScope(); loadStreamSymbolsFromJar(); + SysMLTypeCheck3.init(); } @Override @@ -105,6 +112,10 @@ public void runDefaultCoCos(ASTSysMLModel ast) { checker.addCoCo(new TypeCheckTransitionGuards()); checker.addCoCo(new SendActionTypeCheck()); checker.addCoCo(new AssignActionTypeCheck()); + // TC3 + checker.addCoCo(new SendActionTypeCheck3()); + checker.addCoCo(new AssignActionTypeCheck3()); + checker.addCoCo(new TypeCheck3TransitionGuards()); checker.checkAll(ast); } @@ -118,7 +129,9 @@ public void runAdditionalCoCos( // general checker.addCoCo(new ConstraintIsBoolean()); + checker.addCoCo(new ConstraintIsBooleanTC3()); checker.addCoCo(new SpecializationExists()); + checker.addCoCo(new SpecializationExistsTC3()); // Not-supported language elements checker.addCoCo(new NoExitActions()); diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index f69d3650..e688cbc9 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -40,6 +40,7 @@ import de.se_rwth.commons.Names; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; @@ -280,11 +281,33 @@ default List resolveAdaptedMildPortLocallyMany( // Splitten von Namen - oder ob man irgendwie // nach vollqualifizierten Sachen suchen kann (und vielleicht auch erst // danach schaut, was es war)? + String delimiter; if (name.contains(".")) { - var port = name.split("\\.")[0]; + delimiter = "."; + } + else if (name.contains("::")) { + delimiter = "::"; + } + else { + delimiter = null; + } + + if (delimiter != null) { + List parts = new ArrayList<>(); + int pos = 0; + int idx; + while ((idx = name.indexOf(delimiter, pos)) != -1) { + parts.add(name.substring(pos, idx)); + pos = idx + delimiter.length(); + } + parts.add(name.substring(pos)); + String[] nameParts = parts.toArray(new String[0]); + + // usage could be fully qualified + var port = String.join(delimiter, Arrays.copyOfRange(nameParts, 0, nameParts.length - 1)); var portUsage = resolvePortUsageLocally(port); if (portUsage.isPresent()) { - var attr = name.split("\\.")[1]; + var attr = nameParts[nameParts.length -1]; var input = portUsage.get().getInputAttributes().stream().filter( a -> a.getName().equals(attr)).findFirst(); var output = portUsage.get().getOutputAttributes().stream().filter( diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java index 97ac6265..470c7e66 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java @@ -7,6 +7,7 @@ import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.types.check.TypeCheck; +@Deprecated public class AssignActionTypeCheck implements SysMLActionsASTAssignmentActionUsageCoCo { @Override diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck3.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck3.java new file mode 100644 index 00000000..0e4184ca --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck3.java @@ -0,0 +1,22 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlactions._ast.ASTAssignmentActionUsage; +import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTAssignmentActionUsageCoCo; +import de.monticore.types.check.TypeCheck; +import de.monticore.types3.TypeCheck3; + +public class AssignActionTypeCheck3 implements SysMLActionsASTAssignmentActionUsageCoCo { + + @Override + public void check(ASTAssignmentActionUsage node) { + // Wir gehen davon aus, dass Send-Actions die Kanäle auf Ports nicht als Strom, + // sondern Element-Weise (i.e. Event-basiert) verarbeiten + + var type = TypeCheck3.typeOf(node.getValueExpression()); + if(type.isObscureType()) { + // Error should already be logged? + } + // Vergleich zum Target steht noch aus. + // TODO Target zur Expression erheben (Grammatik ändenr), Checken, dann vergleichen + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java index 1d996e27..da64dfc0 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java @@ -10,6 +10,7 @@ import de.se_rwth.commons.SourcePositionBuilder; import de.se_rwth.commons.logging.Log; +@Deprecated public class ConstraintIsBoolean implements SysMLConstraintsASTConstraintUsageCoCo { @Override public void check(ASTConstraintUsage node) { diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBooleanTC3.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBooleanTC3.java new file mode 100644 index 00000000..1528b02a --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBooleanTC3.java @@ -0,0 +1,41 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlconstraints._cocos.SysMLConstraintsASTConstraintUsageCoCo; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types3.TypeCheck3; +import de.se_rwth.commons.SourcePosition; +import de.se_rwth.commons.SourcePositionBuilder; +import de.se_rwth.commons.logging.Log; + +public class ConstraintIsBooleanTC3 implements SysMLConstraintsASTConstraintUsageCoCo { + + @Override public void check(ASTConstraintUsage node) { + // Expression ausgraben + ASTExpression expr = node.getExpression(); + + try { + SymTypeExpression type = TypeCheck3.typeOf(expr); + if(type.isObscureType()) { + var start = node.get_SourcePositionStart(); + var end = constraintEnd(start); + Log.error("0x80001 Failed to derive a type!", start, end); + } + else if(!type.printFullName().equals("boolean")) { + Log.error("0x80002 The expression type is '" + type.printFullName() + "' but should be boolean!", expr.get_SourcePositionStart(), expr.get_SourcePositionEnd()); + } + } + catch (Exception e) { + var start = node.get_SourcePositionStart(); + var end = constraintEnd(start); + Log.error("0x80003 " + e.getClass().getSimpleName() + " while type checking!", start, end); + } + } + + private SourcePosition constraintEnd(SourcePosition start) { + return new SourcePositionBuilder().setFileName(start.getFileName().get()).setLine(start.getLine()).setColumn( + start.getColumn() + 11).build(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java index bbf0d636..25803f74 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java @@ -4,6 +4,7 @@ import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTSendActionUsageCoCo; import de.monticore.lang.sysmlv2.types.SysMLDeriver; +@Deprecated public class SendActionTypeCheck implements SysMLActionsASTSendActionUsageCoCo { @Override diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck3.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck3.java new file mode 100644 index 00000000..03562cb2 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck3.java @@ -0,0 +1,21 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlactions._ast.ASTSendActionUsage; +import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTSendActionUsageCoCo; +import de.monticore.types3.TypeCheck3; + +public class SendActionTypeCheck3 implements SysMLActionsASTSendActionUsageCoCo { + + @Override + public void check(ASTSendActionUsage node) { + // Wir gehen davon aus, dass Send-Actions die Kanäle auf Ports nicht als Strom, + // sondern Element-Weise (i.e. Event-basiert) verarbeiten + + var payloadType = TypeCheck3.typeOf(node.getPayload()); + if(payloadType.isObscureType()) { + // Error should already be logged? + } + // Vergleich zum Target steht noch aus. + // TODO Target zur Expression erheben (Grammatik ändenr), Checken, dann vergleichen + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java index 1876f560..eabc1000 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java @@ -7,6 +7,7 @@ import de.monticore.lang.sysmlv2.types.SysMLSynthesizer; import de.se_rwth.commons.logging.Log; +@Deprecated public class SpecializationExists implements SysMLBasisASTSpecializationCoCo { @Override diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExistsTC3.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExistsTC3.java new file mode 100644 index 00000000..4a48a70b --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExistsTC3.java @@ -0,0 +1,22 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; +import de.monticore.lang.sysmlbasis._cocos.SysMLBasisASTSpecializationCoCo; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; +import de.monticore.types3.TypeCheck3; + +public class SpecializationExistsTC3 implements SysMLBasisASTSpecializationCoCo { + + @Override + public void check(ASTSpecialization node) { + if (node.getEnclosingScope() instanceof ISysMLv2Scope) { + // We synthesize the SymType from ASTs + for(var typeAst : node.getSuperTypesList()) { + // This will throw an 0xA0324 if the type does not exist. + TypeCheck3.symTypeFromAST(typeAst); + } + } + } + +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheck3TransitionGuards.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheck3TransitionGuards.java new file mode 100644 index 00000000..17a2e5f6 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheck3TransitionGuards.java @@ -0,0 +1,39 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; +import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTSysMLTransitionCoCo; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types3.TypeCheck3; +import de.se_rwth.commons.logging.Log; + +public class TypeCheck3TransitionGuards implements SysMLStatesASTSysMLTransitionCoCo { + + @Override + public void check(ASTSysMLTransition node) { + if(node.isPresentGuard()) { + // Expression ausgraben + ASTExpression expr = node.getGuard(); + + try { + SymTypeExpression type = TypeCheck3.typeOf(expr); + if(type.isObscureType()) { + Log.error("0x80004 Failed to derive a type!", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd()); + } + else if(!type.isPrimitive() || !type.asPrimitive().getPrimitiveName().equals("boolean")) { + Log.error("0x80005 The expression type is '" + type.printFullName() + "' but should be boolean!", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd()); + } + } + catch (Exception e) { + Log.error("0x80006 " + e.getClass().getSimpleName() + " while type checking!", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd()); + } + } + } + +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java index 94780546..15a4f6e5 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java @@ -7,6 +7,7 @@ import de.monticore.types.check.TypeCheckResult; import de.se_rwth.commons.logging.Log; +@Deprecated public class TypeCheckTransitionGuards implements SysMLStatesASTSysMLTransitionCoCo { @Override diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/ConfigurationWrapper.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/ConfigurationWrapper.java index c35ce86b..e6a0bcda 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/ConfigurationWrapper.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/ConfigurationWrapper.java @@ -16,7 +16,6 @@ import de.monticore.lang.sysmlv2._prettyprint.SysMLv2FullPrettyPrinter; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; import de.monticore.lang.sysmlactions.visitors.SendActionAssignmentsVisitor; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.literals.mccommonliterals._symboltable.IMCCommonLiteralsScope; import de.monticore.literals.mcliteralsbasis._symboltable.IMCLiteralsBasisScope; import de.monticore.mcbasics._symboltable.IMCBasicsScope; @@ -24,6 +23,7 @@ import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; import de.monticore.symbols.compsymbols._symboltable.ICompSymbolsScope; import de.monticore.types.mcbasictypes._symboltable.IMCBasicTypesScope; +import de.monticore.types3.TypeCheck3; import de.se_rwth.commons.SourcePosition; import java.util.Collection; @@ -82,8 +82,7 @@ public ConfigurationWrapper( // Wenn der Automat generell Listen senden kann, zB. eine Event- // Automat, dann wird der Typ des Values angeschaut und // entschieden, ob der Output "isListValue" gesetzt bekommt - var typeOfValue = new SysMLDeriver(false) - .deriveType(value).getResult(); + var typeOfValue = TypeCheck3.typeOf(value); if(typeOfValue.printFullName().contains("List")) { isListValue = true; } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/OutputWrapper.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/OutputWrapper.java index 1762ebca..d8fc1083 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/OutputWrapper.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/OutputWrapper.java @@ -11,7 +11,6 @@ import de.monticore.lang.componentconnector._visitor.ComponentConnectorTraverser; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2GlobalScope; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.literals.mccommonliterals._symboltable.IMCCommonLiteralsScope; import de.monticore.literals.mcliteralsbasis._symboltable.IMCLiteralsBasisScope; import de.monticore.mcbasics._symboltable.IMCBasicsScope; diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index 3c3f588c..0c1f1baa 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -1,16 +1,19 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.lang.sysmlv2.symboltable.completers; +import de.monticore.lang.sysmlbasis._ast.ASTAnonymousReference; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousUsage; import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; import de.monticore.lang.sysmlbasis._ast.ASTSysMLParameter; import de.monticore.lang.sysmlbasis._ast.ASTSysMLTyping; +import de.monticore.lang.sysmlbasis._symboltable.AnonymousReferenceSymbol; import de.monticore.lang.sysmlbasis._symboltable.AnonymousUsageSymbol; import de.monticore.lang.sysmlbasis._visitor.SysMLBasisVisitor2; import de.monticore.lang.sysmlconstraints._ast.ASTRequirementSubject; import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; import de.monticore.lang.sysmlconstraints._visitor.SysMLConstraintsVisitor2; import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._ast.ASTEnumDef; import de.monticore.lang.sysmlparts._ast.ASTPartUsage; import de.monticore.lang.sysmlparts._ast.ASTPortUsage; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; @@ -18,6 +21,7 @@ import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; +import de.monticore.symboltable.modifiers.BasicAccessModifier; import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionFactory; import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; @@ -51,7 +55,12 @@ private List getTypeCompletion(List specia (IBasicSymbolsScope) mcType.getEnclosingScope()); } else if(mcType.getDefiningSymbol().isPresent() && mcType.getDefiningSymbol().get() instanceof TypeSymbol) { - res = SymTypeExpressionFactory.createTypeExpression((TypeSymbol) mcType.getDefiningSymbol().get()); + // hacky setup such that nat remains a primitive + if (mcType.getDefiningSymbol().get().getName().equals("nat")) { + res = SymTypeExpressionFactory.createPrimitive((TypeSymbol) mcType.getDefiningSymbol().get()); + } else { + res = SymTypeExpressionFactory.createTypeExpression((TypeSymbol) mcType.getDefiningSymbol().get()); + } } else if(mcType.getDefiningSymbol().isEmpty()) { Log.warn("Defining symbol for " + mcType.printType() + " was not set."); @@ -120,6 +129,8 @@ public void visit(ASTAttributeUsage node) { // type List types = getTypeCompletion(node.getSpecializationList(), false); + symbol.setAccessModifier(BasicAccessModifier.ALL_INCLUSION); + symbol.setTypesList(types); } } @@ -144,4 +155,12 @@ public void visit(ASTRequirementSubject node) { } } + @Override + public void visit(ASTAnonymousReference node) { + if(node.isPresentSymbol()) { + AnonymousReferenceSymbol symbol = node.getSymbol(); + List types = getTypeCompletion(node.getSpecializationList(), false); + symbol.setTypesList(types); + } + } } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriveSymTypeOfStreamExpressions.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriveSymTypeOfStreamExpressions.java index f2ba75b4..bc7ccb9c 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriveSymTypeOfStreamExpressions.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriveSymTypeOfStreamExpressions.java @@ -13,6 +13,7 @@ import java.util.List; +@Deprecated public class SysMLDeriveSymTypeOfStreamExpressions extends AbstractDeriveFromExpression implements StreamExpressionsVisitor2, StreamExpressionsHandler { diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriver.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriver.java index 1f90e20c..e59805cf 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriver.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriver.java @@ -13,6 +13,7 @@ import de.monticore.types.check.DeriveSymTypeOfMCCommonLiterals; import de.monticore.types.check.SynthesizeSymTypeFromMCBasicTypes; +@Deprecated public class SysMLDeriver extends AbstractDerive { /** *

{@code isStream} is used to determine whether the type of the expression is calculated as a Stream, diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLExressionsDeriver.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLExressionsDeriver.java index b4aaaca1..db209532 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLExressionsDeriver.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLExressionsDeriver.java @@ -13,6 +13,7 @@ import de.monticore.types.check.TypeCheckResult; import de.se_rwth.commons.logging.Log; +@Deprecated public class SysMLExressionsDeriver extends AbstractDeriveFromExpression implements SysMLExpressionsVisitor2, SysMLExpressionsHandler { diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLSynthesizer.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLSynthesizer.java index 67b34988..c49bc594 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLSynthesizer.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLSynthesizer.java @@ -8,6 +8,7 @@ import de.monticore.types.check.SynthesizeSymTypeFromMCCollectionTypes; import de.monticore.types.check.SynthesizeSymTypeFromMCSimpleGenericTypes; +@Deprecated public class SysMLSynthesizer extends AbstractSynthesize { public SysMLSynthesizer() { diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java index 3fb2d1a3..2cbd75bb 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java @@ -32,6 +32,7 @@ *

In SysMLv2, the expression in StateUsage is not type of Stream. * Rewrite method {@link #calculateFieldAccess(ASTFieldAccessExpression, boolean)} for this purpose.

*/ +@Deprecated public class SysMLv2DeriveSymTypeOfCommonExpressions extends DeriveSymTypeOfCommonExpressions { /** * @see SysMLDeriver#isStream diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java new file mode 100644 index 00000000..f7071ddf --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java @@ -0,0 +1,326 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.expressions.commonexpressions._ast.ASTArrayAccessExpression; +import de.monticore.expressions.commonexpressions._ast.ASTFieldAccessExpression; +import de.monticore.expressions.commonexpressions._ast.ASTFieldAccessExpressionBuilder; +import de.monticore.expressions.commonexpressions._ast.ASTLogicalNotExpression; +import de.monticore.expressions.commonexpressions._symboltable.ICommonExpressionsScope; +import de.monticore.expressions.commonexpressions._visitor.CommonExpressionsTraverser; +import de.monticore.expressions.commonexpressions.types3.CommonExpressionsTypeVisitor; +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.expressions.expressionsbasis._ast.ASTNameExpression; +import de.monticore.lang.componentconnector.StreamTimingUtil; +import de.monticore.lang.componentconnector._symboltable.IComponentConnectorScope; +import de.monticore.lang.sysmlactions._ast.ASTAssignmentActionUsage; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlexpressions._ast.ASTConditionalNotExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTInfinity; +import de.monticore.lang.sysmlexpressions._ast.ASTSubsetEquationExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTSubsetExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTSupersetEquationExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTSupersetExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTSysMLFieldAccessExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTSysMLInstantiation; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsHandler; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsTraverser; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; +import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; +import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; +import de.monticore.lang.sysmlparts._symboltable.PortDefSymbol; +import de.monticore.lang.sysmlstates._ast.ASTStateDef; +import de.monticore.lang.sysmlstates._ast.ASTStateUsage; +import de.monticore.lang.sysmlstates._symboltable.StateDefSymbol; +import de.monticore.lang.sysmlstates._symboltable.StateUsageSymbol; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2GlobalScope; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; +import de.monticore.ocl.setexpressions._ast.ASTSetNotInExpression; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.symbols.compsymbols._symboltable.PortSymbol; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types.check.SymTypeOfFunction; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.util.TypeContextCalculator; +import de.monticore.types3.util.TypeVisitorLifting; +import de.monticore.types3.util.TypeVisitorOperatorCalculator; +import de.monticore.types3.util.WithinScopeBasicSymbolsResolver; +import de.monticore.types3.util.WithinTypeBasicSymbolsResolver; +import de.se_rwth.commons.logging.Log; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +import static de.monticore.types.check.SymTypeExpressionFactory.createObscureType; + +/** + * Handles type checking the sysmlv2 standard and the particularities of the spes + * language profile regarding streams in expressions. + * 1. Ports in specifications have implicit stream types and are injected in the + * type check at field access derivation and at name expression derivation. + * Also implements the following design decisions using two modes: + * Mode 1: TypeCheck interprets an Expression for a port usage as an implicit + * field access if there is only one attribute inside. Explicit field accesses + * are still supported by ignoring the field access if its type correct. + * Mode 2: TypeCheck finds multiple attributes, and thus multiple channels and + * reverts to the standard (with streams) TypeCheck without implicit field accesses. + */ +public class SysMLCommonExpressionsTypeVisitor extends CommonExpressionsTypeVisitor implements + SysMLExpressionsVisitor2, SysMLExpressionsHandler { + + protected SysMLExpressionsTraverser traverser; + + @Override + public SysMLExpressionsTraverser getTraverser() { + return traverser; + } + + @Override + public void setTraverser(SysMLExpressionsTraverser traverser) { + this.traverser = traverser; + } + + @Override + public void endVisit(ASTConditionalNotExpression expr) { + SymTypeExpression inner = + getType4Ast().getPartialTypeOfExpr(expr.getExpression()); + SymTypeExpression result = getTypeForPrefixOrLogError( + "0xB0165", expr, "not", + SysMLTypeVisitorOperatorCalculator.conditionalNot(inner), inner + ); + getType4Ast().setTypeOfExpression(expr, result); + } + + @Override + public void endVisit(ASTInfinity node) { + // backwards compatibility + getType4Ast().setTypeOfExpression(node, SymTypeExpressionFactory.createPrimitive("int")); + } + + @Override + public void endVisit(ASTSysMLFieldAccessExpression node) { + // does not work with inheritance traverser because this is the handler and + endVisit((ASTFieldAccessExpression) node); + } + + @Override + public void traverse(ASTSysMLFieldAccessExpression node) { + traverse((ASTFieldAccessExpression) node); + } + + @Override + protected Optional calculateExprFieldAccess( + ASTFieldAccessExpression expr, + boolean resultsAreOptional) { + Optional type; + final String name = expr.getName(); + if (!getType4Ast().hasTypeOfExpression(expr.getExpression())) { + Log.error("0xFD231 internal error:" + + "unable to find type identifier for field access", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd() + ); + type = Optional.empty(); + } + else { + SymTypeExpression innerAsExprType = + getType4Ast().getPartialTypeOfExpr(expr.getExpression()); + + //++++++++++ modify start here ++++++++++ + + Optional optPort = Optional.empty(); + if (expr.getExpression() instanceof ASTArrayAccessExpression) { + optPort = ((IComponentConnectorScope) expr.getEnclosingScope()).resolvePort(SysMLv2Mill.prettyPrint( + new ASTFieldAccessExpressionBuilder() + .setExpression(((ASTArrayAccessExpression)expr.getExpression()).getExpression()) + .setName(name) + .build(), + false)); + } else if (expr.getExpression() instanceof ASTNameExpression) { + optPort = ((IComponentConnectorScope) expr.getEnclosingScope()).resolvePort(SysMLv2Mill.prettyPrint(expr, false)); + } + + var innerTypeIsPortDef = innerAsExprType.hasTypeInfo() && + innerAsExprType + .getTypeInfo() + .getSpannedScope() + .getSpanningSymbol() instanceof PortDefSymbol + || innerAsExprType.isArrayType() && + innerAsExprType + .asArrayType() + .getArgument() + .getTypeInfo() + .getSpannedScope() + .getSpanningSymbol() instanceof PortDefSymbol; + + // If no C&C port was found OR the inner expression refers to a port definition + if (optPort.isEmpty() || innerTypeIsPortDef) { + + // Case 1: This is not an implicit field access, we still have to compute it. + // Fall back to the default field access computation + if (WithinTypeBasicSymbolsResolver.canResolveIn(innerAsExprType)) { + AccessModifier modifier = innerAsExprType.hasTypeInfo() ? + TypeContextCalculator.getAccessModifier( + innerAsExprType.getTypeInfo(), expr.getEnclosingScope() + ) : + AccessModifier.ALL_INCLUSION; + + type = resolveVariablesAndFunctionsWithinType( + innerAsExprType, + name, + modifier, + v -> true, + f -> true + ); + + // We can only check if we are not in an automata as state machines always define a scope + if (type.isPresent() && + !type.get().isFunctionType() && + !SysMLWithinScopeBasicSymbolResolver.isDefinedInStateMachine( + getAsBasicSymbolsScope(expr.getEnclosingScope())) && + optPort.isPresent()) { + // found a C&C port -> Adjust type to Stream + var streamType = WithinScopeBasicSymbolsResolver.resolveType( + getAsBasicSymbolsScope(expr.getEnclosingScope()), + StreamTimingUtil.mapTimingToStreamType( + optPort.get().getTiming())); + + if (streamType.isEmpty()) { + Log.error("tried to resolve \"" + name + "\"" + + " given expression of type " + + innerAsExprType.printFullName() + + " but no stream symbol could be resolved.", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd() + ); + } + else { + streamType.get().asGenericType().setArgument(0, type.get()); + } + + type = streamType; + } + + //++++++++++ modify end here ++++++++++ + + // Log remark about access modifier, + // if access modifier is the reason it has not been resolved + if (type.isEmpty() && !resultsAreOptional) { + Optional potentialResult = + resolveVariablesAndFunctionsWithinType( + innerAsExprType, + name, + AccessModifier.ALL_INCLUSION, + v -> true, + f -> true + ); + if (potentialResult.isPresent()) { + Log.warn("tried to resolve \"" + name + "\"" + + " given expression of type " + + innerAsExprType.printFullName() + + " and symbols have been found" + + ", but due to the access modifiers (e.g., public)" + + ", nothing could be resolved", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd() + ); + } + } + } + // extension point + else { + Log.error("0xFDB3A unexpected field access \"" + + expr.getName() + + "\" for type " + + innerAsExprType.printFullName(), + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd() + ); + type = Optional.empty(); + } + } + else { + // Case 2: this is an explicit FA and the type of the inner expression is forwarded + // to the outer expression as it was already computed in a previous step + type = Optional.of(innerAsExprType); + } + } + return type; + } + + @Override + public void endVisit(ASTSubsetExpression expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateSubsetExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + @Override + public void endVisit(ASTSubsetEquationExpression expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateSubsetExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + @Override + public void endVisit(ASTSupersetExpression expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateSubsetExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + @Override + public void endVisit(ASTSupersetEquationExpression expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateSubsetExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + protected SymTypeExpression calculateSubsetExpression( + SymTypeExpression left, SymTypeExpression right) { + + if (SymTypeRelations.isCompatible(left, right) && MCCollectionSymTypeRelations.isSet(left)) { + return SymTypeExpressionFactory.createPrimitive(BasicSymbolsMill.BOOLEAN); + } + return SymTypeExpressionFactory.createObscureType(); + } + + @Override + public void endVisit(ASTSysMLInstantiation expr) { + getType4Ast().setTypeOfExpression(expr, getType4Ast().getPartialTypeOfTypeId( + expr.getMCType())); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLMCBasicTypesTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLMCBasicTypesTypeVisitor.java new file mode 100644 index 00000000..c46ce9e8 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLMCBasicTypesTypeVisitor.java @@ -0,0 +1,15 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.lang.sysmlexpressions._ast.ASTMCPrimitiveTypeWithNat; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; +import de.monticore.types.mcbasictypes._ast.ASTMCPrimitiveType; +import de.monticore.types.mcbasictypes.types3.MCBasicTypesTypeVisitor; + +public class SysMLMCBasicTypesTypeVisitor extends MCBasicTypesTypeVisitor implements + SysMLExpressionsVisitor2 { + + @Override + public void endVisit(ASTMCPrimitiveTypeWithNat node) { + endVisit((ASTMCPrimitiveType) node); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java new file mode 100644 index 00000000..00571202 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java @@ -0,0 +1,13 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.lang.sysmlexpressions._ast.ASTExistsExpression; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; +import de.monticore.ocl.oclexpressions.types3.OCLExpressionsTypeVisitor; + +public class SysMLOCLExpressionsTypeVisitor extends OCLExpressionsTypeVisitor implements + SysMLExpressionsVisitor2 { + @Override + public void endVisit(ASTExistsExpression node) { + endVisit((de.monticore.ocl.oclexpressions._ast.ASTExistsExpression) node); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSetExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSetExpressionsTypeVisitor.java new file mode 100644 index 00000000..cc366e3c --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSetExpressionsTypeVisitor.java @@ -0,0 +1,23 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.lang.sysmlexpressions._ast.ASTElementOfExpression; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; +import de.monticore.ocl.setexpressions._ast.ASTSetInExpressionBuilder; +import de.monticore.ocl.setexpressions.types3.SetExpressionsTypeVisitor; + +public class SysMLSetExpressionsTypeVisitor extends SetExpressionsTypeVisitor implements + SysMLExpressionsVisitor2 { + @Override + public void endVisit(ASTElementOfExpression node) { + var setInExpr = new ASTSetInExpressionBuilder() + .setElem(node.getLeft()) + .setSet(node.getRight()) + .set_SourcePositionStart(node.get_SourcePositionStart()) + .set_SourcePositionEnd(node.get_SourcePositionEnd()) + .build(); + + endVisit(setInExpr); + + getType4Ast().setTypeOfExpression(node, getType4Ast().getTypeOfExpression(setInExpr)); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSymTypeRelations.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSymTypeRelations.java new file mode 100644 index 00000000..97c88757 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSymTypeRelations.java @@ -0,0 +1,28 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.ocl.types3.OCLSymTypeRelations; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types3.util.BuiltInTypeRelations; +import de.monticore.types3.util.SymTypeRelationsDefaultDelegatee; + +public abstract class SysMLSymTypeRelations extends OCLSymTypeRelations { + + public static void init() { + setDelegate(new SysMLSymTypeRelationsDelegatee()); + } + + // selecting the concrete implementations + protected static class SysMLSymTypeRelationsDelegatee extends + SymTypeRelationsDefaultDelegatee { + public SysMLSymTypeRelationsDelegatee() { + builtInRelationsDelegate = new BuiltInTypeRelations() { + @Override + public boolean isIntegralType(SymTypeExpression type) { + return super.isIntegralType(type) || + type.isPrimitive() && + type.asPrimitive().getPrimitiveName().equals("nat"); + } + }; + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java new file mode 100644 index 00000000..06827a24 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java @@ -0,0 +1,101 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.ocl.types3.OCLSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.monticore.visitor.ITraverser; +import de.se_rwth.commons.logging.Log; + +/** + * TypeCheck3 implementation for the SysMLv2 language. After calling {@link #init()}, this + * implementation will be available through the TypeCheck3 interface. + */ +public class SysMLTypeCheck3 extends MapBasedTypeCheck3 { + + public static void init() { + initTC3Delegate(); + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + } + + public static void reset() { + TypeCheck3.resetDelegate(); + StreamSymTypeRelations.reset(); + SysMLWithinScopeBasicSymbolResolver.reset(); + SysMLTypeVisitorOperatorCalculator.reset(); + CommonExpressionsLValueRelations.reset(); + MCCollectionSymTypeRelations.reset(); + OCLSymTypeRelations.reset(); + } + + protected static void initTC3Delegate() { + Log.trace("init SysMLTypeCheck3", "TypeCheck setup"); + + SysMLv2Traverser typeTraverser = SysMLv2Mill.inheritanceTraverser(); + Type4Ast type4Ast = new Type4Ast(); + + // Expressions + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + typeTraverser.add4SysMLExpressions(forSets); + + // MCTypes + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + // TODO are MCSimpleGenerics required? + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + // create delegate + SysMLTypeCheck3 sysmlTC3 = new SysMLTypeCheck3(typeTraverser, type4Ast); + sysmlTC3.setThisAsDelegate(); + } + + public SysMLTypeCheck3( + ITraverser typeTraverser, Type4Ast type4Ast) { + super(typeTraverser, type4Ast); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeVisitorOperatorCalculator.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeVisitorOperatorCalculator.java new file mode 100644 index 00000000..654c98d6 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeVisitorOperatorCalculator.java @@ -0,0 +1,51 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.util.TypeVisitorLifting; +import de.monticore.types3.util.TypeVisitorOperatorCalculator; +import de.monticore.types3.util.WithinScopeBasicSymbolsResolver; +import de.se_rwth.commons.logging.Log; + +import java.util.Optional; + +public class SysMLTypeVisitorOperatorCalculator extends + TypeVisitorOperatorCalculator { + + public static void init() { + Log.trace("init SysMLTypeVisitorOperatorCalculator", "TypeCheck setup"); + setDelegate(new SysMLTypeVisitorOperatorCalculator()); + } + + @Override + protected SymTypeExpression calculateLogicalNot(SymTypeExpression inner) { + var result = super.calculateLogicalNot(inner); + if (SymTypeRelations.isBoolean(result)) { + return result; + } + // TODO resolve for Stream and deepEquals + else if (inner.hasTypeInfo() && inner.getTypeInfo().isPresentSuperClass() && + inner.getTypeInfo().getSuperClass().print().equals("Stream")) { + return inner; + } + + return SymTypeExpressionFactory.createObscureType(); + } + + public static Optional conditionalNot(SymTypeExpression inner) { + return ((SysMLTypeVisitorOperatorCalculator)getDelegate())._conditionalNot(inner); + } + + protected Optional _conditionalNot(SymTypeExpression inner) { + SymTypeExpression result = + TypeVisitorLifting.liftDefault(this::calculateConditionalNot) + .apply(inner); + return obscure2Empty(result); + } + + protected SymTypeExpression calculateConditionalNot(SymTypeExpression inner) { + return super.calculateLogicalNot(inner); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLWithinScopeBasicSymbolResolver.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLWithinScopeBasicSymbolResolver.java new file mode 100644 index 00000000..d072808b --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLWithinScopeBasicSymbolResolver.java @@ -0,0 +1,213 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.expressions.commonexpressions._symboltable.ICommonExpressionsScope; +import de.monticore.lang.componentconnector.StreamTimingUtil; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlparts._symboltable.PortDefSymbol; +import de.monticore.lang.sysmlstates._ast.ASTStateDef; +import de.monticore.lang.sysmlstates._ast.ASTStateUsage; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2GlobalScope; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; +import de.monticore.symboltable.ISymbol; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types.check.SymTypeOfFunction; +import de.monticore.types.check.SymTypeSourceInfo; +import de.monticore.types3.util.TypeContextCalculator; +import de.monticore.types3.util.WithinScopeBasicSymbolsResolver; +import de.monticore.types3.util.WithinTypeBasicSymbolsResolver; +import de.se_rwth.commons.logging.Log; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Implements the normal and implicit field access modes for the TypeCheck. + * We determine the type of the NameExpression according to if it is a port usage, + * how many attributes it has and if it is a stream type or not. + */ +public class SysMLWithinScopeBasicSymbolResolver extends + WithinScopeBasicSymbolsResolver { + + public static void init() { + WithinScopeBasicSymbolsResolver.setDelegate(new SysMLWithinScopeBasicSymbolResolver()); + } + + @Override + protected Optional _resolveNameAsExpr( + IBasicSymbolsScope enclosingScope, String name) { + Log.errorIfNull(enclosingScope); + Log.errorIfNull(name); + // collect all (potential) types + Set types = new HashSet<>(); + + // to circumvent current shortcomings in our resolver, + // we resolve with the resolver AND resolve with the within type resolver + // afterwards we evaluate which result to use + + // not necessarily in an enclosing type + Optional optVar = + resolveVariableWithoutSuperTypes(enclosingScope, name); + + //++++++++++ modify start here ++++++++++ + + if (optVar.isPresent() && enclosingScope instanceof ISysMLv2Scope && + (optVar.get().hasTypeInfo() || + optVar.get().isArrayType() && optVar.get().asArrayType().getArgument().hasTypeInfo()) + ) { + // found var. + IBasicSymbolsScope scope; + var typeToLookIn = optVar.get(); + if (optVar.get().isArrayType()) { + scope = typeToLookIn.asArrayType().getArgument().getTypeInfo().getSpannedScope(); + typeToLookIn = typeToLookIn.asArrayType().getArgument(); + } + else { + scope = optVar.get().getTypeInfo().getSpannedScope(); + } + + var attr = ((ISysMLv2Scope) scope).getLocalAttributeUsageSymbols(); + if (attr.size() == 1 && scope.getSpanningSymbol() instanceof PortDefSymbol) { + // its an implicit field access representing a port + var actualType = WithinTypeBasicSymbolsResolver.resolveVariable( + typeToLookIn, attr.get(0).getName(), AccessModifier.ALL_INCLUSION, + v -> true); + + if (!isDefinedInStateMachine(enclosingScope)) { + // We are in stream mode + + // We have to resolve for port to determine its timing + var optPort = ((ISysMLv2Scope) enclosingScope).resolvePort(name + "." + attr.get(0).getName()); + + var streamType = WithinScopeBasicSymbolsResolver.resolveType( + enclosingScope, + StreamTimingUtil.mapTimingToStreamType( + optPort.get().getTiming())); + + if (streamType.isEmpty()) { + Log.error("0xFDA26 internal error: " + + "cannot resolve stream symbol for " + name + ". Were stream symbols loaded? " + ); + } else { + if (actualType.get().isArrayType()) { + streamType.get().asGenericType().setArgument(0, + actualType.get().asArrayType().getArgument()); + actualType.get().asArrayType().setArgument(streamType.get()); + } else { + streamType.get().asGenericType().setArgument(0, + actualType.get()); + + actualType = streamType; + } + } + } + // if present + if (optVar.get().isArrayType()) { + optVar.get().asArrayType().setArgument(actualType.get()); + } + else { + optVar = actualType; + } + } + } + + //++++++++++ modify end here ++++++++++ + + List funcs = + resolveFunctionsWithoutSuperTypes(enclosingScope, name); + // within type + Optional enclosingType = + TypeContextCalculator.getEnclosingType(enclosingScope); + Optional varInType = Optional.empty(); + List funcsInType = Collections.emptyList(); + if (enclosingType.isPresent()) { + SymTypeExpression enclosingTypeExpr = + SymTypeExpressionFactory.createFromSymbol(enclosingType.get()); + AccessModifier modifier = TypeContextCalculator + .getAccessModifier(enclosingType.get(), enclosingScope); + varInType = WithinTypeBasicSymbolsResolver.resolveVariable( + enclosingTypeExpr, name, modifier, getVariablePredicate()); + funcsInType = WithinTypeBasicSymbolsResolver.resolveFunctions( + enclosingTypeExpr, name, modifier, getFunctionPredicate()); + } + // get the correct variable + if (varInType.isPresent() && optVar.isPresent()) { + SymTypeSourceInfo varInTypeInfo = varInType.get().getSourceInfo(); + SymTypeSourceInfo optVarInfo = optVar.get().getSourceInfo(); + if (varInTypeInfo.getSourceSymbol().isPresent() && + optVarInfo.getSourceSymbol().isPresent() + ) { + ISymbol varInTypeVarSymbol = varInTypeInfo.getSourceSymbol().get(); + ISymbol optVarVarSymbol = optVarInfo.getSourceSymbol().get(); + if (optVarVarSymbol.getEnclosingScope() + .isProperSubScopeOf(varInTypeVarSymbol.getEnclosingScope()) + ) { + types.add(optVar.get()); + } + else { + types.add(varInType.get()); + } + } + else { + Log.error("0xFDA25 internal error: " + + "expected variable symbol for resolved variable " + name + ); + } + } + else if (varInType.isPresent()) { + types.add(varInType.get()); + } + else if (optVar.isPresent()) { + types.add(optVar.get()); + } + // get the correct functions + // heuristic, as we assume the resolver to be extended in the near future, + // and the correct solution would take longer to implement, + // in Javalight, these cases may never happen anyways + types.addAll(funcsInType); + for (SymTypeOfFunction func : funcs) { + if (funcsInType.stream().noneMatch(f -> f.getSymbol() == func.getSymbol())) { + types.add(func); + } + } + + if (types.size() <= 1) { + return types.stream().findAny(); + } + else { + // this can be extended to mark the intersection as + // an intersection that one has to select a type of. + // The current interpretation is, that the result is all the possible types, + // e.g. "a.b" could have the types of (int, int->int, boolean->int). + // in Java, this would be filtered out earlier, + // however, we support more (e.g. SymTypeOfFunction). + return Optional.of(SymTypeExpressionFactory.createIntersection(types)); + } + } + + protected static boolean isDefinedInStateMachine(IBasicSymbolsScope scope) { + var enclosingScope = (ISysMLv2Scope) scope; + if (enclosingScope.getAstNode() instanceof ASTStateDef || + enclosingScope.getAstNode() instanceof ASTStateUsage + ) { + return true; + } + else if (enclosingScope.getAstNode() instanceof ASTPartDef || + enclosingScope.getAstNode() instanceof ASTPartUsage || + enclosingScope instanceof ISysMLv2ArtifactScope || + enclosingScope instanceof ISysMLv2GlobalScope + ) { + return false; + } + else + return isDefinedInStateMachine(scope.getEnclosingScope()); + } +} diff --git a/language/src/test/java/cocos/ConstraintCoCoTest.java b/language/src/test/java/cocos/ConstraintCoCoTest.java index 6cd634b2..09ed9b5a 100644 --- a/language/src/test/java/cocos/ConstraintCoCoTest.java +++ b/language/src/test/java/cocos/ConstraintCoCoTest.java @@ -31,7 +31,6 @@ public class ConstraintCoCoTest { @BeforeAll public static void init() { LogStub.init(); - OCLSymTypeRelations.init(); SysMLv2Mill.init(); } @@ -49,7 +48,7 @@ public class ConstraintCoCoTest { "4_valid.sysml", // stream snth "5_valid.sysml", // port::channel-syntax with comparison //"6_valid.sysml", // port::channel-syntax with literal - //"7_valid.sysml", // INF literal + "7_valid.sysml", // INF literal "8_valid.sysml", // forall construct "9_valid.sysml", // constraint with literal //"10_valid.sysml", // attribute definition without port @@ -58,7 +57,7 @@ public class ConstraintCoCoTest { "13_valid.sysml", // OCL exists expression "14_valid.sysml", // StreamConstructor Expression "15_valid.sysml", //Times function for StreamConstructor Expression - "16_valid.sysml", //Inftimes and takes function + "16_valid.sysml", //Inftimes and takes function }) public void testValid(String modelName) throws IOException { var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); @@ -94,7 +93,7 @@ public void testValid(String modelName) throws IOException { "13_invalid.sysml", // OCL exists expression "14_invalid.sysml", // StreamConstructor Expression "15_invalid.sysml", //Times function for StreamConstructor Expression - "16_invalid.sysml", //Inftimes and takes function + "16_invalid.sysml", //Inftimes and takes function }) public void testInvalid(String modelName) throws IOException { var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); diff --git a/language/src/test/java/types3/ConstraintCoCoTest.java b/language/src/test/java/types3/ConstraintCoCoTest.java new file mode 100644 index 00000000..b033bf3e --- /dev/null +++ b/language/src/test/java/types3/ConstraintCoCoTest.java @@ -0,0 +1,202 @@ +/* (c) https://github.com/MontiCore/monticore */ +package types3; + +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.ocl.types3.OCLSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.monticore.types3.util.WithinScopeBasicSymbolsResolver; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ConstraintCoCoTest { + + private static final String MODEL_PATH = "src/test/resources/cocos/constraints"; + + private SysMLv2Tool tool; + + @BeforeAll public static void init() { + LogStub.init(); + } + + @BeforeEach public void reset() { + Log.getFindings().clear(); + tool = new SysMLv2Tool(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + + @ParameterizedTest(name = "{index} - {0} does pass all checks w/o errors") + @ValueSource(strings = { "1_valid.sysml", + // boolean operator with literals + "2_valid.sysml", // resolve & compare ports + "3_valid.sysml", // resolve & compare channels + "4_valid.sysml", // stream snth + "5_valid.sysml", // port::channel-syntax with comparison + //"6_valid.sysml", // port::channel-syntax with literal + "7_valid.sysml", // INF literal + "8_valid.sysml", // forall construct + "9_valid.sysml", // constraint with literal + //"10_valid.sysml", // attribute definition without port + "11_valid.sysml", // stream length + "12_valid.sysml", // constraint with parameter + "13_valid.sysml", // OCL exists expression + "14_valid.sysml", // StreamConstructor Expression + "15_valid.sysml", //Times function for StreamConstructor Expression + "16_valid.sysml", //Inftimes and takes function + "17_valid.sysml", // user defined type + "18_valid.sysml", // user defined type channels + + "implicitFieldAccess/2_valid.sysml", // resolve & compare ports + "implicitFieldAccess/4_valid.sysml", // stream snth + "implicitFieldAccess/11_valid.sysml", // stream length + "implicitFieldAccess/14_valid.sysml", // StreamConstructor Expression + "implicitFieldAccess/15_valid.sysml", //Times function for StreamConstructor Expression + "implicitFieldAccess/17_valid.sysml", // user defined type + "implicitFieldAccess/18_valid.sysml", // user defined type channels + "implicitFieldAccess/19_valid.sysml", // interoperability between implicit and explicit + + }) + public void testValid(String modelName) throws IOException { + var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); + assertThat(optAst).isPresent(); + + ASTSysMLModel ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.checkAll(ast); + + assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); + } + + @ParameterizedTest(name = "{index} - {0} does pass all checks w/o errors") + @ValueSource(strings = { "1_invalid.sysml", + // boolean operator with literals + "2_invalid.sysml", // resolve & compare ports + "3_invalid.sysml", // resolve & compare channels + "4_invalid.sysml", // stream snth + "5_invalid.sysml", // port::channel-syntax with comparison + "6_invalid.sysml", // port::channel-syntax with literal + "7_invalid.sysml", // INF literal + "8_invalid.sysml", // forall construct + "9_invalid.sysml", // constraint with literal + //"10_invalid.sysml", // attribute definition without port + "11_invalid.sysml", // stream length + //"12_invalid.sysml", // constraint with parameter + "13_invalid.sysml", // OCL exists expression + "14_invalid.sysml", // StreamConstructor Expression + "15_invalid.sysml", //Times function for StreamConstructor Expression + "16_invalid.sysml", //Inftimes and takes function + "17_invalid.sysml", // user defined type + "18_invalid.sysml", // user defined type channels + + "implicitFieldAccess/2_invalid.sysml", // resolve & compare ports + "implicitFieldAccess/4_invalid.sysml", // stream snth + "implicitFieldAccess/11_invalid.sysml", // stream length + "implicitFieldAccess/14_invalid.sysml", // StreamConstructor Expression + "implicitFieldAccess/15_invalid.sysml", //Times function for StreamConstructor Expression + "implicitFieldAccess/17_invalid.sysml", // user defined type + "implicitFieldAccess/18_invalid.sysml", // user defined type channels + "implicitFieldAccess/19_invalid.sysml", // interoperability between implicit and explicit + }) + public void testInvalid(String modelName) throws IOException { + var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); + assertThat(optAst).isPresent(); + + ASTSysMLModel ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + Log.enableFailQuick(false); + checker.checkAll(ast); + assertFalse(Log.getFindings().isEmpty()); + Log.clearFindings(); + Log.enableFailQuick(true); + } +} diff --git a/language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java b/language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java new file mode 100644 index 00000000..fa96a73b --- /dev/null +++ b/language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java @@ -0,0 +1,157 @@ +package types3; + +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2.types.SysMLDeriver; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class FieldAccessExpressionInConstraintUsageTest { + + private final SysMLv2Parser parser = new SysMLv2Parser(); + private final SysMLv2Tool tool = new SysMLv2Tool(); + + @BeforeAll + public static void init() { + LogStub.init(); + } + + @BeforeEach + public void reset() { + Log.getFindings().clear(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { attribute a: boolean[2]; } part s { port f: F; constraint e { f.a[1] } }", + "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1].a } }", + + "port def F { attribute a: boolean[2]; } part s { port f: F; constraint e { f[1] } }", + "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1] } }" + }) public void test4ValidExpr1(String model) throws IOException { + var ast = parser.parse_String(model); + assertThat(ast).isPresent(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); + var type = TypeCheck3.typeOf(expr); + assertFalse(type.isObscureType()); + assertThat(type.printFullName()).isEqualTo("EventStream.EventStream"); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { attribute a: boolean; } part s { port f: F[2]; constraint e { f.a } }", + "port def F { attribute a: boolean; } part s { port f: F[2]; constraint e { f } }" + }) + public void test4InvalidExpr(String model) throws IOException { + var ast = parser.parse_String(model);; + assertThat(ast).isPresent(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); + var type = TypeCheck3.typeOf(expr); + assertTrue(type.isObscureType() || + !Log.getFindings().isEmpty() || + !type.printFullName().equals("EventStream.EventStream")); + } +} + + diff --git a/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java b/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java new file mode 100644 index 00000000..28f5b240 --- /dev/null +++ b/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java @@ -0,0 +1,251 @@ +package types3; + +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +import de.monticore.lang.sysmlparts._ast.ASTPortDef; +import de.monticore.lang.sysmlstates._ast.ASTStateUsage; +import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2.types.SysMLDeriver; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.util.stream.Stream; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + *

This test is about TypeCheck3 deriving the types of FieldAccessExpressions in StateUsages.

+ * + *

When ASTFieldAccessExpression and ASTOCLArrayQualification are in StateUsage + * we test whether they are not calculated as Stream such as in constraints.

+ */ +public class FieldAccessExpressionInStateUsageTest { + + private final SysMLv2Parser parser = new SysMLv2Parser(); + private final SysMLv2Tool tool = new SysMLv2Tool(); + + @BeforeAll + public static void init() { + LogStub.init(); + } + + @BeforeEach + public void reset() { + Log.getFindings().clear(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + + static Stream createInputs() { + return Stream.of( + Arguments.of( + "port def F { attribute a: boolean; }" + + "part def X { port f: F; state s { transition first S if f then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; }" + + "part def X { port f: F; state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1][1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f } }") + + + ,Arguments.of( + "port def F { attribute a: boolean; }" + + "part def X { port f: F; state s { transition first S if f.a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; }" + + "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f.a } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F[3]; constraint e { f[1].a } }") + + + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; }" + + "part def X { port f: F; state s { transition first S if f.a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + + "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F; constraint e { f.a } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F[3]; constraint e { f[1].a } }") + ); + } + + static Stream createInvalidInputs() { + return Stream.of( + Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; }" + + "part def X { port f: F; state s { transition first S if f then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + + "part def X { port f: F; state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1][1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F; constraint e { f } }") + // TODO one field access with a stream method + ); + } + + @ParameterizedTest + @MethodSource({ "createInputs" }) + public void test(String model) throws IOException { + var ast = parser.parse_String(model); + assertThat(ast).isPresent(); + var astSysmlmodel = ast.get(); + SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); + tool.completeSymbolTable(astSysmlmodel); + var astPartdef = astSysmlmodel.getSysMLElementList().get(1); + var astSysmlelement = ((ASTPartDef) astPartdef).getSysMLElement(1); + if (astSysmlelement instanceof ASTStateUsage) { + var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); + var expr = ((ASTSysMLTransition) astTransition).getGuard(); + var type = TypeCheck3.typeOf(expr); + assertThat(type.printFullName()).isEqualTo("boolean"); + } else if (astSysmlelement instanceof ASTConstraintUsage) { + var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); + var type = TypeCheck3.typeOf(expr); + assertThat(type.printFullName()).isEqualTo( + "EventStream.EventStream"); + } + else { + Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); + } + } + + @ParameterizedTest + @MethodSource({ "createInvalidInputs" }) + public void testInvalid(String model) throws IOException { + var ast = parser.parse_String(model); + assertThat(ast).isPresent(); + var astSysmlmodel = ast.get(); + SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); + tool.completeSymbolTable(astSysmlmodel); + var astPartdef = astSysmlmodel.getSysMLElementList().get(1); + var astSysmlelement = ((ASTPartDef) astPartdef).getSysMLElement(1); + SymTypeExpression type = SymTypeExpressionFactory.createObscureType(); + + Log.enableFailQuick(false); + + if (astSysmlelement instanceof ASTStateUsage) { + var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); + var expr = ((ASTSysMLTransition) astTransition).getGuard(); + type = TypeCheck3.typeOf(expr); + } else if (astSysmlelement instanceof ASTConstraintUsage) { + var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); + type = TypeCheck3.typeOf(expr); + } + else { + Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); + } + + assertTrue(!type.isPrimitive() || !type.asPrimitive().getPrimitiveName().equals("boolean")); + Log.enableFailQuick(true); + } +} diff --git a/language/src/test/java/types3/NegationTest.java b/language/src/test/java/types3/NegationTest.java new file mode 100644 index 00000000..0e90be87 --- /dev/null +++ b/language/src/test/java/types3/NegationTest.java @@ -0,0 +1,156 @@ +package types3; + +import de.monticore.expressions.commonexpressions._ast.ASTEqualsExpression; +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.ocl.oclexpressions._ast.ASTForallExpression; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class NegationTest { + + private final SysMLv2Parser parser = new SysMLv2Parser(); + private final SysMLv2Tool tool = new SysMLv2Tool(); + + @BeforeAll + public static void init() { + LogStub.init(); + } + + @BeforeEach + public void reset() { + Log.getFindings().clear(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { in attribute val: boolean; } part s { port f: F; constraint e { forall long t: f.val.nth(t) == !f.val.nth(t) } }" + }) + public void testNotBooleanStream(String model) throws IOException { + var ast = parser.parse_String(model); + assertThat(ast).isPresent(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); + var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); + var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); + var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); + assertFalse(rightType.isObscureType()); + assertThat(rightType.printFullName()).isEqualTo("UntimedStream.UntimedStream"); + assertTrue(rightType.deepEquals(leftType)); + } + + @ParameterizedTest + @ValueSource(strings = { + "part s { constraint e { forall nat t: true == !false } }" + }) + public void testNotBoolean(String model) throws IOException { + var ast = parser.parse_String(model); + assertThat(ast).isPresent(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(0); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(0); + var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); + var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); + var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); + var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); + assertFalse(rightType.isObscureType()); + assertThat(rightType.printFullName()).isEqualTo("boolean"); + assertTrue(rightType.deepEquals(leftType)); + } +} diff --git a/language/src/test/java/types3/SpecializationExistsTest.java b/language/src/test/java/types3/SpecializationExistsTest.java new file mode 100644 index 00000000..ed1ee86f --- /dev/null +++ b/language/src/test/java/types3/SpecializationExistsTest.java @@ -0,0 +1,111 @@ +/* (c) https://github.com/MontiCore/monticore */ +package types3; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2.cocos.SpecializationExists; +import de.monticore.lang.sysmlv2.cocos.SpecializationExistsTC3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.types3.TypeCheck3; +import de.se_rwth.commons.logging.Finding; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Prüft das Finden von Types der Specializations + */ +public class SpecializationExistsTest { + + @BeforeAll + static void setup() { + SysMLv2Mill.init(); + } + + @BeforeEach + void clear() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + SysMLTypeCheck3.reset(); + SysMLTypeCheck3.init(); + Log.clearFindings(); + } + + @Test + public void testMissingDefinition() throws IOException { + var model = "requirement Invalid { subject s: NonExistent; }"; + var ast = parse(model); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0xA0324 Cannot find symbol NonExistent"); + } + + @Test + public void testExistingDefinition() throws IOException { + var model = "part def Existent; requirement Valid { subject s: Existent; }"; + var ast = parse(model); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + // Should also work with state defs + @Test + public void testExistingStateDefinition() throws IOException { + var model = "state def Existent; requirement Valid { subject s: Existent; }"; + var ast = parse(model); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testExistingCollectionType() throws IOException { + var model = "attribute def Existent; part def Valid { attribute e: List; }"; + var ast = parse(model); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + private ASTSysMLModel parse(String model) throws IOException { + var optAst = SysMLv2Mill.parser().parse_String(model); + assertThat(optAst).isPresent(); + return optAst.get(); + } + + private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { + var tool = new SysMLv2Tool(); + var scope = tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + return scope; + } + + private List check(ASTSysMLModel ast) { + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new SpecializationExistsTC3()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(f -> f.isError()).collect(Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + +} diff --git a/language/src/test/java/types3/StreamConstructorExpressionsTest.java b/language/src/test/java/types3/StreamConstructorExpressionsTest.java new file mode 100644 index 00000000..276c7697 --- /dev/null +++ b/language/src/test/java/types3/StreamConstructorExpressionsTest.java @@ -0,0 +1,186 @@ +package types3; + +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2.types.SysMLDeriver; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class StreamConstructorExpressionsTest { + + private final SysMLv2Parser parser = new SysMLv2Parser(); + private final SysMLv2Tool tool = new SysMLv2Tool(); + + @BeforeAll + public static void setup() { + LogStub.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void clear() { + Log.clearFindings(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }", + "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }" + }) + public void test4validStream(String model) throws IOException { + var ast = parser.parse_String(model); + + assertThat(ast).isPresent(); + assertThat(Log.getFindings()).isEmpty(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); + var type = SymTypeRelations.normalize(TypeCheck3.typeOf(expr)); + assertThat(type.printFullName()).isEqualTo("EventStream.EventStream"); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }", + "port def F { attribute a: boolean; } part s { port f: F; constraint e { >} }" + }) + public void test4ValidMixedStream(String model) throws IOException { + var ast = parser.parse_String(model); + + assertThat(ast).isPresent(); + assertThat(Log.getFindings()).isEmpty(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); + var type = TypeCheck3.typeOf(expr); + + // Streams are based on union types. So the following expressions are correct, albeit innerly incompatible + assertTrue(type.isGenericType() && type.asGenericType().getArgument(0).isUnionType()); + var args = type.asGenericType().getArgument(0).asUnionType().getUnionizedTypeSet().toArray(); + assertFalse(SymTypeRelations.isCompatible((SymTypeExpression) args[0], (SymTypeExpression) args[1])); + assertTrue(Log.getFindings().isEmpty()); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { attribute a: boolean; } part s { port f: F; constraint e { == } }", + "port def F { attribute a: boolean; } part s { port f: F; constraint e { > == < >} }" + }) + public void test4InvalidStream(String model) throws IOException { + var ast = parser.parse_String(model); + + assertThat(ast).isPresent(); + assertThat(Log.getFindings()).isEmpty(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); + var type = TypeCheck3.typeOf(expr); + + assertTrue(type.isObscureType()); + assertFalse(Log.getFindings().isEmpty()); + } +} diff --git a/language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java b/language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java new file mode 100644 index 00000000..bf4b6185 --- /dev/null +++ b/language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java @@ -0,0 +1,200 @@ +package types3; + +import de.monticore.expressions.commonexpressions._ast.ASTEqualsExpression; +import de.monticore.expressions.commonexpressions._ast.ASTFieldAccessExpression; +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis._ast.ASTNameExpression; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +public class TC3FieldAccessInteroperabilityTest { + private SysMLv2Tool tool; + @BeforeAll + public static void init() { + LogStub.init(); + } + + @BeforeEach + public void reset() { + Log.getFindings().clear(); + tool = new SysMLv2Tool(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + @Test + public void testInteroperabilityWithoutTCReset() throws IOException { + var optAst = SysMLv2Mill.parser().parse_String( "" + + "port def Naturals {\n" + + " out attribute channel: nat;\n" + + "}\n" + + "\n" + + "part def LogicBasedConstraints {\n" + + " port input: ~Naturals;\n" + + " port output: Naturals;\n" + + "\n" + + " constraint streams {\n" + + " input == input.channel\n" + + " }\n" + + "}\n"); + assertThat(optAst).isPresent(); + + ASTSysMLModel ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var expression = (ASTEqualsExpression)((ASTPartDef)ast.getSysMLElement(1)) + .getSysMLElements(ASTConstraintUsage.class) + .get(0) + .getExpression(); + + var typeEq = TypeCheck3.typeOf(expression); + assertTrue(typeEq.isPrimitive() && typeEq.asPrimitive().getPrimitiveName().equals("boolean")); + + var leftNameExpr = (ASTNameExpression)expression.getLeft(); + var typeLeftNameExpr = TypeCheck3.typeOf(leftNameExpr); + assertEquals("EventStream", typeLeftNameExpr.print()); + + var rightFieldAccess = (ASTFieldAccessExpression)expression.getRight(); + var typeRightFieldAccess = TypeCheck3.typeOf(rightFieldAccess); + assertEquals("EventStream", typeRightFieldAccess.print()); + + var rightNameExpr = (ASTNameExpression)((ASTFieldAccessExpression)expression.getRight()).getExpression(); + var typeRightNameExpr = TypeCheck3.typeOf(rightNameExpr); + // this is the side effect of the 2-modes typecheck implementation. + // Deriving the type of a port usage cannot not reliably be done. + // Only port usages are affected. + assertNotEquals("Naturals", typeRightNameExpr.print()); + assertEquals("EventStream", typeRightNameExpr.print()); + + assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); + } + + @Test + public void testInvalidWithoutTCReset() throws IOException { + var optAst = SysMLv2Mill.parser().parse_String( "" + + "port def Naturals {\n" + + " out attribute channel: nat;\n" + + " out attribute channel1: nat;\n" + + "}\n" + + "\n" + + "part def LogicBasedConstraints {\n" + + " port input: ~Naturals;\n" + + " port output: Naturals;\n" + + "\n" + + " constraint streams {\n" + + " input == input.channel\n" + + " }\n" + + "}\n"); + assertThat(optAst).isPresent(); + + ASTSysMLModel ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var expression = (ASTEqualsExpression)((ASTPartDef)ast.getSysMLElement(1)) + .getSysMLElements(ASTConstraintUsage.class) + .get(0) + .getExpression(); + + var typeEq = TypeCheck3.typeOf(expression); + // in the case there are multiple C&C ports, only field accesses are streams + assertTrue(typeEq.isObscureType()); + + var leftNameExpr = (ASTNameExpression)expression.getLeft(); + var typeLeftNameExpr = TypeCheck3.typeOf(leftNameExpr); + assertEquals("Naturals", typeLeftNameExpr.print()); + + var rightFieldAccess = (ASTFieldAccessExpression)expression.getRight(); + var typeRightFieldAccess = TypeCheck3.typeOf(rightFieldAccess); + assertEquals("EventStream", typeRightFieldAccess.print()); + + var rightNameExpr = (ASTNameExpression)((ASTFieldAccessExpression)expression.getRight()).getExpression(); + var typeRightNameExpr = TypeCheck3.typeOf(rightNameExpr); + assertEquals("Naturals", typeRightNameExpr.print()); + + assertFalse(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); + } +} diff --git a/language/src/test/resources/cocos/constraints/17_invalid.sysml b/language/src/test/resources/cocos/constraints/17_invalid.sysml new file mode 100644 index 00000000..2fada1ee --- /dev/null +++ b/language/src/test/resources/cocos/constraints/17_invalid.sysml @@ -0,0 +1,15 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + + constraint constraintName { + myPortDef.natAttr.nth(3).nth(2) < myPortDef.natAttr.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/17_valid.sysml b/language/src/test/resources/cocos/constraints/17_valid.sysml new file mode 100644 index 00000000..25bd1798 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/17_valid.sysml @@ -0,0 +1,15 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + + constraint constraintName { + myPortDef.natAttr.nth(3).nth(2) == myPortDef.natAttr.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/18_invalid.sysml b/language/src/test/resources/cocos/constraints/18_invalid.sysml new file mode 100644 index 00000000..f3333e3a --- /dev/null +++ b/language/src/test/resources/cocos/constraints/18_invalid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.natAttr.nth(3).nth(2).a < myPortDef.a.natAttr.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/18_valid.sysml b/language/src/test/resources/cocos/constraints/18_valid.sysml new file mode 100644 index 00000000..423cab73 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/18_valid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.natAttr.nth(3).nth(2).a < myPortDef.natAttr.nth(3).nth(3).a + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_invalid.sysml new file mode 100644 index 00000000..6e423d52 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_invalid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute channel: int; +} + +part def LogicBasedConstraints { + port input: ~Integers; + + constraint streams { + input.length() > true + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_valid.sysml new file mode 100644 index 00000000..aad2617d --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_valid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Booleans { + out attribute boolAttr: boolean; +} + +part def LogicBasedConstraints { + port myPortDef: Booleans; + + constraint constraintName { + myPortDef.len() > 1 + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_invalid.sysml new file mode 100644 index 00000000..84763491 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_invalid.sysml @@ -0,0 +1,14 @@ +package 'Inverter' { + port def Booleans { + in attribute val: boolean; + } + + part def Inverter { + port input: Booleans; + port output: ~Booleans; + + assert constraint { + input == implies output == + } + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_valid.sysml new file mode 100644 index 00000000..d186b4ed --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_valid.sysml @@ -0,0 +1,14 @@ +package 'Inverter' { + port def Booleans { + in attribute val: boolean; + } + + part def Inverter { + port input: Booleans; + port output: ~Booleans; + + assert constraint { + input == implies output == + } + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_invalid.sysml new file mode 100644 index 00000000..19b54a46 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_invalid.sysml @@ -0,0 +1,12 @@ +port def Booleans { + in attribute val: boolean; +} + +part def Inverter { + port i: Booleans; + port o: ~Booleans; + + assert constraint { + forall nat k: i== .times(k, 5) implies o == .times(k) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_valid.sysml new file mode 100644 index 00000000..31ae1b18 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_valid.sysml @@ -0,0 +1,12 @@ +port def Booleans { + in attribute val: boolean; +} + +part def Inverter { + port i: Booleans; + port o: ~Booleans; + + assert constraint { + forall long k: i == .times(k) implies o == .times(k) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_invalid.sysml new file mode 100644 index 00000000..a56dcf2a --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_invalid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.nth(3).nth(2) < myPortDef.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_valid.sysml new file mode 100644 index 00000000..c596e24f --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_valid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.nth(3).nth(2) == myPortDef.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_invalid.sysml new file mode 100644 index 00000000..904d4028 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_invalid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: boolean; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.nth(3).nth(2).a < myPortDef.a.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_valid.sysml new file mode 100644 index 00000000..5c637644 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_valid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.nth(3).nth(2).a < myPortDef.nth(3).nth(3).a + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_invalid.sysml new file mode 100644 index 00000000..74470f73 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_invalid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute natAttr: int; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + + constraint constraintName { + myPortDef.nth(3).nth(3).natAttr > myPortDef.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_valid.sysml new file mode 100644 index 00000000..b29efbdf --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_valid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute natAttr: int; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + + constraint constraintName { + myPortDef.natAttr.nth(3).nth(3) > myPortDef.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_invalid.sysml new file mode 100644 index 00000000..0605c1c6 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_invalid.sysml @@ -0,0 +1,17 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute channel: int; +} + +port def Booleans { + out attribute channel: boolean; +} + +part def LogicBasedConstraints { + port input: ~Integers; + port output: Booleans; + + constraint streams { + input == output + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_valid.sysml new file mode 100644 index 00000000..40f652d6 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_valid.sysml @@ -0,0 +1,13 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute channel: int; +} + +part def LogicBasedConstraints { + port input: ~Integers; + port output: Integers; + + constraint streams { + input == output + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_invalid.sysml new file mode 100644 index 00000000..4e9a0c85 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_invalid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute channel: int; +} + +part def LogicBasedConstraints { + port input: ~Integers; + + constraint streams { + input.snth(5) > true + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_valid.sysml new file mode 100644 index 00000000..98343fa5 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_valid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute natAttr: int; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + + constraint constraintName { + myPortDef.nth(3).nth(3) > 1 + } +} From 6fb10d09eb5296e363d3676d91990674af105a1d Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Mon, 12 Jan 2026 11:55:46 +0100 Subject: [PATCH 03/50] Backporting 6 CoCos (#43) * PartTypeDefinitionExistsCoCo (#32) * CoCo1 Every type used in "part name:type" has to be an existing Part-Definition * Test for MKPXCoCo1 * rename and changed error code * RefinementTargetDefinitionExistsCoCo (#33) * CoCo2 Every name used in "part def X refines Name" has to be an existing Part-Definition. * add Test for MKPX_CoCo2 * renamed and changed error codes * UniqueSubPartNamesInConnectionCoCo (#34) * CoCo3 * Test for MKPX_CoCo3 * wrong import * rennamed and changed error codes * QualifiedPortNameExistsCoCo (#35) * CoCo4 * not responsible for undefined parts covered in MKPX_CoCo3 * Test for MKPX_CoCo4 * add parser and Model Path * Missing Import SysMLv2Parser * Missing import assertFalse * Update MKPXCoCo4Test.java * Update MKPXCoCo4Test.java * Update MKPXCoCo4Test.java * Update MKPXCoCo4Test.java * syntax error fixed * renamed and changed error code * ParentComponentInputConnectionDirectionCoCo (#37) * CoCo6 * clean up * Update MKPX_CoCo6.java * Test for MKPX_CoCo6 * add parser and model path * Missing Import SysMLv2Parser * Missing import assertFalse * Update MKPXCoCo6Test.java * Update MKPXCoCo6Test.java * Update MKPXCoCo6Test.java * explicit port direction * fixed resolving issue * added warnings for inout ports * rename and new error codes * conjugated Ports allowed and Tests added * SubcomponentOutputConnectionDirectionCoCo (#36) * CoCo5 * wrong dir and clean up * add Test for MKPX_CoCo5 * add parser and model path * Missing Import SysMLv2Parser * Missing import assertFalse * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPX_CoCo5.java * Revert "Update MKPX_CoCo5.java" This reverts commit ae76ff63630a7c01eb9602fc1d2fd0e3103888b2. * Update MKPX_CoCo5.java * Revert "Update MKPX_CoCo5.java" This reverts commit 710e2b812b7d20161129b66eafb7a84dfaeb30ae. * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPX_CoCo5.java * Update MKPX_CoCo5.java * Update MKPXCoCo5Test.java * Update MKPX_CoCo5.java * explicit port def from (0_valid.sysml) * syntax error * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * fixed resolving method * added warning for inout ports * extended warning for target port * renamed and new error codes * allow conjugated ports * added Tests for conjuagted Ports * clean up * Update SubcomponentOutputConnectionDirectionCoCo.java * Clean Up Tests (#42) use SysMLv2Tool for scope genration and symboltable creation * version bump to 7.8.3 --- gradle.properties | 2 +- ...ComponentInputConnectionDirectionCoCo.java | 197 ++++++++++++++++++ .../cocos/PartTypeDefinitionExistsCoCo.java | 39 ++++ .../cocos/QualifiedPortNameExistsCoCo.java | 96 +++++++++ .../RefinementTargetDefinitionExistsCoCo.java | 41 ++++ ...omponentOutputConnectionDirectionCoCo.java | 194 +++++++++++++++++ .../UniqueSubPartNamesInConnectionCoCo.java | 72 +++++++ ...onentInputConnectionDirectionCoCoTest.java | 157 ++++++++++++++ .../PartTypeDefinitionExistsCoCoTest.java | 107 ++++++++++ .../QualifiedPortNameExistsCoCoTest.java | 110 ++++++++++ ...inementTargetDefinitionExistsCoCoTest.java | 98 +++++++++ ...nentOutputConnectionDirectionCoCoTest.java | 175 ++++++++++++++++ ...niqueSubPartNamesInConnectionCoCoTest.java | 162 ++++++++++++++ 13 files changed, 1449 insertions(+), 1 deletion(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/PartTypeDefinitionExistsCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/QualifiedPortNameExistsCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java create mode 100644 language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java create mode 100644 language/src/test/java/cocos/PartTypeDefinitionExistsCoCoTest.java create mode 100644 language/src/test/java/cocos/QualifiedPortNameExistsCoCoTest.java create mode 100644 language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java create mode 100644 language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java create mode 100644 language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java diff --git a/gradle.properties b/gradle.properties index cda01f97..4cf7d37a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.2 +version = 7.8.3 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java new file mode 100644 index 00000000..49e05c85 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java @@ -0,0 +1,197 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTModifier; +import de.monticore.lang.sysmlbasis._ast.ASTSysMLTyping; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; +import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; +import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; +import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; +import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; +import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.se_rwth.commons.logging.Log; + +import java.util.List; +import java.util.Optional; + +/** + * ParentComponentInputConnectionDirectionCoCo + * Inputs von Oberkomponenten können nur zu Inputs von Subkomponenten oder Outputs der Oberkomponenten verbunden werden + * (alternative Formulierung): + * Inputs von Oberkomponenten können nicht zu Outputs von Subkomponenten verbunden werden. + */ +public class ParentComponentInputConnectionDirectionCoCo implements SysMLPartsASTConnectionUsageCoCo { + + @Override + public void check(ASTConnectionUsage node) { + // Skip validation if endpoints are missing + if (!node.isPresentSrc() || !node.isPresentTgt()) { + return; + } + + ASTEndpoint src = node.getSrc(); + ASTEndpoint tgt = node.getTgt(); + + String srcQName = endpointQName(src); + String tgtQName = endpointQName(tgt); + + ISysMLPartsScope scope = node.getEnclosingScope(); + + // Determine if endpoints reference subcomponents + boolean tgtIsSub = isSubcomponentEndpoint(tgtQName); + boolean srcIsSub = isSubcomponentEndpoint(srcQName); + + // Resolve port symbols + PortUsageSymbol tgtPort = resolvePortSymbol(scope, tgtQName, tgtIsSub); + PortUsageSymbol srcPort = resolvePortSymbol(scope, srcQName, srcIsSub); + + // If any port is unresolvable, let other CoCos handle it + if (srcPort == null || tgtPort == null) { + return; + } + + // Classify ports + boolean tgtIsInput = portIsInput(tgtPort); + boolean tgtIsOutput = portIsOutput(tgtPort); + + // Allowed connections: + // 1. Subcomponent with Input ports + // 2. Parent component with Output ports + boolean allowed = (tgtIsSub && tgtIsInput) || (!tgtIsSub && tgtIsOutput); + + if(srcIsSub || !portIsInput(srcPort)){ + // Source is neither input nor ParentComponent + // CoCo does not apply + return; + } + if( + (portIsInOutput(srcPort)) || + (portIsInOutput(tgtPort)) + ) { + Log.warn("0x10AA6 Warning: Connection involves an 'inout' port which may have ambiguous directionality.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd()); + } + + if (!allowed) { + Log.error( + "0x10AA6 Illegal connection: inputs of parent components can only be " + + "connected to inputs of subcomponents or outputs of the parent component.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } + + // -------- Hilfsmethoden -------- + + /** Qualified Name des Endpunkts als String. */ + protected String endpointQName(ASTEndpoint ep) { + if (ep.getMCQualifiedName() != null) { + return ep.getMCQualifiedName().toString(); + } + return ""; + } + + /** + * Heuristik: ein Name mit '.' steht für einen Port einer Subkomponente, + * z.B. "a.out". Ohne Punkt = Port der Oberkomponente. + */ + protected boolean isSubcomponentEndpoint(String qname) { + return qname.contains("."); + } + + /** Resolve port symbol based on whether it's in a subcomponent */ + protected PortUsageSymbol resolvePortSymbol(ISysMLPartsScope scope, + String qname, boolean isSub) { + if (isSub) { + return resolvePortOfSubPart(scope, qname); + } else { + return resolvePort(scope, qname); + } + } + + /** Resolve PortUsageSymbol by qualified name */ + protected PortUsageSymbol resolvePort(ISysMLPartsScope scope, String qname) { + List result = scope.resolvePortUsageSubKinds( + true, // search in enclosing scopes + qname, // qualified name, e.g., "a.out" + AccessModifier.ALL_INCLUSION, // ignore visibility + p -> true // no additional filtering + ); + + if (result.isEmpty()) { + return scope.resolvePortUsage(qname).orElse(null); + } + // If multiple candidates, take the first (should be unique in your models) + return result.get(0); + } + + /** Resolve port within a subcomponent */ + protected PortUsageSymbol resolvePortOfSubPart(ISysMLPartsScope scope, + String qname) { + // Split "a.out" into part "a" and port "out" + int lastDot = qname.lastIndexOf('.'); + if (lastDot == -1) { + return null; + } + + String partName = qname.substring(0, lastDot); + String portName = qname.substring(lastDot + 1); + + // Resolve the subcomponent + Optional partSymbol = scope.resolvePartUsage(partName); + if (partSymbol.isEmpty()) { + return null; + } + + Optional partDef = partSymbol.get().getPartDef(); + if (partDef.isPresent()) { + ISysMLPartsScope partScope = partDef.get().getSpannedScope(); + return resolvePort(partScope, portName); + } + + return null; + } + + /** Extract modifiers from PortUsageSymbol */ + protected ASTModifier getModifiersFromPortUsageSymbol(PortUsageSymbol symbol) { + ASTAttributeUsage portAttributeUsageAST = (ASTAttributeUsage) + symbol.getAstNode() + .getPortDefs() + .get(0) + .getSysMLElementList() + .get(0); + return portAttributeUsageAST.getModifier(); + } + + protected boolean portIsInput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + boolean portIsInAndNotConjugated = mods.isIn() && !portIsConjugated(symbol); + boolean portIsOutAndConjugated = mods.isOut() && portIsConjugated(symbol); + return (portIsInAndNotConjugated || portIsOutAndConjugated); + } + + protected boolean portIsOutput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + boolean portIsOutAndNotConjugated = mods.isOut() && !portIsConjugated(symbol); + boolean portIsInAndConjugated = mods.isIn() && portIsConjugated(symbol); + return (portIsOutAndNotConjugated || portIsInAndConjugated); + } + + protected boolean portIsInOutput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + return mods.isInout(); + } + + protected boolean portIsConjugated(PortUsageSymbol symbol) { + return + ((ASTSysMLTyping) symbol + .getAstNode() + .getSpecialization(0)) + .isConjugated(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/PartTypeDefinitionExistsCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/PartTypeDefinitionExistsCoCo.java new file mode 100644 index 00000000..faced490 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/PartTypeDefinitionExistsCoCo.java @@ -0,0 +1,39 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartUsageCoCo; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.se_rwth.commons.logging.Log; + +import java.util.stream.Collectors; + +/** + * CoCo1: Jeder in "part name:Typ" verwendete Typ muss eine existierende Part-Definition sein. + */ +public class PartTypeDefinitionExistsCoCo implements SysMLPartsASTPartUsageCoCo { + + protected String printPartType(ASTMCType type) { + return type.printType(); + } + + @Override + public void check(ASTPartUsage node) { + var nonExistent = node.streamSpecializations() + .flatMap(ASTSpecialization::streamSuperTypes) + .filter(t -> + node.getEnclosingScope().resolvePartDef(printPartType(t)).isEmpty() + ) + .collect(Collectors.toList()); + + for (var problem : nonExistent) { + Log.error( + "0x10AA1 The type referenced in a PartUsage \"" + printPartType(problem) + + "\" does not exist as a part definition.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/QualifiedPortNameExistsCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/QualifiedPortNameExistsCoCo.java new file mode 100644 index 00000000..f63d428e --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/QualifiedPortNameExistsCoCo.java @@ -0,0 +1,96 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; +import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; +import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; +import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; +import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.se_rwth.commons.logging.Log; + +import java.util.List; +import java.util.Optional; + +/** + * QualifiedPortNameExistsCoCo: + * In einer Verbindung "connect a.b to c.d" muss jeder verwendete (qualifizierte) Portname existieren. + */ +public class QualifiedPortNameExistsCoCo implements SysMLPartsASTConnectionUsageCoCo { + + @Override + public void check(ASTConnectionUsage node) { + if (!node.isPresentSrc() || !node.isPresentTgt()) { + return; // keine Verbindung + } + + ISysMLPartsScope scope = node.getEnclosingScope(); + + checkEndpoint(scope, node.getSrc(), node); + checkEndpoint(scope, node.getTgt(), node); + } + + protected void checkEndpoint(ISysMLPartsScope scope, + ASTEndpoint endpoint, + ASTConnectionUsage conn) { + String qname = endpointQName(endpoint); + if (qname.isEmpty()) { + return; + } + + String[] parts = qname.split("\\."); + + // Qualifizierter Name: a.b -> resolve a (PartUsage), dann b in PartDef + if (parts.length >= 2) { + String partName = parts[0]; + String portName = parts[parts.length - 1]; + + Optional partOpt = scope.resolvePartUsageLocally(partName); + + if (partOpt.isEmpty()) { + // Existenz der Subkomponente wird bereits in MKPX_CoCo3 geprüft. + return; + } + + var partDefOpt = partOpt.get().getPartDef(); + if (partDefOpt.isEmpty()) { + // CoCo3 + return; + } + + PartDefSymbol partDef = partDefOpt.get(); + boolean portExistsInDef = partDef.getSpannedScope() + .resolvePortUsageLocallyMany(false, portName, AccessModifier.ALL_INCLUSION, p -> true) + .size() == 1; + + if (!portExistsInDef) { + Log.error( + "0x10AA4 The port '" + portName + "' does not exist in the definition of subcomponent '" + + partName + "'.", + conn.get_SourcePositionStart(), + conn.get_SourcePositionEnd() + ); + } + } + else { + // Unqualifiziert: Port der Oberkomponente muss lokal existieren + String portName = parts[0]; + List localPorts = scope.resolvePortUsageLocallyMany( + false, portName, AccessModifier.ALL_INCLUSION, p -> true); + if (localPorts.isEmpty()) { + Log.error( + "0x10AA4 The port used in 'connect' '" + portName + + "' does not exist in the parent component.", + conn.get_SourcePositionStart(), + conn.get_SourcePositionEnd() + ); + } + } + } + + /** Liefert den qualifizierten Namen des Endpunkts als String. */ + protected String endpointQName(ASTEndpoint ep) { + return ep.getMCQualifiedName() != null ? ep.getMCQualifiedName().toString() : ""; + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java new file mode 100644 index 00000000..3b7338d3 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java @@ -0,0 +1,41 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; +import de.monticore.lang.sysmlbasis._ast.ASTSysMLRefinement; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartDefCoCo; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.se_rwth.commons.logging.Log; + +import java.util.stream.Collectors; + +/** + * CoCo2: Jeder im "part def X refines Name" verwendete Name muss eine existierende Part-Definition sein. + */ +public class RefinementTargetDefinitionExistsCoCo implements SysMLPartsASTPartDefCoCo { + + protected String printPartType(ASTMCType type) { + return type.printType(); + } + + @Override + public void check(ASTPartDef node) { + var nonExistent = node.streamSpecializations() + .filter(s -> s instanceof ASTSysMLRefinement) + .flatMap(ASTSpecialization::streamSuperTypes) + .filter(t -> + node.getEnclosingScope().resolvePartDef(printPartType(t)).isEmpty() + ) + .collect(Collectors.toList()); + + for (var problem : nonExistent) { + Log.error( + "0x10AA2 The name used in 'refines' \"" + printPartType(problem) + + "\" does not exist as a part definition.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java new file mode 100644 index 00000000..8a3389c3 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java @@ -0,0 +1,194 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTModifier; +import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; +import de.monticore.lang.sysmlbasis._ast.ASTSysMLTyping; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; +import de.monticore.lang.sysmlparts._symboltable.*; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.se_rwth.commons.logging.Log; + +import java.util.List; +import java.util.Optional; + +/** + * SubcomponentOutputConnectionDirectionCoCo + * Checks that outputs of subcomponents can only be connected to: + * 1. Inputs of subcomponents, or + * 2. Outputs of the parent component. + */ +public class SubcomponentOutputConnectionDirectionCoCo implements SysMLPartsASTConnectionUsageCoCo { + + @Override + public void check(ASTConnectionUsage node) { + // Skip validation if endpoints are missing + if (!node.isPresentSrc() || !node.isPresentTgt()) { + return; + } + + ASTEndpoint src = node.getSrc(); + ASTEndpoint tgt = node.getTgt(); + + String srcQName = endpointQName(src); + String tgtQName = endpointQName(tgt); + + ISysMLPartsScope scope = node.getEnclosingScope(); + + // Determine if endpoints reference subcomponents + boolean tgtIsSub = isSubcomponentEndpoint(tgtQName); + boolean srcIsSub = isSubcomponentEndpoint(srcQName); + + // Resolve port symbols + PortUsageSymbol tgtPort = resolvePortSymbol(scope, tgtQName, tgtIsSub); + PortUsageSymbol srcPort = resolvePortSymbol(scope, srcQName, srcIsSub); + + // If any port is unresolvable, let other CoCos handle it + if (srcPort == null || tgtPort == null) { + return; + } + + // Classify ports + boolean tgtIsInput = portIsInput(tgtPort); + boolean tgtIsOutput = portIsOutput(tgtPort); + + // Allowed connections: + // 1. Subcomponent with Input ports + // 2. Parent component with Output ports + boolean allowed = (tgtIsSub && tgtIsInput) || (!tgtIsSub && tgtIsOutput); + + if(!srcIsSub || !portIsOutput(srcPort)){ + // Source is neither output nor Subcomponent + // CoCo does not apply + return; + } + if( + (portIsInOutput(srcPort)) || + (portIsInOutput(tgtPort)) + ) { + Log.warn("0x10AA5 Warning: Connection involves an 'inout' port which may have ambiguous directionality.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd()); + } + + if (!allowed) { + Log.error( + "0x10AA5 Illegal connection: outputs of subcomponents can only be " + + "connected to inputs of subcomponents or outputs of the parent component.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } + + // -------- Hilfsmethoden -------- + + /** Qualified Name des Endpunkts als String. */ + protected String endpointQName(ASTEndpoint ep) { + if (ep.getMCQualifiedName() != null) { + return ep.getMCQualifiedName().toString(); + } + return ""; + } + + /** + * Heuristik: ein Name mit '.' steht für einen Port einer Subkomponente, + * z.B. "a.out". Ohne Punkt = Port der Oberkomponente. + */ + protected boolean isSubcomponentEndpoint(String qname) { + return qname.contains("."); + } + + /** Resolve port symbol based on whether it's in a subcomponent */ + protected PortUsageSymbol resolvePortSymbol(ISysMLPartsScope scope, + String qname, boolean isSub) { + if (isSub) { + return resolvePortOfSubPart(scope, qname); + } else { + return resolvePort(scope, qname); + } + } + + /** Resolve PortUsageSymbol by qualified name */ + protected PortUsageSymbol resolvePort(ISysMLPartsScope scope, String qname) { + List result = scope.resolvePortUsageSubKinds( + true, // search in enclosing scopes + qname, // qualified name, e.g., "a.out" + AccessModifier.ALL_INCLUSION, // ignore visibility + p -> true // no additional filtering + ); + + if (result.isEmpty()) { + return scope.resolvePortUsage(qname).orElse(null); + } + // If multiple candidates, take the first (should be unique in your models) + return result.get(0); + } + + /** Resolve port within a subcomponent */ + protected PortUsageSymbol resolvePortOfSubPart(ISysMLPartsScope scope, + String qname) { + // Split "a.out" into part "a" and port "out" + int lastDot = qname.lastIndexOf('.'); + if (lastDot == -1) { + return null; + } + + String partName = qname.substring(0, lastDot); + String portName = qname.substring(lastDot + 1); + + // Resolve the subcomponent + Optional partSymbol = scope.resolvePartUsage(partName); + if (partSymbol.isEmpty()) { + return null; + } + + Optional partDef = partSymbol.get().getPartDef(); + if (partDef.isPresent()) { + ISysMLPartsScope partScope = partDef.get().getSpannedScope(); + return resolvePort(partScope, portName); + } + + return null; + } + + /** Extract modifiers from PortUsageSymbol */ + protected ASTModifier getModifiersFromPortUsageSymbol(PortUsageSymbol symbol) { + ASTAttributeUsage portAttributeUsageAST = (ASTAttributeUsage) + symbol.getAstNode() + .getPortDefs() + .get(0) + .getSysMLElementList() + .get(0); + return portAttributeUsageAST.getModifier(); + } + + protected boolean portIsInput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + boolean portIsInAndNotConjugated = mods.isIn() && !portIsConjugated(symbol); + boolean portIsOutAndConjugated = mods.isOut() && portIsConjugated(symbol); + return (portIsInAndNotConjugated || portIsOutAndConjugated); + } + + protected boolean portIsOutput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + boolean portIsOutAndNotConjugated = mods.isOut() && !portIsConjugated(symbol); + boolean portIsInAndConjugated = mods.isIn() && portIsConjugated(symbol); + return (portIsOutAndNotConjugated || portIsInAndConjugated); + } + + protected boolean portIsInOutput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + return mods.isInout(); + } + + protected boolean portIsConjugated(PortUsageSymbol symbol) { + return + ((ASTSysMLTyping) symbol + .getAstNode() + .getSpecialization(0)) + .isConjugated(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java new file mode 100644 index 00000000..70161fe8 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java @@ -0,0 +1,72 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; +import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; +import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.se_rwth.commons.logging.Log; + +/** + * CoCo3: Jeder in "connect a.b to c.d" verwendete Name von Subkomponenten (a und c) + * muss eindeutig im Modell vorhanden sein. + */ +public class UniqueSubPartNamesInConnectionCoCo implements SysMLPartsASTConnectionUsageCoCo { + + @Override + public void check(ASTConnectionUsage node) { + if (!node.isPresentSrc() || !node.isPresentTgt()) { + return; // keine Verbindung + } + + var scope = node.getEnclosingScope(); + + checkSubcomponentQualifier(scope, node.getSrc(), node); + checkSubcomponentQualifier(scope, node.getTgt(), node); + } + + protected void checkSubcomponentQualifier(ISysMLPartsScope scope, + ASTEndpoint endpoint, + ASTConnectionUsage node) { + String qname = endpointQName(endpoint); + String subName = extractFirstSegment(qname); + + if (subName == null) { + return; + } + + int matches = scope + .resolvePartUsageLocallyMany(false, subName, + AccessModifier.ALL_INCLUSION, p -> true) + .size(); + + if (matches > 1) { + Log.error( + "0x10AA3 The subcomponent name used in 'connect' \"" + subName + + "\" is not unique in the model.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } else if (matches != 1) { /** matches = 0 */ + Log.error( + "0x10AA3 The subcomponent name used in 'connect' \"" + subName + + "\" does not exist in the model.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } + + protected String endpointQName(ASTEndpoint ep) { + return ep.getMCQualifiedName() != null ? ep.getMCQualifiedName().toString() : ""; + } + + protected String extractFirstSegment(String qname) { + int dot = qname.indexOf('.'); + if (dot > 0) { + return qname.substring(0, dot); + } + return null; + } +} diff --git a/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java b/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java new file mode 100644 index 00000000..4374e2b7 --- /dev/null +++ b/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java @@ -0,0 +1,157 @@ +/* (c) https://github.com/MontiCore/monticore */ +package cocos; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2.cocos.ParentComponentInputConnectionDirectionCoCo; +import de.se_rwth.commons.logging.Finding; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ParentComponentInputConnectionDirectionCoCoTest { + + private static final String MODEL_PATH = "src/test/resources/parser"; + + private SysMLv2Parser parser = SysMLv2Mill.parser(); + + @BeforeAll + public static void init() { + Log.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + Log.clearFindings(); + } + + @Nested + public class InputConnectionTests { + @Test + public void testValid() throws IOException { + String validModel = + "port def InPort { in attribute data: int; }" + + "port def OutPort { out attribute data: int; }" + + "part def A { port input: InPort; }" + + "part def B { port output: OutPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "port sysInAnother: InPort;" + + "port sysOut: OutPort;" + + "part a: A;" + + "part b: B;" + + "connect sysIn to a.input;" + + "connect sysInAnother to sysOut;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testValidConjugatedModel() throws IOException { + String validModel = + "port def InPort { in attribute data: int; }" + + "part def A { port input: InPort; }" + + "part def B { port output: ~InPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "port sysInAnother: InPort;" + + "port sysOut: ~InPort;" + + "part a: A;" + + "part b: B;" + + "connect sysIn to a.input;" + + "connect sysInAnother to sysOut;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalid() throws IOException { + String invalidModel = + "port def InPort { in attribute data: int; }" + + "port def OutPort { out attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "part a: A;" + + "connect sysIn to a.output;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA6"); + } + + @Test + public void testInvalidConjugatedModel() throws IOException { + String invalidModel = + "port def InPort { in attribute data: int; }" + + "part def A { port output: ~InPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "part a: A;" + + "connect sysIn to a.output;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA6"); + } + + private ASTSysMLModel parse(String model) throws IOException { + var optAst = SysMLv2Mill.parser().parse_String(model); + assertThat(optAst).isPresent(); + return optAst.get(); + } + + private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { + var tool = new SysMLv2Tool(); + var scope = tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + return scope; + } + + private List check(ASTSysMLModel ast) { + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} diff --git a/language/src/test/java/cocos/PartTypeDefinitionExistsCoCoTest.java b/language/src/test/java/cocos/PartTypeDefinitionExistsCoCoTest.java new file mode 100644 index 00000000..a5a0f380 --- /dev/null +++ b/language/src/test/java/cocos/PartTypeDefinitionExistsCoCoTest.java @@ -0,0 +1,107 @@ +/* (c) https://github.com/MontiCore/monticore */ +package cocos; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2.cocos.PartTypeDefinitionExistsCoCo; +import de.se_rwth.commons.logging.Finding; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PartTypeDefinitionExistsCoCoTest { + + private static final String MODEL_PATH = "src/test/resources/parser"; + + private SysMLv2Parser parser = SysMLv2Mill.parser(); + + @BeforeAll + public static void init() { + Log.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + Log.clearFindings(); + } + + @Nested + public class PartTypeDefinitionExistsCoCoTests { + @Test + public void testValid() throws IOException { + String validModel = + "part def SubComponent1;" + + "part def SubComponent2;" + + "part def MainComponent{" + + "part subcomp1: SubComponent1;" + + "part subcomp2: SubComponent2;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalid() throws IOException { + String invalidModel = + "part def SubComponent1;" + + "part def MainComponent{" + + "part subcomp1: SubComponent1;" + + "part subcomp2: UndefinedComponent;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA1"); + } + + private ASTSysMLModel parse(String model) throws IOException { + var optAst = SysMLv2Mill.parser().parse_String(model); + assertThat(optAst).isPresent(); + return optAst.get(); + } + + private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { + var tool = new SysMLv2Tool(); + var scope = tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + return scope; + } + + private List check(ASTSysMLModel ast) { + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new PartTypeDefinitionExistsCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} diff --git a/language/src/test/java/cocos/QualifiedPortNameExistsCoCoTest.java b/language/src/test/java/cocos/QualifiedPortNameExistsCoCoTest.java new file mode 100644 index 00000000..b55a6e8e --- /dev/null +++ b/language/src/test/java/cocos/QualifiedPortNameExistsCoCoTest.java @@ -0,0 +1,110 @@ +/* (c) https://github.com/MontiCore/monticore */ +package cocos; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo; +import de.se_rwth.commons.logging.Finding; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class QualifiedPortNameExistsCoCoTest { + + private static final String MODEL_PATH = "src/test/resources/parser"; + + private SysMLv2Parser parser = SysMLv2Mill.parser(); + + @BeforeAll + public static void init() { + Log.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + Log.clearFindings(); + } + + @Nested + public class QualifiedPortNameExistsCoCoTests { + @Test + public void testValid() throws IOException { + String validModel = + "part def A { port p: int; }" + + "part def B { port q: ~int; }" + + "part def System {" + + "part a: A;" + + "part b: B;" + + "connect a.p to b.q;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalid() throws IOException { + String invalidModel = + "part def A { port p: int; }" + + "part def B { port q: ~int; }" + + "part def System {" + + "part a: A;" + + "part b: B;" + + "connect a.wrongName to b.q;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA4"); + } + + private ASTSysMLModel parse(String model) throws IOException { + var optAst = SysMLv2Mill.parser().parse_String(model); + assertThat(optAst).isPresent(); + return optAst.get(); + } + + private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { + var tool = new SysMLv2Tool(); + var scope = tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + return scope; + } + + private List check(ASTSysMLModel ast) { + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new QualifiedPortNameExistsCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} diff --git a/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java b/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java new file mode 100644 index 00000000..a9e924de --- /dev/null +++ b/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java @@ -0,0 +1,98 @@ +/* (c) https://github.com/MontiCore/monticore */ +package cocos; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; +import de.se_rwth.commons.logging.Finding; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RefinementTargetDefinitionExistsCoCoTest { + + private static final String MODEL_PATH = "src/test/resources/parser"; + + private SysMLv2Parser parser = SysMLv2Mill.parser(); + + @BeforeAll + public static void init() { + Log.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + Log.clearFindings(); + } + + @Nested + public class RefinementTargetDefinitionExistsCoCoTests { + @Test + public void testValid() throws IOException { + String validModel = + "part def BasePart;" + + "part def Refining refines BasePart;"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalid() throws IOException { + String invalidModel = "part def Refining refines UndefinedBasePart;"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA2"); + } + + private ASTSysMLModel parse(String model) throws IOException { + var optAst = SysMLv2Mill.parser().parse_String(model); + assertThat(optAst).isPresent(); + return optAst.get(); + } + + private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { + var tool = new SysMLv2Tool(); + var scope = tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + return scope; + } + + private List check(ASTSysMLModel ast) { + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} diff --git a/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java b/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java new file mode 100644 index 00000000..18c74360 --- /dev/null +++ b/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java @@ -0,0 +1,175 @@ +/* (c) https://github.com/MontiCore/monticore */ +package cocos; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2.cocos.SubcomponentOutputConnectionDirectionCoCo; +import de.se_rwth.commons.logging.Finding; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SubcomponentOutputConnectionDirectionCoCoTest { + + private static final String MODEL_PATH = "src/test/resources/parser"; + + private SysMLv2Parser parser = SysMLv2Mill.parser(); + + @BeforeAll + public static void init() { + Log.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + Log.clearFindings(); + } + + @Nested + public class OutputConnectionTests { + + @Test + public void testValid() throws IOException { + String validModel = + "port def OutPort { out attribute data: int; }" + + "port def InPort { in attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def B { port input: InPort; }" + + "part def C { port output: OutPort; }" + + "part def System {" + + "port sysOutput: OutPort;" + + "part a: A;" + + "part b: B;" + + "part c: C;" + + "connect a.output to b.input;" // (Sub) Output -> (Sub) Input + + "connect c.output to sysOutput;" // (Sub) Output -> (main) Output + + "}"; + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testValidConjugatedModel() throws IOException { + String validModel = + "port def OutPort { out attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def B { port input: ~OutPort; }" + + "part def C { port output: OutPort; }" + + "part def System {" + + "port sysOutput: OutPort;" + + "part a: A;" + + "part b: B;" + + "part c: C;" + + "connect a.output to b.input;" // (Sub) Output -> (Sub) Input + + "connect c.output to sysOutput;" // (Sub) Output -> (main) Output + + "}"; + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalidSubOutToSubOut() throws IOException { + String invalidModel = + "port def OutPort { out attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def B { port output: OutPort; }" + + "part def System {" + + "part a: A;" + + "part b: B;" + + "connect a.output to b.output;" // (Sub) Output -> (Sub) Output + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA5"); + } + + @Test + public void testInvalidSubOutToMainInConjugatedModel() throws IOException { + String invalidModel = + "port def OutPort { out attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def System {" + + "port sysInput: ~OutPort;" + + "part a: A;" + + "connect a.output to sysInput;" // (Sub) Output -> (main) Input + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA5"); + } + + @Test + public void testInvalidSubOutToMainIn() throws IOException { + String invalidModel = + "port def OutPort { out attribute data: int; }" + + "port def InPort { in attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def System {" + + "port sysInput: InPort;" + + "part a: A;" + + "connect a.output to sysInput;" // (Sub) Output -> (main) Input + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA5"); + } + + private ASTSysMLModel parse(String model) throws IOException { + var optAst = SysMLv2Mill.parser().parse_String(model); + assertThat(optAst).isPresent(); + return optAst.get(); + } + + private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { + var tool = new SysMLv2Tool(); + var scope = tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + return scope; + } + + private List check(ASTSysMLModel ast) { + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new SubcomponentOutputConnectionDirectionCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} diff --git a/language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java b/language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java new file mode 100644 index 00000000..38913d6b --- /dev/null +++ b/language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java @@ -0,0 +1,162 @@ +/* (c) https://github.com/MontiCore/monticore */ +package cocos; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInConnectionCoCo; +import de.se_rwth.commons.logging.Finding; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class UniqueSubPartNamesInConnectionCoCoTest { + + private static final String MODEL_PATH = "src/test/resources/parser"; + + private SysMLv2Parser parser = SysMLv2Mill.parser(); + + @BeforeAll + public static void init() { + Log.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + Log.clearFindings(); + } + + @Nested + public class UniqueSubPartNamesInConnectionCoCoTests { + @Test + public void testValid() throws IOException { + String validModel = + "part def A { port p: int; }" + + "part def B { port q: ~int; }" + + "part def System {" + + "part a: A;" + + "part b: B;" + + "connect a.p to b.q;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalidUndefined() throws IOException { + String invalidModel = + "part def A { port p: int; }" + + "part def B { port q: ~int; }" + + "part def System {" + + "part a: A;" + + "connect a.p to c.q;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA3"); + } + + @Test + public void testInvalidDuplicateName() throws IOException { + String invalidModel = + "part def A { port p; }" + + "part def System {" + + "part a: A;" + + "part a: A;" + + "connect a.p to a.p;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(2); + assertThat(errors.get(0).getMsg()).contains("0x10AA3"); + assertThat(errors.get(1).getMsg()).contains("0x10AA3"); + } + + @Test + public void testInvalidBothUndefined() throws IOException { + String invalidModel = + "part def A { port p; }" + + "part def System {" + + "part a: A;" + + "connect undefined1.p to undefined2.p;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(2); + assertThat(errors.get(0).getMsg()).contains("0x10AA3"); + assertThat(errors.get(1).getMsg()).contains("0x10AA3"); + } + + @Test + public void testInvalidUndefinedAndDuplicateName() throws IOException { + String invalidModel = + "part def A { port p; }" + + "part def System {" + + "part duplicate1: A;" + + "part duplicate1: ~A;" + + "connect duplicate1.p to undefined3.p;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(2); + assertThat(errors.get(0).getMsg()).contains("0x10AA3"); + assertThat(errors.get(1).getMsg()).contains("0x10AA3"); + } + + private ASTSysMLModel parse(String model) throws IOException { + var optAst = SysMLv2Mill.parser().parse_String(model); + assertThat(optAst).isPresent(); + return optAst.get(); + } + + private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { + var tool = new SysMLv2Tool(); + var scope = tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + return scope; + } + + private List check(ASTSysMLModel ast) { + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} From b470d3148ecfac64ce31d135a58ea59fa57ef679 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:28:02 +0100 Subject: [PATCH 04/50] add CoCos to Checker (#44) * add CoCos to Checker * version bump to 7.8.4 --- gradle.properties | 2 +- .../de/monticore/lang/sysmlv2/SysMLv2Tool.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4cf7d37a..5af85ba3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.3 +version = 7.8.4 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index bb49c544..c8960180 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -41,6 +41,12 @@ import de.monticore.lang.sysmlv2.cocos.TypeCheckTransitionGuards; import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; +import de.monticore.lang.sysmlv2.cocos.PartTypeDefinitionExistsCoCo; +import de.monticore.lang.sysmlv2.cocos.ParentComponentInputConnectionDirectionCoCo; +import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo; +import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; +import de.monticore.lang.sysmlv2.cocos.SubcomponentOutputConnectionDirectionCoCo; +import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInConnectionCoCo; import de.monticore.lang.sysmlv2.symboltable.completers.CausalityCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectRefinementCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectionCompleter; @@ -167,6 +173,16 @@ public void runAdditionalCoCos( checker.addCoCo(new PortDefinitionExistsCoCo()); checker.addCoCo(new PartBehaviorCoCo()); + // Check Definitions exist + checker.addCoCo(new PartTypeDefinitionExistsCoCo()); + checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); + + // Connection CoCos + checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); + checker.addCoCo(new QualifiedPortNameExistsCoCo()); + checker.addCoCo(new SubcomponentOutputConnectionDirectionCoCo()); + checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); + checker.checkAll(ast); } From e84c971614f74b5910b480c31862ca020ce8fb13 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Sun, 18 Jan 2026 09:07:04 +0100 Subject: [PATCH 05/50] CoCos to default and version bump (#46) * switched some CoCos from extended Checker to default Checker * version bump to 7.8.5 --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5af85ba3..5fd9e5fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.4 +version = 7.8.5 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index c8960180..98922538 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -122,6 +122,15 @@ public void runDefaultCoCos(ASTSysMLModel ast) { checker.addCoCo(new SendActionTypeCheck3()); checker.addCoCo(new AssignActionTypeCheck3()); checker.addCoCo(new TypeCheck3TransitionGuards()); + // Check Definitions exist + checker.addCoCo(new PartTypeDefinitionExistsCoCo()); + checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); + // Connection CoCos + checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); + checker.addCoCo(new QualifiedPortNameExistsCoCo()); + checker.addCoCo(new SubcomponentOutputConnectionDirectionCoCo()); + checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); + checker.checkAll(ast); } @@ -173,16 +182,6 @@ public void runAdditionalCoCos( checker.addCoCo(new PortDefinitionExistsCoCo()); checker.addCoCo(new PartBehaviorCoCo()); - // Check Definitions exist - checker.addCoCo(new PartTypeDefinitionExistsCoCo()); - checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); - - // Connection CoCos - checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); - checker.addCoCo(new QualifiedPortNameExistsCoCo()); - checker.addCoCo(new SubcomponentOutputConnectionDirectionCoCo()); - checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); - checker.checkAll(ast); } From 255df7bd60e9c8e0c406ac162ca45add22a891aa Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:42:17 +0200 Subject: [PATCH 06/50] Eps added to global scope (#47) * Eps added to global scope * Version erhoeht --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Mill.java | 18 +++++++ .../test/java/symboltable/TsynTypeTest.java | 50 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 language/src/test/java/symboltable/TsynTypeTest.java diff --git a/gradle.properties b/gradle.properties index 5fd9e5fe..ff425dfa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.5 +version = 7.8.6 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java index 04fd57b2..d9dc1f6b 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java @@ -32,6 +32,7 @@ public static void prepareGlobalScope() { SysMLv2Mill.initializePrimitives(); SysMLv2Mill.addStringType(); SysMLv2Mill.addCollectionTypes(); + SysMLv2Mill.addTsynTypes(); } /** @@ -171,6 +172,23 @@ protected void _addCollectionTypes() { } } + public static void addTsynTypes() { + getMill()._addTsynTypes(); + } + + protected void _addTsynTypes() { + if (SysMLv2Mill.globalScope().resolveType("Eps").isEmpty()) { + var eps = typeSymbolBuilder() + .setName("Eps") + .setEnclosingScope(globalScope()) + .setFullName("Eps") + .setSpannedScope(scope()) + .setAccessModifier(AccessModifier.ALL_INCLUSION) + .build(); + SysMLv2Mill.globalScope().add(eps); + } + } + protected OOTypeSymbol buildCollectionType(String name, String... typeVars) { var spannedScope = scope(); diff --git a/language/src/test/java/symboltable/TsynTypeTest.java b/language/src/test/java/symboltable/TsynTypeTest.java new file mode 100644 index 00000000..6b7eed4e --- /dev/null +++ b/language/src/test/java/symboltable/TsynTypeTest.java @@ -0,0 +1,50 @@ +package symboltable; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class TsynTypeTest { + + @BeforeAll + static void setup() { + SysMLv2Mill.init(); + } + + @BeforeEach + public void init() { + LogStub.init(); + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + SysMLv2Mill.addTsynTypes(); + Log.clearFindings(); + } + + @Test + public void testEpsInModel() throws IOException { + var tool = new SysMLv2Tool(); + + var model = "part def Valid { attribute e: Eps; }"; + var optAst = SysMLv2Mill.parser().parse_String(model); + + assertThat(optAst).isPresent(); + ASTSysMLModel ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + + assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); + } + +} From 12e3e3736044211bd6284db0cbe7f50512773b1e Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:15:57 +0100 Subject: [PATCH 07/50] CoCo: Erkennung doppelt verwendeter Part-Namen (Backport) (#49) * clean up SubPartNamesInConnectionExistCoCo remove ambiguous name check from SubPartNamesInConnectionExistCoCo * add UniqueSubPartNamesInParentCoCo * update SysMLv2Tool Checker * version bump to 7.8.7 --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 9 +- ...=> SubPartNamesInConnectionExistCoCo.java} | 15 +-- .../cocos/UniqueSubPartNamesInParentCoCo.java | 35 ++++++ ...ubPartNamesInConnectionExistCoCoTest.java} | 42 +------ .../UniqueSubPartNamesInParentCoCoTest.java | 104 ++++++++++++++++++ 6 files changed, 155 insertions(+), 52 deletions(-) rename language/src/main/java/de/monticore/lang/sysmlv2/cocos/{UniqueSubPartNamesInConnectionCoCo.java => SubPartNamesInConnectionExistCoCo.java} (82%) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInParentCoCo.java rename language/src/test/java/cocos/{UniqueSubPartNamesInConnectionCoCoTest.java => SubPartNamesInConnectionExistCoCoTest.java} (72%) create mode 100644 language/src/test/java/cocos/UniqueSubPartNamesInParentCoCoTest.java diff --git a/gradle.properties b/gradle.properties index ff425dfa..1966761e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.6 +version = 7.8.7 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 98922538..4bd3bc19 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -46,7 +46,8 @@ import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo; import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; import de.monticore.lang.sysmlv2.cocos.SubcomponentOutputConnectionDirectionCoCo; -import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInConnectionCoCo; +import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; +import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; import de.monticore.lang.sysmlv2.symboltable.completers.CausalityCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectRefinementCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectionCompleter; @@ -126,11 +127,13 @@ public void runDefaultCoCos(ASTSysMLModel ast) { checker.addCoCo(new PartTypeDefinitionExistsCoCo()); checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); // Connection CoCos - checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); + checker.addCoCo(new SubPartNamesInConnectionExistCoCo()); checker.addCoCo(new QualifiedPortNameExistsCoCo()); checker.addCoCo(new SubcomponentOutputConnectionDirectionCoCo()); checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); - + // Check ambiguous names + checker.addCoCo(new UniqueSubPartNamesInParentCoCo()); + checker.checkAll(ast); } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubPartNamesInConnectionExistCoCo.java similarity index 82% rename from language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java rename to language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubPartNamesInConnectionExistCoCo.java index 70161fe8..683f207c 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubPartNamesInConnectionExistCoCo.java @@ -10,9 +10,9 @@ /** * CoCo3: Jeder in "connect a.b to c.d" verwendete Name von Subkomponenten (a und c) - * muss eindeutig im Modell vorhanden sein. + * muss im Modell vorhanden sein. */ -public class UniqueSubPartNamesInConnectionCoCo implements SysMLPartsASTConnectionUsageCoCo { +public class SubPartNamesInConnectionExistCoCo implements SysMLPartsASTConnectionUsageCoCo { @Override public void check(ASTConnectionUsage node) { @@ -42,13 +42,10 @@ protected void checkSubcomponentQualifier(ISysMLPartsScope scope, .size(); if (matches > 1) { - Log.error( - "0x10AA3 The subcomponent name used in 'connect' \"" + subName - + "\" is not unique in the model.", - node.get_SourcePositionStart(), - node.get_SourcePositionEnd() - ); - } else if (matches != 1) { /** matches = 0 */ + /* + * ambiguous names in PartDefinition are caught by UniqueSubPartNamesInParentCoCo + */ + } else if (matches == 0) { Log.error( "0x10AA3 The subcomponent name used in 'connect' \"" + subName + "\" does not exist in the model.", diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInParentCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInParentCoCo.java new file mode 100644 index 00000000..9bd3f697 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInParentCoCo.java @@ -0,0 +1,35 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartUsageCoCo; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.se_rwth.commons.logging.Log; + +/** + * CoCo: Jede Subkomponente muss einen eindeutigen Namen haben + */ +public class UniqueSubPartNamesInParentCoCo implements SysMLPartsASTPartUsageCoCo { + + @Override + public void check(ASTPartUsage node) { + + var scope = node.getEnclosingScope(); + + String partName = node.getName(); + + int matches = scope + .resolvePartUsageLocallyMany(false, partName, + AccessModifier.ALL_INCLUSION, p -> true) + .size(); + + if (matches > 1) { + Log.error( + "0x10AA7 The subcomponent name used in 'def' \"" + partName + + "\" is not unique in the model.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } +} diff --git a/language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java b/language/src/test/java/cocos/SubPartNamesInConnectionExistCoCoTest.java similarity index 72% rename from language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java rename to language/src/test/java/cocos/SubPartNamesInConnectionExistCoCoTest.java index 38913d6b..a662826d 100644 --- a/language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java +++ b/language/src/test/java/cocos/SubPartNamesInConnectionExistCoCoTest.java @@ -7,7 +7,7 @@ import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; -import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInConnectionCoCo; +import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; import de.se_rwth.commons.logging.Finding; import de.se_rwth.commons.logging.Log; import org.junit.jupiter.api.AfterEach; @@ -22,7 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat; -public class UniqueSubPartNamesInConnectionCoCoTest { +public class SubPartNamesInConnectionExistCoCoTest { private static final String MODEL_PATH = "src/test/resources/parser"; @@ -78,24 +78,6 @@ public void testInvalidUndefined() throws IOException { assertThat(errors.get(0).getMsg()).contains("0x10AA3"); } - @Test - public void testInvalidDuplicateName() throws IOException { - String invalidModel = - "part def A { port p; }" - + "part def System {" - + "part a: A;" - + "part a: A;" - + "connect a.p to a.p;" - + "}"; - - var ast = parse(invalidModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(2); - assertThat(errors.get(0).getMsg()).contains("0x10AA3"); - assertThat(errors.get(1).getMsg()).contains("0x10AA3"); - } - @Test public void testInvalidBothUndefined() throws IOException { String invalidModel = @@ -113,24 +95,6 @@ public void testInvalidBothUndefined() throws IOException { assertThat(errors.get(1).getMsg()).contains("0x10AA3"); } - @Test - public void testInvalidUndefinedAndDuplicateName() throws IOException { - String invalidModel = - "part def A { port p; }" - + "part def System {" - + "part duplicate1: A;" - + "part duplicate1: ~A;" - + "connect duplicate1.p to undefined3.p;" - + "}"; - - var ast = parse(invalidModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(2); - assertThat(errors.get(0).getMsg()).contains("0x10AA3"); - assertThat(errors.get(1).getMsg()).contains("0x10AA3"); - } - private ASTSysMLModel parse(String model) throws IOException { var optAst = SysMLv2Mill.parser().parse_String(model); assertThat(optAst).isPresent(); @@ -146,7 +110,7 @@ private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { private List check(ASTSysMLModel ast) { var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); + checker.addCoCo(new SubPartNamesInConnectionExistCoCo()); Log.enableFailQuick(false); checker.checkAll(ast); return Log.getFindings().stream().filter(Finding::isError).collect( diff --git a/language/src/test/java/cocos/UniqueSubPartNamesInParentCoCoTest.java b/language/src/test/java/cocos/UniqueSubPartNamesInParentCoCoTest.java new file mode 100644 index 00000000..3eeaba20 --- /dev/null +++ b/language/src/test/java/cocos/UniqueSubPartNamesInParentCoCoTest.java @@ -0,0 +1,104 @@ +/* (c) https://github.com/MontiCore/monticore */ +package cocos; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; +import de.se_rwth.commons.logging.Finding; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.*; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class UniqueSubPartNamesInParentCoCoTest { + + private static final String MODEL_PATH = "src/test/resources/parser"; + + private SysMLv2Parser parser = SysMLv2Mill.parser(); + + @BeforeAll + public static void init() { + Log.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + Log.clearFindings(); + } + + @Nested + public class UniqueSubPartNamesInConnectionCoCoTests { + @Test + public void testValid() throws IOException { + String validModel = + "part def A { port p: int; }" + + "part def B { port q: ~int; }" + + "part def System {" + + "part a: A;" + + "part b: B;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalidDoubleDefined() throws IOException { + String invalidModel = + "part def A { port p: int; }" + + "part def B { port q: ~int; }" + + "part def System {" + + "part a: A;" + + "part a: B;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(2); + assertThat(errors.get(0).getMsg()).contains("0x10AA7"); + } + + private ASTSysMLModel parse(String model) throws IOException { + var optAst = SysMLv2Mill.parser().parse_String(model); + assertThat(optAst).isPresent(); + return optAst.get(); + } + + private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { + var tool = new SysMLv2Tool(); + var scope = tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + return scope; + } + + private List check(ASTSysMLModel ast) { + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new UniqueSubPartNamesInParentCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} From c590793f061a42e4d945af970eb7702fe3e894b0 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Tue, 10 Feb 2026 14:55:34 +0100 Subject: [PATCH 08/50] 7.8.8: Fix for LanguageServer Listing Errors Multiple Times (Backport) (#53) * Override runCoCosForAllDocuments Generated class "SysMLv2LspCoCoRunnerTOP" was missing the line 38: "di.findings.clear()" which lead to multiple Error listing * version bump to 7.8.8 --- gradle.properties | 2 +- .../language_access/SysMLv2LspCoCoRunner.java | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1966761e..2298e42d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.7 +version = 7.8.8 diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java index 16948795..426438ca 100644 --- a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java @@ -2,6 +2,8 @@ import de.mclsg.lsp.document_management.DocumentManager; import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._lsp.SysMLv2DocumentInformationFilter; +import de.se_rwth.commons.logging.Log; public class SysMLv2LspCoCoRunner extends SysMLv2LspCoCoRunnerTOP { public SysMLv2LspCoCoRunner(DocumentManager documentManager) { @@ -23,5 +25,27 @@ public void runAllCoCos(ASTSysMLModel ast){ } } + @Override + public void runCoCosForAllDocuments(){ + documentManager.getAllDocumentInformation(new SysMLv2DocumentInformationFilter()).forEach(di -> { + Log.enableFailQuick(false); + + if(di.ast != null){ + Log.getFindings().clear(); + try { + runAllCoCos((ASTSysMLModel) di.ast); + } finally { + di.findings.clear(); + di.findings.addAll(Log.getFindings()); + /* + * did-change message from Client triggers runAllCoCos. Each Error + * from those CoCos is logged in Findings and then added to + * DocumentInformation. These are then displayed to the User. + */ + } + } + }); + } + } From d6ccd2c39e5214dbeef4f13e23fda838b3cf1774 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Tue, 10 Feb 2026 16:15:42 +0100 Subject: [PATCH 09/50] 7.8.9: Fix for CoCos Assuming Direction In Connection (Backport) (#54) * check both possible directions SysML v2 'Connection' elements do not inherently specify flow direction * version bump to 7.8.9 * edit ParentComponentInputConnectionDirectionCoCo description * remove unnecessary comments --- gradle.properties | 2 +- ...ComponentInputConnectionDirectionCoCo.java | 37 ++++++++++++--- ...omponentOutputConnectionDirectionCoCo.java | 21 +++++++-- ...onentInputConnectionDirectionCoCoTest.java | 45 +++++++++++++++++++ ...nentOutputConnectionDirectionCoCoTest.java | 30 ++++++++++++- 5 files changed, 121 insertions(+), 14 deletions(-) diff --git a/gradle.properties b/gradle.properties index 2298e42d..272a1e37 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.8 +version = 7.8.9 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java index 49e05c85..a05e694c 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java @@ -18,10 +18,9 @@ import java.util.Optional; /** - * ParentComponentInputConnectionDirectionCoCo - * Inputs von Oberkomponenten können nur zu Inputs von Subkomponenten oder Outputs der Oberkomponenten verbunden werden - * (alternative Formulierung): - * Inputs von Oberkomponenten können nicht zu Outputs von Subkomponenten verbunden werden. + * Checks that Inputs of the parent component can only be connected to: + * 1. Inputs of subcomponents, or + * 2. Outputs of the parent component. */ public class ParentComponentInputConnectionDirectionCoCo implements SysMLPartsASTConnectionUsageCoCo { @@ -56,17 +55,41 @@ public void check(ASTConnectionUsage node) { // Classify ports boolean tgtIsInput = portIsInput(tgtPort); boolean tgtIsOutput = portIsOutput(tgtPort); + boolean srcIsInput = portIsInput(srcPort); + boolean srcIsOutput = portIsOutput(srcPort); // Allowed connections: // 1. Subcomponent with Input ports // 2. Parent component with Output ports - boolean allowed = (tgtIsSub && tgtIsInput) || (!tgtIsSub && tgtIsOutput); + // 3. Connection does not imply flow directions. + // This information must be inferred by port attributes + boolean allowed = true; - if(srcIsSub || !portIsInput(srcPort)){ - // Source is neither input nor ParentComponent + if (!((srcIsInput && !srcIsSub) || (tgtIsInput && !tgtIsSub))) { + // Both Endpoints are not a Parent input // CoCo does not apply return; + } else { + // At least one endpoint is of the Parent component + // Check if the OTHER endpoint satisfies the rule + + // If src is parent input + if (srcIsInput && !srcIsSub) { + allowed = allowed && ( + (tgtIsInput && tgtIsSub) || // tgt is sub input + (tgtIsOutput && !tgtIsSub) // tgt is parent output + ); + } + + // If tgt is parent input + if (tgtIsInput && !tgtIsSub) { + allowed = allowed && ( + (srcIsInput && srcIsSub) || // src is sub input + (srcIsOutput && !srcIsSub) // src is parent output + ); + } } + if( (portIsInOutput(srcPort)) || (portIsInOutput(tgtPort)) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java index 8a3389c3..9832bbaf 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java @@ -15,7 +15,6 @@ import java.util.Optional; /** - * SubcomponentOutputConnectionDirectionCoCo * Checks that outputs of subcomponents can only be connected to: * 1. Inputs of subcomponents, or * 2. Outputs of the parent component. @@ -53,14 +52,28 @@ public void check(ASTConnectionUsage node) { // Classify ports boolean tgtIsInput = portIsInput(tgtPort); boolean tgtIsOutput = portIsOutput(tgtPort); + boolean srcIsInput = portIsInput(srcPort); + boolean srcIsOutput = portIsOutput(srcPort); // Allowed connections: // 1. Subcomponent with Input ports // 2. Parent component with Output ports - boolean allowed = (tgtIsSub && tgtIsInput) || (!tgtIsSub && tgtIsOutput); + // 3. Connection does not imply flow directions. + // This information must be inferred by port attributes + boolean allowed = true; - if(!srcIsSub || !portIsOutput(srcPort)){ - // Source is neither output nor Subcomponent + // Handle src as sub output + if (srcIsOutput && srcIsSub) { + allowed = (tgtIsInput && tgtIsSub) || (tgtIsOutput && !tgtIsSub); + } + + // Handle tgt as sub output (if not already failed) + if (allowed && tgtIsOutput && tgtIsSub) { + allowed = (srcIsInput && srcIsSub) || (srcIsOutput && !srcIsSub); + } + + if(!((srcIsOutput && srcIsSub) || (tgtIsOutput && tgtIsSub))){ + // Both Endpoints are not a Subcomponent output // CoCo does not apply return; } diff --git a/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java b/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java index 4374e2b7..11aedaa9 100644 --- a/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java +++ b/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java @@ -67,6 +67,29 @@ public void testValid() throws IOException { assertThat(errors).hasSize(0); } + @Test + public void testValidSwitchTgtAndSrc() throws IOException { + String validModel = + "port def InPort { in attribute data: int; }" + + "port def OutPort { out attribute data: int; }" + + "part def A { port input: InPort; }" + + "part def B { port output: OutPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "port sysInAnother: InPort;" + + "port sysOut: OutPort;" + + "part a: A;" + + "part b: B;" + + "connect a.input to sysIn;" + + "connect sysOut to sysInAnother;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + @Test public void testValidConjugatedModel() throws IOException { String validModel = @@ -126,6 +149,28 @@ public void testInvalidConjugatedModel() throws IOException { assertThat(errors.get(0).getMsg()).contains("0x10AA6"); } + @Test + public void testInvalidConjugatedModelSwitchTgtAndSrc() throws IOException { + /* (Sub) Output -> (main) Input + * (also caught by SubcomponentOutputConnectionDirectionCoCo, so the + * connection would throw 0x10AA5 and 0x10AA6 in the actual Server) + */ + String invalidModel = + "port def InPort { in attribute data: int; }" + + "part def A { port output: ~InPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "part a: A;" + + "connect a.output to sysIn;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA6"); + } + private ASTSysMLModel parse(String model) throws IOException { var optAst = SysMLv2Mill.parser().parse_String(model); assertThat(optAst).isPresent(); diff --git a/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java b/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java index 18c74360..21d7d903 100644 --- a/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java +++ b/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java @@ -67,6 +67,28 @@ public void testValid() throws IOException { assertThat(errors).hasSize(0); } + @Test + public void testValidSwitchSrcAndTgt() throws IOException { + String validModel = + "port def OutPort { out attribute data: int; }" + + "port def InPort { in attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def B { port input: InPort; }" + + "part def C { port output: OutPort; }" + + "part def System {" + + "port sysOutput: OutPort;" + + "part a: A;" + + "part b: B;" + + "part c: C;" + + "connect b.input to a.output;" // (Sub) Output -> (Sub) Input + + "connect sysOutput to c.output;" // (Sub) Output -> (main) Output + + "}"; + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + @Test public void testValidConjugatedModel() throws IOException { String validModel = @@ -126,7 +148,11 @@ public void testInvalidSubOutToMainInConjugatedModel() throws IOException { } @Test - public void testInvalidSubOutToMainIn() throws IOException { + public void testInvalidSubOutToMainInSwitchSrcAndTgt() throws IOException { + /* (Sub) Output -> (main) Input + * (also caught by ParentComponentInputConnectionDirectionCoCo, so the + * connection would throw 0x10AA5 and 0x10AA6 in the actual Server) + */ String invalidModel = "port def OutPort { out attribute data: int; }" + "port def InPort { in attribute data: int; }" @@ -134,7 +160,7 @@ public void testInvalidSubOutToMainIn() throws IOException { + "part def System {" + "port sysInput: InPort;" + "part a: A;" - + "connect a.output to sysInput;" // (Sub) Output -> (main) Input + + "connect sysInput to a.output;" + "}"; var ast = parse(invalidModel); From 23e9b264617aa7df7f567481f62e1949d4462215 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:40:11 +0100 Subject: [PATCH 10/50] #119 Added RequirementSubject2Variable symbol adapter (#56) * #119 Added RequirementSubject2Variable symbol adapter * #131 smaller refactor, removing duplicate type setter * #131 refactor var names * #115 version bump to 7.8.5 * #131 version bump to 7.8.10 --- gradle.properties | 2 +- ...uirementSubject2VariableSymbolAdapter.java | 76 +++++++++++++++++++ .../sysmlv2/_symboltable/ISysMLv2Scope.java | 9 +++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlconstraints/symboltable/adapters/RequirementSubject2VariableSymbolAdapter.java diff --git a/gradle.properties b/gradle.properties index 272a1e37..3802c6c2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.9 +version = 7.8.10 diff --git a/language/src/main/java/de/monticore/lang/sysmlconstraints/symboltable/adapters/RequirementSubject2VariableSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlconstraints/symboltable/adapters/RequirementSubject2VariableSymbolAdapter.java new file mode 100644 index 00000000..201aa6b0 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlconstraints/symboltable/adapters/RequirementSubject2VariableSymbolAdapter.java @@ -0,0 +1,76 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlconstraints.symboltable.adapters; + +import com.google.common.base.Preconditions; +import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.types.check.SymTypeExpression; +import de.se_rwth.commons.SourcePosition; +import de.se_rwth.commons.logging.Log; + +public class RequirementSubject2VariableSymbolAdapter extends VariableSymbol { + protected RequirementSubjectSymbol adaptee; + + public RequirementSubject2VariableSymbolAdapter(RequirementSubjectSymbol adaptee) { + super(adaptee.getName()); + this.adaptee = adaptee; + } + + protected RequirementSubjectSymbol getAdaptee() { + return adaptee; + } + + @Override + public SymTypeExpression getType() { + var types = this.adaptee.getTypesList(); + if(types.size() != 1) { + Log.trace("Experiencing Subj. with > 1 types", getClass().getName()); + return null; + } + return types.get(0); + } + + @Override + public void setName(String name) { + Preconditions.checkNotNull(name); + Preconditions.checkArgument(!name.isBlank()); + getAdaptee().setName(name); + } + + @Override + public String getName() { + return getAdaptee().getName(); + } + + @Override + public String getFullName() { + return getAdaptee().getFullName(); + } + + @Override + public IBasicSymbolsScope getEnclosingScope() { + return getAdaptee().getEnclosingScope(); + } + + @Override + public SourcePosition getSourcePosition() { + return getAdaptee().getSourcePosition(); + } + + @Override + public RequirementSubject2VariableSymbolAdapter deepClone() { + RequirementSubject2VariableSymbolAdapter clone = new RequirementSubject2VariableSymbolAdapter(this.getAdaptee()); + clone.setAccessModifier(this.getAccessModifier()); + clone.setEnclosingScope(this.getEnclosingScope()); + clone.setFullName(this.getFullName()); + clone.setIsReadOnly(this.isIsReadOnly()); + if (this.isPresentAstNode()) { + clone.setAstNode(this.getAstNode()); + } + if (this.getType() != null) { + clone.setType(this.getType().deepClone()); + } + return clone; + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index e688cbc9..5e841780 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -9,6 +9,8 @@ import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; import de.monticore.lang.sysmlbasis._symboltable.AnonymousUsageSymbol; import de.monticore.lang.sysmlconstraints._ast.ASTRequirementUsage; +import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; +import de.monticore.lang.sysmlconstraints.symboltable.adapters.RequirementSubject2VariableSymbolAdapter; import de.monticore.lang.sysmloccurrences.symboltable.adapters.ItemDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; @@ -68,6 +70,8 @@ default List resolveAdaptedVariableLocallyMany( AccessModifier.ALL_INCLUSION, x -> true); var attributes = resolveAttributeUsageLocallyMany(false, name, AccessModifier.ALL_INCLUSION, x -> true); + var requirementSubjects = resolveRequirementSubjectLocallyMany(false, name, + AccessModifier.ALL_INCLUSION, x -> true); var anonymous = resolveAnonymousUsageLocallyMany(false, name, AccessModifier.ALL_INCLUSION, x -> true); @@ -117,6 +121,11 @@ default List resolveAdaptedVariableLocallyMany( } } + for (RequirementSubjectSymbol reqSub : requirementSubjects) { + var variable = new RequirementSubject2VariableSymbolAdapter(reqSub); + adapted.add(variable); + } + for (AnonymousUsageSymbol anonymousUsage : anonymous) { var types = new ArrayList(); types.addAll(anonymousUsage.getTypesList()); From c7767a1854864d82bc8a0387cd953e915b9066c7 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:49:02 +0100 Subject: [PATCH 11/50] 7.8.11: Added Requirements to CC-Language (#57) * #119 Added RequirementSubject2Variable symbol adapter * #131 Added RequirmentUsage (id per name) to CC, Implemented sysmlv2 to CC Adapter * #131 smaller refactoring for var names * #131 smaller refactor, removing duplicate type setter * #131 refactor var names * #131 removed testcode comments * #115 version bump to 7.8.5 * #131 version bump to 7.8.5 * #131 version bump to 7.8.10 * #131 version bump to 7.8.11 --- .../de/monticore/lang/ComponentConnector.mc4 | 5 +++++ gradle.properties | 2 +- .../sysmlv2/_symboltable/ISysMLv2Scope.java | 18 ++++++++++++++++++ .../Requirement2RequirementCCAdapter.java | 19 +++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java diff --git a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 index 4b7251a3..e0ccf2a1 100644 --- a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 +++ b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 @@ -156,4 +156,9 @@ component grammar ComponentConnector transitions: Transition* ; + /** + * Requirements: Wir berücksichtigen primär die Namen der Requirements + */ + interface symbol Requirement = Name; + } diff --git a/gradle.properties b/gradle.properties index 3802c6c2..41a9b47a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.10 +version = 7.8.11 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 5e841780..3711631a 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -29,9 +29,11 @@ import de.monticore.lang.sysmlv2.symboltable.adapters.AttributeUsage2PortSymbolAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Constraint2SpecificationAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.PartDef2ComponentAdapter; +import de.monticore.lang.sysmlv2.symboltable.adapters.Requirement2RequirementCCAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Requirement2SpecificationAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.StateUsage2AutomatonAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.StateUsage2EventAutomatonAdapter; +import de.monticore.lang.componentconnector._symboltable.RequirementSymbol; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; @@ -51,6 +53,22 @@ public interface ISysMLv2Scope extends ISysMLv2ScopeTOP { + @Override + default List resolveRequirementLocallyMany( + boolean foundSymbols, + String name, AccessModifier modifier, + Predicate predicate) { + var adapted = new ArrayList(); + var req = resolveRequirementUsageLocally(name); + + if(req.isPresent()) { + var ccReq = new Requirement2RequirementCCAdapter(req.get()); + adapted.add(ccReq); + } + + return adapted; + } + /** * Adaptiert AttributeUsages oder PortUsages zu Variablen. *
diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java new file mode 100644 index 00000000..df2f3a43 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java @@ -0,0 +1,19 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.symboltable.adapters; + +import de.monticore.lang.componentconnector._symboltable.RequirementSymbol; +import de.monticore.lang.sysmlconstraints._ast.ASTRequirementUsage; +import de.monticore.lang.sysmlconstraints._symboltable.RequirementUsageSymbol; + +public class Requirement2RequirementCCAdapter extends RequirementSymbol { + private ASTRequirementUsage ccAST; + + public Requirement2RequirementCCAdapter(RequirementUsageSymbol requirementUsageSymbol) { + super(requirementUsageSymbol.getFullName()); + this.ccAST = requirementUsageSymbol.getAstNode(); + } + + public ASTRequirementUsage getCcAST() { + return ccAST; + } +} From 60e528e4cce9831fd0a73337a6bee468de01c37b Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Wed, 11 Feb 2026 16:27:57 +0100 Subject: [PATCH 12/50] 7.8.12: Possibility to configure which CoCos are run --- gradle.properties | 2 +- .../sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 41a9b47a..d82b48cd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.11 +version = 7.8.12 diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java index 426438ca..329ad223 100644 --- a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java @@ -17,7 +17,9 @@ public boolean needsSymbols() { @Override public void runAllCoCos(ASTSysMLModel ast){ - tool.runDefaultCoCos(ast); + if(System.getenv("SYSML_DEFAULT_COCOS") == null) { + tool.runDefaultCoCos(ast); + } // Runs additional (verification-specific) CoCos when variable is set. // Defaults to not running them. if(System.getenv("SYSML_ADDITIONAL_COCOS") != null) { From f78d92258b8ba2cd7fa8e0ace6265e8a11fd2e84 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Fri, 13 Feb 2026 22:05:28 +0100 Subject: [PATCH 13/50] 7.8.13: Added Quickfix for Duplicate Names in Subparts (#59) * implement QuickFix for UniqueSubPartNameCoCo * version bumb to 7.8.13 --- gradle.properties | 2 +- .../SysMLv2CodeActionProvider.java | 1 + .../code_action/UniqueSubPartName.java | 170 ++++++++++++++++++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/UniqueSubPartName.java diff --git a/gradle.properties b/gradle.properties index d82b48cd..9c6432fc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.12 +version = 7.8.13 diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/SysMLv2CodeActionProvider.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/SysMLv2CodeActionProvider.java index 1c33c6e0..ae9be4e8 100644 --- a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/SysMLv2CodeActionProvider.java +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/SysMLv2CodeActionProvider.java @@ -18,6 +18,7 @@ public SysMLv2CodeActionProvider(DocumentManager documentManager, AstPrettyPrinter astSysMLModelAstPrettyPrinter) { super(documentManager, astSysMLModelAstPrettyPrinter); coCoCodeActionProviders.add(new UpperCaseBlockName(documentManager)); + coCoCodeActionProviders.add(new UniqueSubPartName(documentManager)); coCoCodeActionProviders.add(new MissingRefinement(documentManager)); coCoCodeActionProviders.add(new MissingRefiner(documentManager)); } diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/UniqueSubPartName.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/UniqueSubPartName.java new file mode 100644 index 00000000..7a58a183 --- /dev/null +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/UniqueSubPartName.java @@ -0,0 +1,170 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2._lsp.features.code_action; + +import de.mclsg.lsp.document_management.DocumentInformation; +import de.mclsg.lsp.document_management.DocumentManager; +import de.monticore.ast.ASTNode; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; +import de.monticore.symboltable.modifiers.AccessModifier; +import org.eclipse.lsp4j.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +/** + * CodeAction for UniqueSubPartNamesInParentCoCo with ErrorCode 0x10AA7. Suggest + * a new name by appending "A". + */ +public class UniqueSubPartName extends CoCoCodeActionProvider { + + public UniqueSubPartName(DocumentManager documentManager) { + super(documentManager, "0x10AA7"); + } + + @Override + public List createFixesFor(TextDocumentItem document, + Diagnostic diagnostic) { + List res = new ArrayList<>(); + Optional di = documentManager.getDocumentInformation( + document); + + if (di.isEmpty()) { + return res; + } + + ASTNode ast = di.get().ast; + + Range diagnosticRange = diagnostic.getRange(); + int diagnosticLine = diagnosticRange.getStart().getLine(); + int diagnosticColumn = diagnosticRange.getStart().getCharacter(); + + traverse((ISysMLv2Scope) ast.getEnclosingScope(), symbol -> { + if (symbol == null || symbol.getAstNode() == null) { + return; + } + + ASTPartUsage node = symbol.getAstNode(); + + if (!isContainedInPosition(node, diagnosticLine, diagnosticColumn)) { + return; // Skip if this node doesn't contain the diagnostic position + } + + if (triggeredCoCo(node) && node.isPresentName()) { + String currentName = node.getName(); + String newName = suggestedName(currentName); + + CodeAction ca = new CodeAction( + String.format("Change name to '%s'", newName)); + ca.setKind(CodeActionKind.QuickFix); + + TextEdit textEdit = new TextEdit(); + Position pStart = calculateStartPosition(document, node, currentName); + Position pEnd = new Position(pStart.getLine(), + pStart.getCharacter() + currentName.length()); + + textEdit.setRange(new Range(pStart, pEnd)); + textEdit.setNewText(newName); + + ca.setEdit(new WorkspaceEdit(Collections.singletonMap(document.getUri(), + Collections.singletonList(textEdit)))); + res.add(ca); + } + }); + + return res; + } + + // Simply appends "A", can be changed in the future + private String suggestedName(String oldName){ + return oldName + "A"; + } + + private static void traverse(ISysMLv2Scope scope, + Consumer f) { + if (scope != null) { + scope.getPartUsageSymbols().entries().forEach( + entry -> f.accept(entry.getValue())); + scope.getSubScopes().forEach(s -> traverse(s, f)); + } + } + + // Returns true if this node has triggered 0x10AA7 + private boolean triggeredCoCo(ASTPartUsage node) { + var scope = node.getEnclosingScope(); + String partName = node.getName(); + + var allMatches = scope.resolvePartUsageLocallyMany(false, partName, + AccessModifier.ALL_INCLUSION, p -> true); + + return allMatches.size() > 1; + } + + /** + * Finds the exact start position of the part name. + * + * Skips the 'part' keyword and any following whitespaces + * to avoid editing keywords and other syntax elements. + */ + protected Position calculateStartPosition(TextDocumentItem document, + ASTPartUsage partUsage, + String currentName) { + int lineIdx = partUsage.get_SourcePositionStart().getLine() - 1; + int nameIdx = partUsage.get_SourcePositionStart().getColumn() - 1; + + String[] lines = document.getText().split("\\r?\\n"); + if (lineIdx < lines.length) { + String line = lines[lineIdx]; + + int startIdx = Math.max(0, nameIdx); + + int partIdx = line.indexOf("part", startIdx); + if (partIdx != -1) { + startIdx = partIdx + 4; // Skip "part" + + // Skip any whitespace after "part" + while (startIdx < line.length() && Character.isWhitespace(line.charAt(startIdx))) { + startIdx++; + } + } + + nameIdx = line.indexOf(currentName, startIdx); + + } + return new Position(lineIdx, nameIdx); + } + + /** + * Verifies that the diagnostic is pointing at the exact node as the same line + * is not enough. + * Example: "part a : type; part b : type;" + */ + private static boolean isContainedInPosition(ASTPartUsage node, + int diagnosticLine, + int diagnosticColumn) { + + int startLine = node.get_SourcePositionStart().getLine() - 1; + int endLine = node.get_SourcePositionEnd().getLine() - 1; + + boolean containsPosition = false; + if (diagnosticLine >= startLine && diagnosticLine <= endLine) { + if (diagnosticLine == startLine) { + containsPosition = diagnosticColumn >= + node.get_SourcePositionStart().getColumn() - 1; + } + else if (diagnosticLine == endLine) { + containsPosition = diagnosticColumn <= + node.get_SourcePositionEnd().getColumn() - 1; + } + else { + containsPosition = true; + } + } + return containsPosition; + } + +} From dfe9665b96b58401a57dc1e5d66af694d78252d9 Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:35:38 +0200 Subject: [PATCH 14/50] MCStructuralTypes wird im Grammar importiert (#62) --- .../src/main/grammars/de/monticore/lang/SysMLExpressions.mc4 | 1 + .../de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/language/src/main/grammars/de/monticore/lang/SysMLExpressions.mc4 b/language/src/main/grammars/de/monticore/lang/SysMLExpressions.mc4 index 0968db61..91cedf60 100644 --- a/language/src/main/grammars/de/monticore/lang/SysMLExpressions.mc4 +++ b/language/src/main/grammars/de/monticore/lang/SysMLExpressions.mc4 @@ -4,6 +4,7 @@ package de.monticore.lang; component grammar SysMLExpressions extends de.monticore.literals.MCCommonLiterals, // SignedLiteral de.monticore.types.MCBasicTypes, // MCType + de.monticore.types.MCStructuralTypes, de.monticore.expressions.CommonExpressions, // FieldAccessExpression de.monticore.ocl.OCLExpressions, // ExistsExpression de.monticore.ocl.SetExpressions, // UnionExpression diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java index 06827a24..642921ac 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java @@ -9,6 +9,7 @@ import de.monticore.ocl.types3.OCLSymTypeRelations; import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types.mcstructuraltypes.types3.MCStructuralTypesTypeVisitor; import de.monticore.types3.Type4Ast; import de.monticore.types3.TypeCheck3; import de.monticore.types3.streams.StreamSymTypeRelations; @@ -84,6 +85,10 @@ protected static void initTC3Delegate() { typeTraverser.add4MCBasicTypes(forBasicTypes); typeTraverser.add4SysMLExpressions(forBasicTypes); + var forStructuralTypes = new MCStructuralTypesTypeVisitor(); + forStructuralTypes.setType4Ast(type4Ast); + typeTraverser.add4MCStructuralTypes(forStructuralTypes); + // TODO are MCSimpleGenerics required? var forCollectionTypes = new MCCollectionTypesTypeVisitor(); forCollectionTypes.setType4Ast(type4Ast); From eb6e6e0853cdb5e13b7a15e56a6f117189ecb46b Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Tue, 17 Feb 2026 19:03:37 +0100 Subject: [PATCH 15/50] 7.8.14: Allow Relativ ModelPaths and take current Workspace as Default (#63) * Update MCLSG Version to 7.8.1 * version bumb to 7.8.14 --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9c6432fc..c3e21634 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,10 +19,10 @@ sysmlGitlab = https://git.rwth-aachen.de/api/v4/projects/37093/packages/m # Dependencies mc_version = 7.8.0 -mclsg_version = 7.8.0 +mclsg_version = 7.8.1 se_commons_version = 7.8.0 assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.13 +version = 7.8.14 From a993b4920c7763b4095d944ccf4ca557ad9350c9 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Tue, 24 Feb 2026 10:10:36 +0100 Subject: [PATCH 16/50] 7.8.15 Adapting CC-Requirement Adapter to work without sysml-ast reference (#65) * Removed intermediate constraints-ast from cc-ast representations * Version bump to 7.8.15 --- gradle.properties | 2 +- .../adapters/Requirement2RequirementCCAdapter.java | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index c3e21634..183af661 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.14 +version = 7.8.15 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java index df2f3a43..a54e28e5 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java @@ -2,18 +2,12 @@ package de.monticore.lang.sysmlv2.symboltable.adapters; import de.monticore.lang.componentconnector._symboltable.RequirementSymbol; -import de.monticore.lang.sysmlconstraints._ast.ASTRequirementUsage; import de.monticore.lang.sysmlconstraints._symboltable.RequirementUsageSymbol; public class Requirement2RequirementCCAdapter extends RequirementSymbol { - private ASTRequirementUsage ccAST; public Requirement2RequirementCCAdapter(RequirementUsageSymbol requirementUsageSymbol) { super(requirementUsageSymbol.getFullName()); - this.ccAST = requirementUsageSymbol.getAstNode(); } - public ASTRequirementUsage getCcAST() { - return ccAST; - } } From 1c3f2fcbd624e27f6841a2c4c9044384d22c8fd4 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Tue, 24 Feb 2026 12:15:49 +0100 Subject: [PATCH 17/50] 7.8.16: old type check removed, new type check disabled --- build.gradle | 10 +- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 41 +-- .../sysmlv2/cocos/AssignActionTypeCheck.java | 29 -- .../sysmlv2/cocos/ConstraintIsBoolean.java | 45 ---- .../sysmlv2/cocos/SendActionTypeCheck.java | 25 -- .../sysmlv2/cocos/SpecializationExists.java | 26 -- .../cocos/TypeCheckTransitionGuards.java | 43 --- .../test/java/cocos/ConstraintCoCoTest.java | 97 ++++++- .../java/cocos/RequirementSubjectTest.java | 4 +- .../SpecializationExistsCoCoTest.java} | 6 +- .../java/cocos/SpecializationExistsTest.java | 107 -------- .../java/cocos/{spesml => }/SpesMLTest.java | 2 +- .../src/test/java/symboltable/SymTabTest.java | 4 +- ...AccessExpressionInConstraintUsageTest.java | 15 +- ...FieldAccessExpressionInStateUsageTest.java | 203 ++++++++++---- .../src/test/java/typecheck/NegationTest.java | 92 ++++++- .../StreamConstructorExpressionsTest.java | 4 +- .../TC3FieldAccessInteroperabilityTest.java | 4 +- .../TypeCheck4CardinalExpressionsTest.java | 86 ------ ...heck4StreamConstructorExpressionsTest.java | 91 ------- .../test/java/types3/ConstraintCoCoTest.java | 202 -------------- ...FieldAccessExpressionInStateUsageTest.java | 251 ------------------ .../src/test/java/types3/NegationTest.java | 156 ----------- 24 files changed, 354 insertions(+), 1191 deletions(-) delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java rename language/src/test/java/{types3/SpecializationExistsTest.java => cocos/SpecializationExistsCoCoTest.java} (95%) delete mode 100644 language/src/test/java/cocos/SpecializationExistsTest.java rename language/src/test/java/cocos/{spesml => }/SpesMLTest.java (99%) rename language/src/test/java/{types3 => typecheck}/FieldAccessExpressionInConstraintUsageTest.java (91%) rename language/src/test/java/{types3 => typecheck}/StreamConstructorExpressionsTest.java (98%) rename language/src/test/java/{types3 => typecheck}/TC3FieldAccessInteroperabilityTest.java (98%) delete mode 100644 language/src/test/java/typecheck/TypeCheck4CardinalExpressionsTest.java delete mode 100644 language/src/test/java/typecheck/TypeCheck4StreamConstructorExpressionsTest.java delete mode 100644 language/src/test/java/types3/ConstraintCoCoTest.java delete mode 100644 language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java delete mode 100644 language/src/test/java/types3/NegationTest.java diff --git a/build.gradle b/build.gradle index deae1268..cfee3749 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ subprojects { group = 'de.monticore.lang.sysml_v2' // Needs to be after java plugin - sourceCompatibility = "11" + sourceCompatibility = JavaVersion.VERSION_11 project.buildDir = "target" @@ -19,8 +19,12 @@ subprojects { } // Java JDK Warning - if (JavaVersion.current() > sourceCompatibility) { - logger.warn("\u001B[33m Warning: You are currently using JDK Version " + JavaVersion.current() + ". " + "Higher JDK versions may cause compatibility problems. JDK 11 is recommended. \u001B[0m") + if (JavaVersion.current() > sourceCompatibility + && JavaVersion.current() != JavaVersion.VERSION_17) + { + logger.warn("\u001B[33m Warning: You are currently using JDK Version " + + JavaVersion.current() + ". " + "Higher JDK versions may cause " + + "compatibility problems. JDK 11 or 17 is recommended. \u001B[0m") } // Use the same testing framework for all modules diff --git a/gradle.properties b/gradle.properties index 183af661..03e261a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.15 +version = 7.8.16 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 4bd3bc19..2f3bded0 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -4,6 +4,7 @@ import de.monticore.lang.componentconnector.SerializationUtil; import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTActionDefCoCo; import de.monticore.lang.sysmlconstraints._cocos.SysMLConstraintsASTConstraintDefCoCo; +import de.monticore.lang.sysmlconstraints._cocos.SysMLConstraintsASTRequirementDefCoCo; import de.monticore.lang.sysmlimportsandpackages._cocos.SysMLImportsAndPackagesASTSysMLPackageCoCo; import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTAttributeDefCoCo; import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartDefCoCo; @@ -11,7 +12,6 @@ import de.monticore.lang.sysmlparts.coco.PortDefHasOneType; import de.monticore.lang.sysmlparts.coco.PortDefNeedsDirection; import de.monticore.lang.sysmlparts.symboltable.completers.ConvertEnumUsagesToFields; -import de.monticore.lang.sysmlconstraints._cocos.SysMLConstraintsASTRequirementDefCoCo; import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTStateDefCoCo; import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTStateUsageCoCo; import de.monticore.lang.sysmlstates.cocos.NoDoActions; @@ -23,31 +23,24 @@ import de.monticore.lang.sysmlv2._symboltable.ISysMLv2GlobalScope; import de.monticore.lang.sysmlv2._symboltable.SysMLv2Symbols2Json; import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; -import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck; import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck3; -import de.monticore.lang.sysmlv2.cocos.ConstraintIsBoolean; -import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; import de.monticore.lang.sysmlv2.cocos.FlowCheckCoCo; import de.monticore.lang.sysmlv2.cocos.NameCompatible4Isabelle; import de.monticore.lang.sysmlv2.cocos.OneCardinality; +import de.monticore.lang.sysmlv2.cocos.ParentComponentInputConnectionDirectionCoCo; import de.monticore.lang.sysmlv2.cocos.PartBehaviorCoCo; +import de.monticore.lang.sysmlv2.cocos.PartTypeDefinitionExistsCoCo; import de.monticore.lang.sysmlv2.cocos.PortDefinitionExistsCoCo; +import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo; import de.monticore.lang.sysmlv2.cocos.RefinementCyclic; -import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck; +import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck3; -import de.monticore.lang.sysmlv2.cocos.SpecializationExists; -import de.monticore.lang.sysmlv2.cocos.SpecializationExistsTC3; import de.monticore.lang.sysmlv2.cocos.StateSupertypes; -import de.monticore.lang.sysmlv2.cocos.TypeCheckTransitionGuards; -import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; -import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; -import de.monticore.lang.sysmlv2.cocos.PartTypeDefinitionExistsCoCo; -import de.monticore.lang.sysmlv2.cocos.ParentComponentInputConnectionDirectionCoCo; -import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo; -import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; +import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; import de.monticore.lang.sysmlv2.cocos.SubcomponentOutputConnectionDirectionCoCo; +import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; -import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; +import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; import de.monticore.lang.sysmlv2.symboltable.completers.CausalityCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectRefinementCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectionCompleter; @@ -114,18 +107,16 @@ public void prettyPrint(ASTSysMLModel ast, String file) { @Override public void runDefaultCoCos(ASTSysMLModel ast) { var checker = new SysMLv2CoCoChecker(); - checker.addCoCo((SysMLStatesASTStateDefCoCo) new StateSupertypes()); - checker.addCoCo((SysMLStatesASTStateUsageCoCo) new StateSupertypes()); - checker.addCoCo(new TypeCheckTransitionGuards()); - checker.addCoCo(new SendActionTypeCheck()); - checker.addCoCo(new AssignActionTypeCheck()); - // TC3 + // Type Check checker.addCoCo(new SendActionTypeCheck3()); checker.addCoCo(new AssignActionTypeCheck3()); checker.addCoCo(new TypeCheck3TransitionGuards()); - // Check Definitions exist + // Check that Defs exist checker.addCoCo(new PartTypeDefinitionExistsCoCo()); checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); + // Check that Defs are of correct type + checker.addCoCo((SysMLStatesASTStateDefCoCo) new StateSupertypes()); + checker.addCoCo((SysMLStatesASTStateUsageCoCo) new StateSupertypes()); // Connection CoCos checker.addCoCo(new SubPartNamesInConnectionExistCoCo()); checker.addCoCo(new QualifiedPortNameExistsCoCo()); @@ -145,12 +136,6 @@ public void runAdditionalCoCos( de.monticore.lang.sysmlv2._ast.ASTSysMLModel ast) { var checker = new SysMLv2CoCoChecker(); - // general - checker.addCoCo(new ConstraintIsBoolean()); - checker.addCoCo(new ConstraintIsBooleanTC3()); - checker.addCoCo(new SpecializationExists()); - checker.addCoCo(new SpecializationExistsTC3()); - // Not-supported language elements checker.addCoCo(new NoExitActions()); checker.addCoCo((SysMLStatesASTStateDefCoCo) new NoDoActions()); diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java deleted file mode 100644 index 470c7e66..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.lang.sysmlactions._ast.ASTAssignmentActionUsage; -import de.monticore.lang.sysmlactions._ast.ASTSendActionUsage; -import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTAssignmentActionUsageCoCo; -import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTSendActionUsageCoCo; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.types.check.TypeCheck; - -@Deprecated -public class AssignActionTypeCheck implements SysMLActionsASTAssignmentActionUsageCoCo { - - @Override - public void check(ASTAssignmentActionUsage node) { - // Wir gehen davon aus, dass Send-Actions die Kanäle auf Ports nicht als Strom, - // sondern Element-Weise (i.e. Event-basiert) verarbeiten - var deriver = new SysMLDeriver(false); - deriver.init(); - var tc = new TypeCheck(); - - var type = deriver.deriveType(node.getValueExpression()); - if(!type.isPresentResult() || type.getResult().isObscureType()) { - // Error should already be logged? - } - // Vergleich zum Target steht noch aus. - // TODO Target zur Expression erheben (Grammatik ändenr), Checken, dann vergleichen - } - -} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java deleted file mode 100644 index da64dfc0..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java +++ /dev/null @@ -1,45 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.expressions.expressionsbasis._ast.ASTExpression; -import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlconstraints._cocos.SysMLConstraintsASTConstraintUsageCoCo; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.types.check.TypeCheckResult; -import de.se_rwth.commons.SourcePosition; -import de.se_rwth.commons.SourcePositionBuilder; -import de.se_rwth.commons.logging.Log; - -@Deprecated -public class ConstraintIsBoolean implements SysMLConstraintsASTConstraintUsageCoCo { - - @Override public void check(ASTConstraintUsage node) { - // Expression ausgraben - ASTExpression expr = node.getExpression(); - - // TypeCheck (Deriver) initialisieren - var deriver = new SysMLDeriver(true); - - try { - TypeCheckResult type = deriver.deriveType(expr); - if(!type.isPresentResult() || type.getResult().getTypeInfo() == null) { - var start = node.get_SourcePositionStart(); - var end = constraintEnd(start); - Log.error("0x80001 Failed to derive a type!", start, end); - } - else if(!type.getResult().printFullName().equals("boolean")) { - Log.error("0x80002 The expression type is '" + type.getResult().printFullName() + "' but should be boolean!", expr.get_SourcePositionStart(), expr.get_SourcePositionEnd()); - } - } - catch (Exception e) { - var start = node.get_SourcePositionStart(); - var end = constraintEnd(start); - Log.error("0x80003 " + e.getClass().getSimpleName() + " while type checking!", start, end); - } - } - - private SourcePosition constraintEnd(SourcePosition start) { - return new SourcePositionBuilder().setFileName(start.getFileName().get()).setLine(start.getLine()).setColumn( - start.getColumn() + 11).build(); - } -} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java deleted file mode 100644 index 25803f74..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java +++ /dev/null @@ -1,25 +0,0 @@ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.lang.sysmlactions._ast.ASTSendActionUsage; -import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTSendActionUsageCoCo; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; - -@Deprecated -public class SendActionTypeCheck implements SysMLActionsASTSendActionUsageCoCo { - - @Override - public void check(ASTSendActionUsage node) { - // Wir gehen davon aus, dass Send-Actions die Kanäle auf Ports nicht als Strom, - // sondern Element-Weise (i.e. Event-basiert) verarbeiten - var deriver = new SysMLDeriver(false); - deriver.init(); - - var payloadType = deriver.deriveType(node.getPayload()); - if(!payloadType.isPresentResult() || payloadType.getResult().isObscureType()) { - // Error should already be logged? - } - // Vergleich zum Target steht noch aus. - // TODO Target zur Expression erheben (Grammatik ändenr), Checken, dann vergleichen - } - -} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java deleted file mode 100644 index eabc1000..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java +++ /dev/null @@ -1,26 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; -import de.monticore.lang.sysmlbasis._cocos.SysMLBasisASTSpecializationCoCo; -import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; -import de.monticore.lang.sysmlv2.types.SysMLSynthesizer; -import de.se_rwth.commons.logging.Log; - -@Deprecated -public class SpecializationExists implements SysMLBasisASTSpecializationCoCo { - - @Override - public void check(ASTSpecialization node) { - if (node.getEnclosingScope() instanceof ISysMLv2Scope) { - var scope = (ISysMLv2Scope)node.getEnclosingScope(); - // Synthesizers are used to "build" the SymType from ASTs - var synthesizer = new SysMLSynthesizer(); - for(var typeAst : node.getSuperTypesList()) { - // This will throw an 0xA0324 if the type does not exist. - synthesizer.synthesizeType(typeAst); - } - } - } - -} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java deleted file mode 100644 index 15a4f6e5..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.expressions.expressionsbasis._ast.ASTExpression; -import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; -import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTSysMLTransitionCoCo; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.types.check.TypeCheckResult; -import de.se_rwth.commons.logging.Log; - -@Deprecated -public class TypeCheckTransitionGuards implements SysMLStatesASTSysMLTransitionCoCo { - - @Override - public void check(ASTSysMLTransition node) { - if(node.isPresentGuard()) { - // Expression ausgraben - ASTExpression expr = node.getGuard(); - - // TypeCheck (Deriver) initialisieren - var deriver = new SysMLDeriver(false); - - try { - TypeCheckResult type = deriver.deriveType(expr); - if(!type.isPresentResult() || type.getResult().getTypeInfo() == null) { - Log.error("0x80004 Failed to derive a type!", - expr.get_SourcePositionStart(), - expr.get_SourcePositionEnd()); - } - else if(!type.getResult().printFullName().equals("boolean")) { - Log.error("0x80005 The expression type is '" + type.getResult().printFullName() + "' but should be boolean!", - expr.get_SourcePositionStart(), - expr.get_SourcePositionEnd()); - } - } - catch (Exception e) { - Log.error("0x80006 " + e.getClass().getSimpleName() + " while type checking!", - expr.get_SourcePositionStart(), - expr.get_SourcePositionEnd()); - } - } - } - -} diff --git a/language/src/test/java/cocos/ConstraintCoCoTest.java b/language/src/test/java/cocos/ConstraintCoCoTest.java index 09ed9b5a..10873836 100644 --- a/language/src/test/java/cocos/ConstraintCoCoTest.java +++ b/language/src/test/java/cocos/ConstraintCoCoTest.java @@ -1,17 +1,29 @@ /* (c) https://github.com/MontiCore/monticore */ package cocos; +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; -import de.monticore.lang.sysmlv2.cocos.ConstraintIsBoolean; -import de.monticore.ocl.types3.OCLSymTypeRelations; -import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.streams.StreamSymTypeRelations; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -31,13 +43,61 @@ public class ConstraintCoCoTest { @BeforeAll public static void init() { LogStub.init(); - SysMLv2Mill.init(); } @BeforeEach public void reset() { Log.getFindings().clear(); tool = new SysMLv2Tool(); tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); } @ParameterizedTest(name = "{index} - {0} does pass all checks w/o errors") @@ -58,6 +118,18 @@ public class ConstraintCoCoTest { "14_valid.sysml", // StreamConstructor Expression "15_valid.sysml", //Times function for StreamConstructor Expression "16_valid.sysml", //Inftimes and takes function + "17_valid.sysml", // user defined type + "18_valid.sysml", // user defined type channels + + "implicitFieldAccess/2_valid.sysml", // resolve & compare ports + "implicitFieldAccess/4_valid.sysml", // stream snth + "implicitFieldAccess/11_valid.sysml", // stream length + "implicitFieldAccess/14_valid.sysml", // StreamConstructor Expression + "implicitFieldAccess/15_valid.sysml", //Times function for StreamConstructor Expression + "implicitFieldAccess/17_valid.sysml", // user defined type + "implicitFieldAccess/18_valid.sysml", // user defined type channels + "implicitFieldAccess/19_valid.sysml", // interoperability between implicit and explicit + }) public void testValid(String modelName) throws IOException { var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); @@ -70,7 +142,7 @@ public void testValid(String modelName) throws IOException { tool.finalizeSymbolTable(ast); var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBoolean()); + checker.addCoCo(new ConstraintIsBooleanTC3()); checker.checkAll(ast); assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); @@ -94,6 +166,17 @@ public void testValid(String modelName) throws IOException { "14_invalid.sysml", // StreamConstructor Expression "15_invalid.sysml", //Times function for StreamConstructor Expression "16_invalid.sysml", //Inftimes and takes function + "17_invalid.sysml", // user defined type + "18_invalid.sysml", // user defined type channels + + "implicitFieldAccess/2_invalid.sysml", // resolve & compare ports + "implicitFieldAccess/4_invalid.sysml", // stream snth + "implicitFieldAccess/11_invalid.sysml", // stream length + "implicitFieldAccess/14_invalid.sysml", // StreamConstructor Expression + "implicitFieldAccess/15_invalid.sysml", //Times function for StreamConstructor Expression + "implicitFieldAccess/17_invalid.sysml", // user defined type + "implicitFieldAccess/18_invalid.sysml", // user defined type channels + "implicitFieldAccess/19_invalid.sysml", // interoperability between implicit and explicit }) public void testInvalid(String modelName) throws IOException { var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); @@ -106,7 +189,7 @@ public void testInvalid(String modelName) throws IOException { tool.finalizeSymbolTable(ast); var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBoolean()); + checker.addCoCo(new ConstraintIsBooleanTC3()); Log.enableFailQuick(false); checker.checkAll(ast); assertFalse(Log.getFindings().isEmpty()); diff --git a/language/src/test/java/cocos/RequirementSubjectTest.java b/language/src/test/java/cocos/RequirementSubjectTest.java index 1d2b75da..f1c1ca9e 100644 --- a/language/src/test/java/cocos/RequirementSubjectTest.java +++ b/language/src/test/java/cocos/RequirementSubjectTest.java @@ -3,7 +3,7 @@ import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; -import de.monticore.lang.sysmlv2.cocos.ConstraintIsBoolean; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; import de.se_rwth.commons.logging.Finding; import de.se_rwth.commons.logging.Log; import org.junit.jupiter.api.Test; @@ -37,7 +37,7 @@ public void testInvalid() throws IOException { private List check(ASTSysMLModel ast) { var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBoolean()); + checker.addCoCo(new ConstraintIsBooleanTC3()); Log.enableFailQuick(false); checker.checkAll(ast); return Log.getFindings().stream().filter(f -> f.isError()).collect(Collectors.toList()); diff --git a/language/src/test/java/types3/SpecializationExistsTest.java b/language/src/test/java/cocos/SpecializationExistsCoCoTest.java similarity index 95% rename from language/src/test/java/types3/SpecializationExistsTest.java rename to language/src/test/java/cocos/SpecializationExistsCoCoTest.java index ed1ee86f..60fd5a15 100644 --- a/language/src/test/java/types3/SpecializationExistsTest.java +++ b/language/src/test/java/cocos/SpecializationExistsCoCoTest.java @@ -1,15 +1,13 @@ /* (c) https://github.com/MontiCore/monticore */ -package types3; +package cocos; import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; -import de.monticore.lang.sysmlv2.cocos.SpecializationExists; import de.monticore.lang.sysmlv2.cocos.SpecializationExistsTC3; import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; -import de.monticore.types3.TypeCheck3; import de.se_rwth.commons.logging.Finding; import de.se_rwth.commons.logging.Log; import org.junit.jupiter.api.AfterEach; @@ -26,7 +24,7 @@ /** * Prüft das Finden von Types der Specializations */ -public class SpecializationExistsTest { +public class SpecializationExistsCoCoTest { @BeforeAll static void setup() { diff --git a/language/src/test/java/cocos/SpecializationExistsTest.java b/language/src/test/java/cocos/SpecializationExistsTest.java deleted file mode 100644 index 097f0b7b..00000000 --- a/language/src/test/java/cocos/SpecializationExistsTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package cocos; - -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; -import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; -import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; -import de.monticore.lang.sysmlv2.cocos.SpecializationExists; -import de.se_rwth.commons.logging.Finding; -import de.se_rwth.commons.logging.Log; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Prüft das Finden von Types der Specializations - */ -public class SpecializationExistsTest { - - @BeforeAll - static void setup() { - SysMLv2Mill.init(); - } - - @BeforeEach - void clear() { - SysMLv2Mill.globalScope().clear(); - SysMLv2Mill.initializePrimitives(); - SysMLv2Mill.addCollectionTypes(); - Log.clearFindings(); - } - - @Test - public void testMissingDefinition() throws IOException { - var model = "requirement Invalid { subject s: NonExistent; }"; - var ast = parse(model); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMsg()).contains("0xA0324 Cannot find symbol NonExistent"); - } - - @Test - public void testExistingDefinition() throws IOException { - var model = "part def Existent; requirement Valid { subject s: Existent; }"; - var ast = parse(model); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - // Should also work with state defs - @Test - public void testExistingStateDefinition() throws IOException { - var model = "state def Existent; requirement Valid { subject s: Existent; }"; - var ast = parse(model); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - @Test - public void testExistingCollectionType() throws IOException { - var model = "attribute def Existent; part def Valid { attribute e: List; }"; - var ast = parse(model); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - private ASTSysMLModel parse(String model) throws IOException { - var optAst = SysMLv2Mill.parser().parse_String(model); - assertThat(optAst).isPresent(); - return optAst.get(); - } - - private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { - var tool = new SysMLv2Tool(); - var scope = tool.createSymbolTable(ast); - tool.completeSymbolTable(ast); - return scope; - } - - private List check(ASTSysMLModel ast) { - var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new SpecializationExists()); - Log.enableFailQuick(false); - checker.checkAll(ast); - return Log.getFindings().stream().filter(f -> f.isError()).collect(Collectors.toList()); - } - - @AfterEach - void clearLog() { - Log.clearFindings(); - Log.enableFailQuick(true); - } - -} diff --git a/language/src/test/java/cocos/spesml/SpesMLTest.java b/language/src/test/java/cocos/SpesMLTest.java similarity index 99% rename from language/src/test/java/cocos/spesml/SpesMLTest.java rename to language/src/test/java/cocos/SpesMLTest.java index 5af7616d..bcb84938 100644 --- a/language/src/test/java/cocos/spesml/SpesMLTest.java +++ b/language/src/test/java/cocos/SpesMLTest.java @@ -1,5 +1,5 @@ /* (c) https://github.com/MontiCore/monticore */ -package cocos.spesml; +package cocos; import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; diff --git a/language/src/test/java/symboltable/SymTabTest.java b/language/src/test/java/symboltable/SymTabTest.java index 6751b319..823dd564 100644 --- a/language/src/test/java/symboltable/SymTabTest.java +++ b/language/src/test/java/symboltable/SymTabTest.java @@ -6,7 +6,7 @@ import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; -import de.monticore.lang.sysmlv2.cocos.ConstraintIsBoolean; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.Assertions; @@ -45,7 +45,7 @@ public void testStream() throws IOException { Assertions.assertTrue(streamSymOpt.isPresent(), "Stream symbol should be resolvable!"); var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBoolean()); + checker.addCoCo(new ConstraintIsBooleanTC3()); checker.checkAll(ast); tool.runDefaultCoCos(ast); tool.runAdditionalCoCos(ast); diff --git a/language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java b/language/src/test/java/typecheck/FieldAccessExpressionInConstraintUsageTest.java similarity index 91% rename from language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java rename to language/src/test/java/typecheck/FieldAccessExpressionInConstraintUsageTest.java index fa96a73b..d77c27c4 100644 --- a/language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java +++ b/language/src/test/java/typecheck/FieldAccessExpressionInConstraintUsageTest.java @@ -1,4 +1,4 @@ -package types3; +package typecheck; import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; @@ -8,7 +8,6 @@ import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; @@ -23,13 +22,10 @@ import de.monticore.types3.Type4Ast; import de.monticore.types3.TypeCheck3; import de.monticore.types3.streams.StreamSymTypeRelations; -import de.monticore.types3.util.MapBasedTypeCheck3; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -107,10 +103,8 @@ public void reset() { @ParameterizedTest @ValueSource(strings = { "port def F { attribute a: boolean[2]; } part s { port f: F; constraint e { f.a[1] } }", - "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1].a } }", + "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1].a } }" - "port def F { attribute a: boolean[2]; } part s { port f: F; constraint e { f[1] } }", - "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1] } }" }) public void test4ValidExpr1(String model) throws IOException { var ast = parser.parse_String(model); assertThat(ast).isPresent(); @@ -148,9 +142,8 @@ public void test4InvalidExpr(String model) throws IOException { var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); var type = TypeCheck3.typeOf(expr); - assertTrue(type.isObscureType() || - !Log.getFindings().isEmpty() || - !type.printFullName().equals("EventStream.EventStream")); + + assertFalse(type.printFullName().equals("EventStream.EventStream")); } } diff --git a/language/src/test/java/typecheck/FieldAccessExpressionInStateUsageTest.java b/language/src/test/java/typecheck/FieldAccessExpressionInStateUsageTest.java index e9ad4304..91785613 100644 --- a/language/src/test/java/typecheck/FieldAccessExpressionInStateUsageTest.java +++ b/language/src/test/java/typecheck/FieldAccessExpressionInStateUsageTest.java @@ -1,22 +1,36 @@ package typecheck; +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; import de.monticore.lang.sysmlparts._ast.ASTPartDef; -import de.monticore.lang.sysmlparts._ast.ASTPortDef; import de.monticore.lang.sysmlstates._ast.ASTStateUsage; import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -25,18 +39,14 @@ import java.util.stream.Stream; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** - *

This test is about TypeCheck.

+ *

This test is about TypeCheck3 deriving the types of FieldAccessExpressions in StateUsages.

* - *

In this test, the expression is calculated by creating SysMLExpressionsDeriver with a boolean parameter.

- * - *

When ASTFieldAccessExpression and ASTOCLArrayQualification are in StateUsage, this parameter - * is set to false and we test whether they are not calculated as Stream.

- * - *

For comparison, we set this parameter is set to true (This is the same as creating - * SysMLExpressionsDeriver without parameter) for ASTFieldAccessExpression in ConstraintUsage, - * we test whether ASTFieldAccessExpression will still be calculated as Stream.

+ *

When ASTFieldAccessExpression and ASTOCLArrayQualification are in StateUsage + * we test whether they are not calculated as Stream such as in constraints.

*/ public class FieldAccessExpressionInStateUsageTest { @@ -52,38 +62,120 @@ public static void init() { public void reset() { Log.getFindings().clear(); tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); } static Stream createInputs() { return Stream.of( Arguments.of( "port def F { attribute a: boolean; }" + - "part def X { port f: F; state s { transition first S if f.a then S; } }", - false), - Arguments.of( + "part def X { port f: F; state s { transition first S if f.a then S; } }") + ,Arguments.of( "port def F { attribute a: boolean[3]; }" + - "part def X { port f: F; state s { transition first S if f.a[1] then S; } }", - false), - Arguments.of( + "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") + ,Arguments.of( "port def F { attribute a: boolean; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }", - false), - Arguments.of( + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") + ,Arguments.of( "port def F { attribute a: boolean[3]; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }", - false), + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f.a } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F[3]; constraint e { f[1].a } }") + + + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; }" + + "part def X { port f: F; state s { transition first S if f.a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + + "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F; constraint e { f.a } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F[3]; constraint e { f[1].a } }") + ); + } + + static Stream createInvalidInputs() { + return Stream.of( Arguments.of( - "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f.a } }", - true) + "port def F { attribute a: boolean; attribute b: nat; }" + + "part def X { port f: F; state s { transition first S if f then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + + "part def X { port f: F; state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1][1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f } }") ); } @ParameterizedTest @MethodSource({ "createInputs" }) - public void test(String model, boolean isStream) throws IOException { + public void test(String model) throws IOException { var ast = parser.parse_String(model); assertThat(ast).isPresent(); - var deriver = new SysMLDeriver(isStream); var astSysmlmodel = ast.get(); SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); tool.completeSymbolTable(astSysmlmodel); @@ -92,37 +184,46 @@ public void test(String model, boolean isStream) throws IOException { if (astSysmlelement instanceof ASTStateUsage) { var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); var expr = ((ASTSysMLTransition) astTransition).getGuard(); - var type = deriver.deriveType(expr); - assertThat(type.getResult().printFullName()).isEqualTo("boolean"); + var type = TypeCheck3.typeOf(expr); + assertThat(type.printFullName()).isEqualTo("boolean"); } else if (astSysmlelement instanceof ASTConstraintUsage) { var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); - var type = deriver.deriveType(expr); - assertThat(type.getResult().printFullName()).isEqualTo("EventStream.EventStream"); - } else { - // TODO The test is too complex - Assertions.fail("ASTSysMLElement should here be ASTStateUsage or ASTConstraintUsage"); + var type = TypeCheck3.typeOf(expr); + assertThat(type.printFullName()).isEqualTo( + "EventStream.EventStream"); + } + else { + Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); } } - @Test - public void testProblem() throws IOException { - var ast = parser.parse_String("attribute a: boolean;"); + @ParameterizedTest + @MethodSource({ "createInvalidInputs" }) + public void testInvalid(String model) throws IOException { + var ast = parser.parse_String(model); assertThat(ast).isPresent(); var astSysmlmodel = ast.get(); SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); tool.completeSymbolTable(astSysmlmodel); - ASTAttributeUsage attr = (ASTAttributeUsage) astSysmlmodel.getSysMLElementList().get(0); - assertThat(attr.getEnclosingScope().resolveVariable("a").get().getType().printFullName()).isEqualTo("boolean"); - } + var astPartdef = astSysmlmodel.getSysMLElementList().get(1); + var astSysmlelement = ((ASTPartDef) astPartdef).getSysMLElement(1); + SymTypeExpression type = SymTypeExpressionFactory.createObscureType(); - @Test - public void testProblem2() throws IOException { - var ast = parser.parse_String("port def P { attribute a: boolean; }"); - assertThat(ast).isPresent(); - var astSysmlmodel = ast.get(); - SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); - tool.completeSymbolTable(astSysmlmodel); - var attr = (ASTPortDef) astSysmlmodel.getSysMLElementList().get(0); - assertThat(attr.getSpannedScope().resolveVariable("a").get().getType().printFullName()).isEqualTo("boolean"); + Log.enableFailQuick(false); + + if (astSysmlelement instanceof ASTStateUsage) { + var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); + var expr = ((ASTSysMLTransition) astTransition).getGuard(); + type = TypeCheck3.typeOf(expr); + } else if (astSysmlelement instanceof ASTConstraintUsage) { + var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); + type = TypeCheck3.typeOf(expr); + } + else { + Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); + } + + assertTrue(!type.isPrimitive() || !type.asPrimitive().getPrimitiveName().equals("boolean")); + Log.enableFailQuick(true); } } diff --git a/language/src/test/java/typecheck/NegationTest.java b/language/src/test/java/typecheck/NegationTest.java index 1b101de6..6c52f112 100644 --- a/language/src/test/java/typecheck/NegationTest.java +++ b/language/src/test/java/typecheck/NegationTest.java @@ -1,13 +1,29 @@ package typecheck; import de.monticore.expressions.commonexpressions._ast.ASTEqualsExpression; -import de.monticore.expressions.commonexpressions._ast.ASTLogicalNotExpression; +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; import de.monticore.ocl.oclexpressions._ast.ASTForallExpression; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.BeforeAll; @@ -18,6 +34,7 @@ import java.io.IOException; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class NegationTest { @@ -34,6 +51,55 @@ public static void init() { public void reset() { Log.getFindings().clear(); tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); } @ParameterizedTest @@ -54,12 +120,11 @@ public void testNotBooleanStream(String model) throws IOException { var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); - var deriver = new SysMLDeriver(); - var rightType = deriver.deriveType(equalsExpr.getRight()); - var leftType = deriver.deriveType(equalsExpr.getLeft()); - assertTrue(rightType.isPresentResult()); - assertThat(rightType.getResult().printFullName()).isEqualTo("UntimedStream.UntimedStream"); - assertThat(rightType.getResult().equals(leftType.getResult())); + var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); + var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); + assertFalse(rightType.isObscureType()); + assertThat(rightType.printFullName()).isEqualTo("UntimedStream.UntimedStream"); + assertTrue(rightType.deepEquals(leftType)); } @ParameterizedTest @@ -80,11 +145,10 @@ public void testNotBoolean(String model) throws IOException { var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(0); var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); - var deriver = new SysMLDeriver(); - var rightType = deriver.deriveType(equalsExpr.getRight()); - var leftType = deriver.deriveType(equalsExpr.getLeft()); - assertTrue(rightType.isPresentResult()); - assertThat(rightType.getResult().printFullName()).isEqualTo("boolean"); - assertThat(rightType.getResult().equals(leftType.getResult())); + var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); + var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); + assertFalse(rightType.isObscureType()); + assertThat(rightType.printFullName()).isEqualTo("boolean"); + assertTrue(rightType.deepEquals(leftType)); } } diff --git a/language/src/test/java/types3/StreamConstructorExpressionsTest.java b/language/src/test/java/typecheck/StreamConstructorExpressionsTest.java similarity index 98% rename from language/src/test/java/types3/StreamConstructorExpressionsTest.java rename to language/src/test/java/typecheck/StreamConstructorExpressionsTest.java index 276c7697..21812d28 100644 --- a/language/src/test/java/types3/StreamConstructorExpressionsTest.java +++ b/language/src/test/java/typecheck/StreamConstructorExpressionsTest.java @@ -1,4 +1,4 @@ -package types3; +package typecheck; import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; @@ -8,7 +8,6 @@ import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; @@ -25,7 +24,6 @@ import de.monticore.types3.Type4Ast; import de.monticore.types3.TypeCheck3; import de.monticore.types3.streams.StreamSymTypeRelations; -import de.monticore.types3.util.MapBasedTypeCheck3; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.BeforeAll; diff --git a/language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java b/language/src/test/java/typecheck/TC3FieldAccessInteroperabilityTest.java similarity index 98% rename from language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java rename to language/src/test/java/typecheck/TC3FieldAccessInteroperabilityTest.java index bf4b6185..2e57a2f4 100644 --- a/language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java +++ b/language/src/test/java/typecheck/TC3FieldAccessInteroperabilityTest.java @@ -1,4 +1,4 @@ -package types3; +package typecheck; import de.monticore.expressions.commonexpressions._ast.ASTEqualsExpression; import de.monticore.expressions.commonexpressions._ast.ASTFieldAccessExpression; @@ -11,8 +11,6 @@ import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; -import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; -import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; diff --git a/language/src/test/java/typecheck/TypeCheck4CardinalExpressionsTest.java b/language/src/test/java/typecheck/TypeCheck4CardinalExpressionsTest.java deleted file mode 100644 index 58c46888..00000000 --- a/language/src/test/java/typecheck/TypeCheck4CardinalExpressionsTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package typecheck; - -import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlparts._ast.ASTPartUsage; -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.symbols.basicsymbols.BasicSymbolsMill; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import java.io.IOException; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class TypeCheck4CardinalExpressionsTest { - - private final SysMLv2Parser parser = new SysMLv2Parser(); - private final SysMLv2Tool tool = new SysMLv2Tool(); - - @BeforeAll - public static void init() { - LogStub.init(); - } - - @BeforeEach - public void reset() { - Log.getFindings().clear(); - tool.init(); - } - - @ParameterizedTest - @ValueSource(strings = { - "port def F { attribute a: boolean[2]; } part s { port f: F; constraint e { f.a[1] } }", - "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1].a } }" - }) public void test4ValidExpr1(String model) throws IOException { - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(1); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); - var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); - var deriver = new SysMLDeriver(); - var type = deriver.deriveType(expr); - assertTrue(type.isPresentResult()); - assertThat(type.getResult().printFullName()).isEqualTo("EventStream.EventStream"); - } - - @Test - @Disabled - public void test4InvalidExpr() throws IOException { - var model = "port def F { attribute a: boolean; } part s { port f: F[2]; constraint e { f.a } }"; - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(1); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); - var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); - var deriver = new SysMLDeriver(); - var type = deriver.deriveType(expr); - assertTrue(type.getResult().isObscureType()); - assertTrue(!Log.getFindings().isEmpty()); - } -} - - diff --git a/language/src/test/java/typecheck/TypeCheck4StreamConstructorExpressionsTest.java b/language/src/test/java/typecheck/TypeCheck4StreamConstructorExpressionsTest.java deleted file mode 100644 index 450f8bb9..00000000 --- a/language/src/test/java/typecheck/TypeCheck4StreamConstructorExpressionsTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package typecheck; - -import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlparts._ast.ASTPartUsage; -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class TypeCheck4StreamConstructorExpressionsTest { - - private final SysMLv2Parser parser = new SysMLv2Parser(); - private final SysMLv2Tool tool = new SysMLv2Tool(); - - @BeforeAll - public static void setup() { - LogStub.init(); - SysMLv2Mill.init(); - } - - @BeforeEach - public void clear() { - Log.clearFindings(); - tool.init(); - } - - @ParameterizedTest - @ValueSource(strings = { - "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }", - "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }" - }) - public void test4validStream(String model) throws IOException { - var ast = parser.parse_String(model); - - assertThat(ast).isPresent(); - assertThat(Log.getFindings()).isEmpty(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(1); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); - var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); - var deriver = new SysMLDeriver(); - var type = deriver.deriveType(expr); - assertTrue(type.isPresentResult()); - assertThat(type.getResult().printFullName()).isEqualTo("Stream.Stream"); - } - - @ParameterizedTest - @ValueSource(strings = { - "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }", - "port def F { attribute a: boolean; } part s { port f: F; constraint e { >} }" - }) - public void test4invalidStream(String model) throws IOException { - var ast = parser.parse_String(model); - - assertThat(ast).isPresent(); - assertThat(Log.getFindings()).isEmpty(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(1); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); - var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); - var deriver = new SysMLDeriver(); - var type = deriver.deriveType(expr); - assertTrue(type.isPresentResult()); - assertFalse(Log.getFindings().isEmpty()); - assertThat(type.getResult().printFullName()).isEqualTo("Stream.Stream"); - } -} diff --git a/language/src/test/java/types3/ConstraintCoCoTest.java b/language/src/test/java/types3/ConstraintCoCoTest.java deleted file mode 100644 index b033bf3e..00000000 --- a/language/src/test/java/types3/ConstraintCoCoTest.java +++ /dev/null @@ -1,202 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package types3; - -import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; -import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; -import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; -import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; -import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; -import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; -import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; -import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; -import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; -import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; -import de.monticore.ocl.types3.OCLSymTypeRelations; -import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; -import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; -import de.monticore.types3.Type4Ast; -import de.monticore.types3.streams.StreamSymTypeRelations; -import de.monticore.types3.util.MapBasedTypeCheck3; -import de.monticore.types3.util.WithinScopeBasicSymbolsResolver; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class ConstraintCoCoTest { - - private static final String MODEL_PATH = "src/test/resources/cocos/constraints"; - - private SysMLv2Tool tool; - - @BeforeAll public static void init() { - LogStub.init(); - } - - @BeforeEach public void reset() { - Log.getFindings().clear(); - tool = new SysMLv2Tool(); - tool.init(); - - var type4Ast = new Type4Ast(); - var typeTraverser = SysMLv2Mill.inheritanceTraverser(); - - var forBasis = new ExpressionBasisTypeVisitor(); - forBasis.setType4Ast(type4Ast); - typeTraverser.add4ExpressionsBasis(forBasis); - - var forLiterals = new MCCommonLiteralsTypeVisitor(); - forLiterals.setType4Ast(type4Ast); - typeTraverser.add4MCCommonLiterals(forLiterals); - - var forCommon = new SysMLCommonExpressionsTypeVisitor(); - forCommon.setType4Ast(type4Ast); - typeTraverser.add4CommonExpressions(forCommon); - typeTraverser.setCommonExpressionsHandler(forCommon); - typeTraverser.add4SysMLExpressions(forCommon); - typeTraverser.setSysMLExpressionsHandler(forCommon); - - var forOcl = new SysMLOCLExpressionsTypeVisitor(); - forOcl.setType4Ast(type4Ast); - typeTraverser.add4OCLExpressions(forOcl); - typeTraverser.add4SysMLExpressions(forOcl); - - var forStreams = new StreamExpressionsTypeVisitor(); - forStreams.setType4Ast(type4Ast); - typeTraverser.add4StreamExpressions(forStreams); - - var forSets = new SysMLSetExpressionsTypeVisitor(); - forSets.setType4Ast(type4Ast); - typeTraverser.add4SetExpressions(forSets); - - var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); - forBasicTypes.setType4Ast(type4Ast); - typeTraverser.add4MCBasicTypes(forBasicTypes); - typeTraverser.add4SysMLExpressions(forBasicTypes); - - var forCollectionTypes = new MCCollectionTypesTypeVisitor(); - forCollectionTypes.setType4Ast(type4Ast); - typeTraverser.add4MCCollectionTypes(forCollectionTypes); - - StreamSymTypeRelations.init(); - SysMLWithinScopeBasicSymbolResolver.init(); - SysMLTypeVisitorOperatorCalculator.init(); - CommonExpressionsLValueRelations.init(); - MCCollectionSymTypeRelations.init(); - SysMLSymTypeRelations.init(); - - new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); - } - - @ParameterizedTest(name = "{index} - {0} does pass all checks w/o errors") - @ValueSource(strings = { "1_valid.sysml", - // boolean operator with literals - "2_valid.sysml", // resolve & compare ports - "3_valid.sysml", // resolve & compare channels - "4_valid.sysml", // stream snth - "5_valid.sysml", // port::channel-syntax with comparison - //"6_valid.sysml", // port::channel-syntax with literal - "7_valid.sysml", // INF literal - "8_valid.sysml", // forall construct - "9_valid.sysml", // constraint with literal - //"10_valid.sysml", // attribute definition without port - "11_valid.sysml", // stream length - "12_valid.sysml", // constraint with parameter - "13_valid.sysml", // OCL exists expression - "14_valid.sysml", // StreamConstructor Expression - "15_valid.sysml", //Times function for StreamConstructor Expression - "16_valid.sysml", //Inftimes and takes function - "17_valid.sysml", // user defined type - "18_valid.sysml", // user defined type channels - - "implicitFieldAccess/2_valid.sysml", // resolve & compare ports - "implicitFieldAccess/4_valid.sysml", // stream snth - "implicitFieldAccess/11_valid.sysml", // stream length - "implicitFieldAccess/14_valid.sysml", // StreamConstructor Expression - "implicitFieldAccess/15_valid.sysml", //Times function for StreamConstructor Expression - "implicitFieldAccess/17_valid.sysml", // user defined type - "implicitFieldAccess/18_valid.sysml", // user defined type channels - "implicitFieldAccess/19_valid.sysml", // interoperability between implicit and explicit - - }) - public void testValid(String modelName) throws IOException { - var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); - assertThat(optAst).isPresent(); - - ASTSysMLModel ast = optAst.get(); - - tool.createSymbolTable(ast); - tool.completeSymbolTable(ast); - tool.finalizeSymbolTable(ast); - - var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBooleanTC3()); - checker.checkAll(ast); - - assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); - } - - @ParameterizedTest(name = "{index} - {0} does pass all checks w/o errors") - @ValueSource(strings = { "1_invalid.sysml", - // boolean operator with literals - "2_invalid.sysml", // resolve & compare ports - "3_invalid.sysml", // resolve & compare channels - "4_invalid.sysml", // stream snth - "5_invalid.sysml", // port::channel-syntax with comparison - "6_invalid.sysml", // port::channel-syntax with literal - "7_invalid.sysml", // INF literal - "8_invalid.sysml", // forall construct - "9_invalid.sysml", // constraint with literal - //"10_invalid.sysml", // attribute definition without port - "11_invalid.sysml", // stream length - //"12_invalid.sysml", // constraint with parameter - "13_invalid.sysml", // OCL exists expression - "14_invalid.sysml", // StreamConstructor Expression - "15_invalid.sysml", //Times function for StreamConstructor Expression - "16_invalid.sysml", //Inftimes and takes function - "17_invalid.sysml", // user defined type - "18_invalid.sysml", // user defined type channels - - "implicitFieldAccess/2_invalid.sysml", // resolve & compare ports - "implicitFieldAccess/4_invalid.sysml", // stream snth - "implicitFieldAccess/11_invalid.sysml", // stream length - "implicitFieldAccess/14_invalid.sysml", // StreamConstructor Expression - "implicitFieldAccess/15_invalid.sysml", //Times function for StreamConstructor Expression - "implicitFieldAccess/17_invalid.sysml", // user defined type - "implicitFieldAccess/18_invalid.sysml", // user defined type channels - "implicitFieldAccess/19_invalid.sysml", // interoperability between implicit and explicit - }) - public void testInvalid(String modelName) throws IOException { - var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); - assertThat(optAst).isPresent(); - - ASTSysMLModel ast = optAst.get(); - - tool.createSymbolTable(ast); - tool.completeSymbolTable(ast); - tool.finalizeSymbolTable(ast); - - var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBooleanTC3()); - Log.enableFailQuick(false); - checker.checkAll(ast); - assertFalse(Log.getFindings().isEmpty()); - Log.clearFindings(); - Log.enableFailQuick(true); - } -} diff --git a/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java b/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java deleted file mode 100644 index 28f5b240..00000000 --- a/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java +++ /dev/null @@ -1,251 +0,0 @@ -package types3; - -import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; -import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; -import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; -import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; -import de.monticore.lang.sysmlparts._ast.ASTPartDef; -import de.monticore.lang.sysmlparts._ast.ASTPortDef; -import de.monticore.lang.sysmlstates._ast.ASTStateUsage; -import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; -import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; -import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; -import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; -import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; -import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.SymTypeExpressionFactory; -import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; -import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; -import de.monticore.types3.Type4Ast; -import de.monticore.types3.TypeCheck3; -import de.monticore.types3.streams.StreamSymTypeRelations; -import de.monticore.types3.util.MapBasedTypeCheck3; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.io.IOException; -import java.util.stream.Stream; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -/** - *

This test is about TypeCheck3 deriving the types of FieldAccessExpressions in StateUsages.

- * - *

When ASTFieldAccessExpression and ASTOCLArrayQualification are in StateUsage - * we test whether they are not calculated as Stream such as in constraints.

- */ -public class FieldAccessExpressionInStateUsageTest { - - private final SysMLv2Parser parser = new SysMLv2Parser(); - private final SysMLv2Tool tool = new SysMLv2Tool(); - - @BeforeAll - public static void init() { - LogStub.init(); - } - - @BeforeEach - public void reset() { - Log.getFindings().clear(); - tool.init(); - - var type4Ast = new Type4Ast(); - var typeTraverser = SysMLv2Mill.inheritanceTraverser(); - - var forBasis = new ExpressionBasisTypeVisitor(); - forBasis.setType4Ast(type4Ast); - typeTraverser.add4ExpressionsBasis(forBasis); - - var forLiterals = new MCCommonLiteralsTypeVisitor(); - forLiterals.setType4Ast(type4Ast); - typeTraverser.add4MCCommonLiterals(forLiterals); - - var forCommon = new SysMLCommonExpressionsTypeVisitor(); - forCommon.setType4Ast(type4Ast); - typeTraverser.add4CommonExpressions(forCommon); - typeTraverser.setCommonExpressionsHandler(forCommon); - typeTraverser.add4SysMLExpressions(forCommon); - typeTraverser.setSysMLExpressionsHandler(forCommon); - - var forOcl = new SysMLOCLExpressionsTypeVisitor(); - forOcl.setType4Ast(type4Ast); - typeTraverser.add4OCLExpressions(forOcl); - typeTraverser.add4SysMLExpressions(forOcl); - - var forStreams = new StreamExpressionsTypeVisitor(); - forStreams.setType4Ast(type4Ast); - typeTraverser.add4StreamExpressions(forStreams); - - var forSets = new SysMLSetExpressionsTypeVisitor(); - forSets.setType4Ast(type4Ast); - typeTraverser.add4SetExpressions(forSets); - - var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); - forBasicTypes.setType4Ast(type4Ast); - typeTraverser.add4MCBasicTypes(forBasicTypes); - typeTraverser.add4SysMLExpressions(forBasicTypes); - - var forCollectionTypes = new MCCollectionTypesTypeVisitor(); - forCollectionTypes.setType4Ast(type4Ast); - typeTraverser.add4MCCollectionTypes(forCollectionTypes); - - StreamSymTypeRelations.init(); - SysMLWithinScopeBasicSymbolResolver.init(); - SysMLTypeVisitorOperatorCalculator.init(); - CommonExpressionsLValueRelations.init(); - MCCollectionSymTypeRelations.init(); - SysMLSymTypeRelations.init(); - - new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); - } - - static Stream createInputs() { - return Stream.of( - Arguments.of( - "port def F { attribute a: boolean; }" + - "part def X { port f: F; state s { transition first S if f then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; }" + - "part def X { port f: F; state s { transition first S if f[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1][1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f } }") - - - ,Arguments.of( - "port def F { attribute a: boolean; }" + - "part def X { port f: F; state s { transition first S if f.a then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; }" + - "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f.a } }") - ,Arguments.of( - "port def F { attribute a: boolean; } part def X { port f: F[3]; constraint e { f[1].a } }") - - - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; }" + - "part def X { port f: F; state s { transition first S if f.a then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + - "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F; constraint e { f.a } }") - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F[3]; constraint e { f[1].a } }") - ); - } - - static Stream createInvalidInputs() { - return Stream.of( - Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; }" + - "part def X { port f: F; state s { transition first S if f then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + - "part def X { port f: F; state s { transition first S if f[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1][1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F; constraint e { f } }") - // TODO one field access with a stream method - ); - } - - @ParameterizedTest - @MethodSource({ "createInputs" }) - public void test(String model) throws IOException { - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysmlmodel = ast.get(); - SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); - tool.completeSymbolTable(astSysmlmodel); - var astPartdef = astSysmlmodel.getSysMLElementList().get(1); - var astSysmlelement = ((ASTPartDef) astPartdef).getSysMLElement(1); - if (astSysmlelement instanceof ASTStateUsage) { - var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); - var expr = ((ASTSysMLTransition) astTransition).getGuard(); - var type = TypeCheck3.typeOf(expr); - assertThat(type.printFullName()).isEqualTo("boolean"); - } else if (astSysmlelement instanceof ASTConstraintUsage) { - var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); - var type = TypeCheck3.typeOf(expr); - assertThat(type.printFullName()).isEqualTo( - "EventStream.EventStream"); - } - else { - Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); - } - } - - @ParameterizedTest - @MethodSource({ "createInvalidInputs" }) - public void testInvalid(String model) throws IOException { - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysmlmodel = ast.get(); - SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); - tool.completeSymbolTable(astSysmlmodel); - var astPartdef = astSysmlmodel.getSysMLElementList().get(1); - var astSysmlelement = ((ASTPartDef) astPartdef).getSysMLElement(1); - SymTypeExpression type = SymTypeExpressionFactory.createObscureType(); - - Log.enableFailQuick(false); - - if (astSysmlelement instanceof ASTStateUsage) { - var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); - var expr = ((ASTSysMLTransition) astTransition).getGuard(); - type = TypeCheck3.typeOf(expr); - } else if (astSysmlelement instanceof ASTConstraintUsage) { - var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); - type = TypeCheck3.typeOf(expr); - } - else { - Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); - } - - assertTrue(!type.isPrimitive() || !type.asPrimitive().getPrimitiveName().equals("boolean")); - Log.enableFailQuick(true); - } -} diff --git a/language/src/test/java/types3/NegationTest.java b/language/src/test/java/types3/NegationTest.java deleted file mode 100644 index 0e90be87..00000000 --- a/language/src/test/java/types3/NegationTest.java +++ /dev/null @@ -1,156 +0,0 @@ -package types3; - -import de.monticore.expressions.commonexpressions._ast.ASTEqualsExpression; -import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; -import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; -import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; -import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlparts._ast.ASTPartUsage; -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; -import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; -import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; -import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; -import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; -import de.monticore.ocl.oclexpressions._ast.ASTForallExpression; -import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; -import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; -import de.monticore.types3.Type4Ast; -import de.monticore.types3.TypeCheck3; -import de.monticore.types3.streams.StreamSymTypeRelations; -import de.monticore.types3.util.MapBasedTypeCheck3; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import java.io.IOException; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class NegationTest { - - private final SysMLv2Parser parser = new SysMLv2Parser(); - private final SysMLv2Tool tool = new SysMLv2Tool(); - - @BeforeAll - public static void init() { - LogStub.init(); - } - - @BeforeEach - public void reset() { - Log.getFindings().clear(); - tool.init(); - - var type4Ast = new Type4Ast(); - var typeTraverser = SysMLv2Mill.inheritanceTraverser(); - - var forBasis = new ExpressionBasisTypeVisitor(); - forBasis.setType4Ast(type4Ast); - typeTraverser.add4ExpressionsBasis(forBasis); - - var forLiterals = new MCCommonLiteralsTypeVisitor(); - forLiterals.setType4Ast(type4Ast); - typeTraverser.add4MCCommonLiterals(forLiterals); - - var forCommon = new SysMLCommonExpressionsTypeVisitor(); - forCommon.setType4Ast(type4Ast); - typeTraverser.add4CommonExpressions(forCommon); - typeTraverser.setCommonExpressionsHandler(forCommon); - typeTraverser.add4SysMLExpressions(forCommon); - typeTraverser.setSysMLExpressionsHandler(forCommon); - - var forOcl = new SysMLOCLExpressionsTypeVisitor(); - forOcl.setType4Ast(type4Ast); - typeTraverser.add4OCLExpressions(forOcl); - typeTraverser.add4SysMLExpressions(forOcl); - - var forStreams = new StreamExpressionsTypeVisitor(); - forStreams.setType4Ast(type4Ast); - typeTraverser.add4StreamExpressions(forStreams); - - var forSets = new SysMLSetExpressionsTypeVisitor(); - forSets.setType4Ast(type4Ast); - typeTraverser.add4SetExpressions(forSets); - - var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); - forBasicTypes.setType4Ast(type4Ast); - typeTraverser.add4MCBasicTypes(forBasicTypes); - typeTraverser.add4SysMLExpressions(forBasicTypes); - - var forCollectionTypes = new MCCollectionTypesTypeVisitor(); - forCollectionTypes.setType4Ast(type4Ast); - typeTraverser.add4MCCollectionTypes(forCollectionTypes); - - StreamSymTypeRelations.init(); - SysMLWithinScopeBasicSymbolResolver.init(); - SysMLTypeVisitorOperatorCalculator.init(); - CommonExpressionsLValueRelations.init(); - MCCollectionSymTypeRelations.init(); - SysMLSymTypeRelations.init(); - - new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); - } - - @ParameterizedTest - @ValueSource(strings = { - "port def F { in attribute val: boolean; } part s { port f: F; constraint e { forall long t: f.val.nth(t) == !f.val.nth(t) } }" - }) - public void testNotBooleanStream(String model) throws IOException { - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(1); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); - var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); - var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); - var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); - var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); - assertFalse(rightType.isObscureType()); - assertThat(rightType.printFullName()).isEqualTo("UntimedStream.UntimedStream"); - assertTrue(rightType.deepEquals(leftType)); - } - - @ParameterizedTest - @ValueSource(strings = { - "part s { constraint e { forall nat t: true == !false } }" - }) - public void testNotBoolean(String model) throws IOException { - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(0); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(0); - var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); - var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); - var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); - var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); - assertFalse(rightType.isObscureType()); - assertThat(rightType.printFullName()).isEqualTo("boolean"); - assertTrue(rightType.deepEquals(leftType)); - } -} From 30b322a5518c9c8eb3b36a6f21b33c35f22d146b Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Tue, 24 Feb 2026 12:39:17 +0100 Subject: [PATCH 18/50] 7.8.17: COmplete refinements from Specialization too --- gradle.properties | 2 +- .../completers/DirectRefinementCompleter.java | 39 ++++++++++++++++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index 03e261a4..5d394dc6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.16 +version = 7.8.17 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java index 05d23f53..a0ce4819 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java @@ -1,6 +1,7 @@ package de.monticore.lang.sysmlv2.symboltable.completers; import de.monticore.lang.sysmlbasis._ast.ASTSysMLRefinement; +import de.monticore.lang.sysmlbasis._ast.ASTSysMLSpecialization; import de.monticore.lang.sysmlparts._ast.ASTPartDef; import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; import de.monticore.lang.sysmlv2.SysMLv2Mill; @@ -11,27 +12,53 @@ import java.util.ArrayList; import java.util.stream.Collectors; +/** + * Adds specializations and refinements to the list of direct refinements. + * Example: + * "part def Specific specializes Abstract" + * Results in the "Specific"-PartDefSymbol to contain "Abstract" in the list of + * "directRefinements". + */ public class DirectRefinementCompleter implements SysMLPartsVisitor2 { @Override public void visit(ASTPartDef node) { + var syn = new SysMLSynthesizer(); + + node.getSymbol().setDirectRefinementsList( + new ArrayList() + ); + var refinementTypes = node.getSpecializationList().stream() .filter(r -> r instanceof ASTSysMLRefinement) .flatMap(r -> r.getSuperTypesList().stream()).collect(Collectors.toList()); - var syn = new SysMLSynthesizer(); - - var validRefinementExpressions = new ArrayList(); for (var refinementType : refinementTypes) { - // Check existince of refinement before actually synthesizing it to avoid FATAL errors thrown by the synthesizer + // Check existence of refinement before actually synthesizing it to avoid + // FATAL errors thrown by the synthesizer if (refinementType.getDefiningSymbol().isEmpty()) { continue; } var result = syn.synthesizeType(refinementType); if (result.isPresentResult()) { - validRefinementExpressions.add(result.getResult()); + node.getSymbol().addDirectRefinements(result.getResult()); + } + } + + var specializationTypes = node.getSpecializationList().stream() + .filter(r -> r instanceof ASTSysMLSpecialization) + .flatMap(r -> r.getSuperTypesList().stream()).collect(Collectors.toList()); + + for (var specializationType : specializationTypes) { + // Check existence of refinement before actually synthesizing it to avoid + // FATAL errors thrown by the synthesizer + if (specializationType.getDefiningSymbol().isEmpty()) { + continue; + } + var result = syn.synthesizeType(specializationType); + if (result.isPresentResult()) { + node.getSymbol().addDirectRefinements(result.getResult()); } } - node.getSymbol().setDirectRefinementsList(validRefinementExpressions); } } From 128a0108c033abbac44712fd93bc832d6bcc12e4 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Tue, 24 Feb 2026 14:41:01 +0100 Subject: [PATCH 19/50] 7.8.18: Port-CoCos dont behave properly and try to access AST instead of ST --- gradle.properties | 2 +- .../src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5d394dc6..216e6a78 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.17 +version = 7.8.18 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 2f3bded0..c5d98df8 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -120,8 +120,6 @@ public void runDefaultCoCos(ASTSysMLModel ast) { // Connection CoCos checker.addCoCo(new SubPartNamesInConnectionExistCoCo()); checker.addCoCo(new QualifiedPortNameExistsCoCo()); - checker.addCoCo(new SubcomponentOutputConnectionDirectionCoCo()); - checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); // Check ambiguous names checker.addCoCo(new UniqueSubPartNamesInParentCoCo()); From 8cefc64647934c817f0fdf53eaa143e2d37c17f2 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Mon, 2 Mar 2026 17:51:40 +0100 Subject: [PATCH 20/50] =?UTF-8?q?7.8.19:=20TypeVisitor=20f=C3=BCr=20Condit?= =?UTF-8?q?ionAndExpression2q?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../SysMLOCLExpressionsTypeVisitor.java | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 216e6a78..3a60b6d8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.18 +version = 7.8.19 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java index 00571202..bb40eaf3 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java @@ -1,8 +1,16 @@ package de.monticore.lang.sysmlv2.types3; +import de.monticore.lang.sysmlexpressions._ast.ASTConditionalAndExpression2; import de.monticore.lang.sysmlexpressions._ast.ASTExistsExpression; import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; import de.monticore.ocl.oclexpressions.types3.OCLExpressionsTypeVisitor; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.util.TypeVisitorLifting; +import de.se_rwth.commons.logging.Log; public class SysMLOCLExpressionsTypeVisitor extends OCLExpressionsTypeVisitor implements SysMLExpressionsVisitor2 { @@ -10,4 +18,28 @@ public class SysMLOCLExpressionsTypeVisitor extends OCLExpressionsTypeVisitor im public void endVisit(ASTExistsExpression node) { endVisit((de.monticore.ocl.oclexpressions._ast.ASTExistsExpression) node); } + + @Override + public void endVisit(ASTConditionalAndExpression2 expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateAndExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + protected SymTypeExpression calculateAndExpression( + SymTypeExpression left, SymTypeExpression right) { + + if (SymTypeRelations.isCompatible(left, right) + && left.isPrimitive() + && left.asPrimitive().getPrimitiveName().equals("boolean")) { + return SymTypeExpressionFactory.createPrimitive(BasicSymbolsMill.BOOLEAN); + } + return SymTypeExpressionFactory.createObscureType(); + } + } From 54e2767b7485388346fd126cb736e7b35e0380d7 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Fri, 6 Mar 2026 09:37:09 +0100 Subject: [PATCH 21/50] 7.8.20: Fixed Resolving for Relative ModelPaths (#27, upate mclsg_version to 7.8.3) --- gradle.properties | 4 ++-- .../lang/sysmlv2/_lsp/SysMLv2LanguageServer.java | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 3a60b6d8..3c366e3f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,10 +19,10 @@ sysmlGitlab = https://git.rwth-aachen.de/api/v4/projects/37093/packages/m # Dependencies mc_version = 7.8.0 -mclsg_version = 7.8.1 +mclsg_version = 7.8.3 se_commons_version = 7.8.0 assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.19 +version = 7.8.20 diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/SysMLv2LanguageServer.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/SysMLv2LanguageServer.java index 2fedde56..99eedd99 100644 --- a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/SysMLv2LanguageServer.java +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/SysMLv2LanguageServer.java @@ -5,6 +5,7 @@ import de.mclsg.lsp.document_management.DocumentManager; import de.mclsg.lsp.modelpath.multiproject.ProjectLayoutBuilder; import de.monticore.lang.sysmlv2._lsp.language_access.SysMLv2ScopeManager; +import org.eclipse.lsp4j.InitializedParams; import org.eclipse.lsp4j.MessageParams; import org.eclipse.lsp4j.MessageType; import org.slf4j.Logger; @@ -17,6 +18,21 @@ public class SysMLv2LanguageServer extends SysMLv2LanguageServerTOP { private static final Logger logger = LoggerFactory.getLogger(SysMLv2LanguageServer.class); + @Override + public void initialized(InitializedParams params) { + if (options != null) { + // Re-resolve layout with correct workspace path + ProjectLayout newLayout = new ProjectLayoutBuilder() + .projectpath(options.getWorkspacePath()) + .symbolPath(options.getSymbolPaths()) + .resources(options.getModelPaths()) + .build(); + + resetContent(newLayout); + } + super.initialized(params); + } + /** Convenience: Wir modifizieren aktuell eigentlich nur den ModelPath */ public SysMLv2LanguageServer(ProjectLayout layout) { this( From 209cd00a9a018f9a81955afafa62e18f014ceb37 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Fri, 6 Mar 2026 09:37:50 +0100 Subject: [PATCH 22/50] =?UTF-8?q?7.8.21:=20TypeVisitor=20f=C3=BCr=20Condit?= =?UTF-8?q?ionalOrExpression2=20(#70)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../SysMLOCLExpressionsTypeVisitor.java | 17 ++++- .../test/java/typecheck/TypeCheck3Test.java | 66 +++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 3c366e3f..6abf99eb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.20 +version = 7.8.21 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java index bb40eaf3..b5c8247e 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java @@ -1,6 +1,7 @@ package de.monticore.lang.sysmlv2.types3; import de.monticore.lang.sysmlexpressions._ast.ASTConditionalAndExpression2; +import de.monticore.lang.sysmlexpressions._ast.ASTConditionalOrExpression2; import de.monticore.lang.sysmlexpressions._ast.ASTExistsExpression; import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; import de.monticore.ocl.oclexpressions.types3.OCLExpressionsTypeVisitor; @@ -26,12 +27,24 @@ public void endVisit(ASTConditionalAndExpression2 expr) { SymTypeExpression result = TypeVisitorLifting.liftDefault( - this::calculateAndExpression) + this::calculateBooleanBinaryExpression) .apply(left, right); getType4Ast().setTypeOfExpression(expr, result); } - protected SymTypeExpression calculateAndExpression( + @Override + public void endVisit(ASTConditionalOrExpression2 expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateBooleanBinaryExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + protected SymTypeExpression calculateBooleanBinaryExpression( SymTypeExpression left, SymTypeExpression right) { if (SymTypeRelations.isCompatible(left, right) diff --git a/language/src/test/java/typecheck/TypeCheck3Test.java b/language/src/test/java/typecheck/TypeCheck3Test.java index 21d64edc..940847e8 100644 --- a/language/src/test/java/typecheck/TypeCheck3Test.java +++ b/language/src/test/java/typecheck/TypeCheck3Test.java @@ -4,14 +4,17 @@ import de.monticore.expressions.commonexpressions._visitor.CommonExpressionsVisitor2; import de.monticore.expressions.commonexpressions.types3.CommonExpressionsTypeVisitor; import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; import de.monticore.ocl.oclexpressions.types3.OCLExpressionsTypeVisitor; +import de.monticore.types.check.SymTypeExpression; import de.monticore.types.mcbasictypes.types3.MCBasicTypesTypeVisitor; import de.monticore.types3.Type4Ast; import de.monticore.types3.TypeCheck3; import de.monticore.types3.util.MapBasedTypeCheck3; +import de.se_rwth.commons.logging.Log; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -95,4 +98,67 @@ void testTypeCheck3() throws IOException { assertThat(printer.content).isEqualTo("Übersetzung der length-Funktion"); } + @Test + public void testConditionalAnd2Type() throws IOException { + var tool = new SysMLv2Tool(); + Log.getFindings().clear(); + tool.init(); + + var astExp = SysMLv2Mill.parser().parse_String("constraint { true & false }").get(); + tool.createSymbolTable(astExp); + tool.completeSymbolTable(astExp); + + SymTypeExpression type = TypeCheck3.typeOf(((ASTConstraintUsage)astExp.getSysMLElement(0)).getExpression()); + + assertThat(Log.getFindings().isEmpty()).isTrue(); + assertThat(type.isPrimitive()).isTrue(); + assertThat(type.asPrimitive().getPrimitiveName()).isEqualTo("boolean"); + } + + @Test + public void testConditionalAnd2TypeExpressionOnly() throws IOException { + var tool = new SysMLv2Tool(); + Log.getFindings().clear(); + tool.init(); + + var astExp = SysMLv2Mill.parser().parse_StringExpression("true & false").get(); + + SymTypeExpression type = TypeCheck3.typeOf(astExp); + + assertThat(Log.getFindings().isEmpty()).isTrue(); + assertThat(type.isPrimitive()).isTrue(); + assertThat(type.asPrimitive().getPrimitiveName()).isEqualTo("boolean"); + } + + @Test + public void testConditionalOr2Type() throws IOException { + var tool = new SysMLv2Tool(); + Log.getFindings().clear(); + tool.init(); + + var astExp = SysMLv2Mill.parser().parse_String("constraint { true | false }").get(); + tool.createSymbolTable(astExp); + tool.completeSymbolTable(astExp); + + SymTypeExpression type = TypeCheck3.typeOf(((ASTConstraintUsage)astExp.getSysMLElement(0)).getExpression()); + + assertThat(Log.getFindings().isEmpty()).isTrue(); + assertThat(type.isPrimitive()).isTrue(); + assertThat(type.asPrimitive().getPrimitiveName()).isEqualTo("boolean"); + } + + @Test + public void testConditionalOr2TypeExpressionOnly() throws IOException { + var tool = new SysMLv2Tool(); + Log.getFindings().clear(); + tool.init(); + + var astExp = SysMLv2Mill.parser().parse_StringExpression("true | false").get(); + + SymTypeExpression type = TypeCheck3.typeOf(astExp); + + assertThat(Log.getFindings().isEmpty()).isTrue(); + assertThat(type.isPrimitive()).isTrue(); + assertThat(type.asPrimitive().getPrimitiveName()).isEqualTo("boolean"); + } } From f6017732ccbfeed1ecc0ca853dc970b7d7f70386 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Fri, 6 Mar 2026 09:50:59 +0100 Subject: [PATCH 23/50] 7.8.22: CoCo for AcceptAction in Event-Transitions --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 2 + .../cocos/EventTransitionRequiresAccept.java | 38 ++++++ .../EventTransitionRequiresAcceptTest.java | 108 ++++++++++++++++++ 4 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/EventTransitionRequiresAccept.java create mode 100644 language/src/test/java/cocos/EventTransitionRequiresAcceptTest.java diff --git a/gradle.properties b/gradle.properties index 6abf99eb..5af3d3ae 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.21 +version = 7.8.22 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index c5d98df8..1096b91e 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -24,6 +24,7 @@ import de.monticore.lang.sysmlv2._symboltable.SysMLv2Symbols2Json; import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck3; +import de.monticore.lang.sysmlv2.cocos.EventTransitionRequiresAccept; import de.monticore.lang.sysmlv2.cocos.FlowCheckCoCo; import de.monticore.lang.sysmlv2.cocos.NameCompatible4Isabelle; import de.monticore.lang.sysmlv2.cocos.OneCardinality; @@ -167,6 +168,7 @@ public void runAdditionalCoCos( checker.addCoCo(new FlowCheckCoCo()); checker.addCoCo(new PortDefinitionExistsCoCo()); checker.addCoCo(new PartBehaviorCoCo()); + checker.addCoCo(new EventTransitionRequiresAccept()); checker.checkAll(ast); } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/EventTransitionRequiresAccept.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/EventTransitionRequiresAccept.java new file mode 100644 index 00000000..34353602 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/EventTransitionRequiresAccept.java @@ -0,0 +1,38 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.componentconnector._symboltable.EventAutomatonSymbol; +import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; +import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTSysMLTransitionCoCo; +import de.se_rwth.commons.logging.Log; + +/** + * All transitions in an Event-Automaton need AcceptActions + */ +public class EventTransitionRequiresAccept implements + SysMLStatesASTSysMLTransitionCoCo { + + @Override + public void check(ASTSysMLTransition node) { + if (!isInEventAutomaton(node)) return; + + if (!node.isPresentInlineAcceptActionUsage()) { + Log.error("EventAutomaton transition must contain an AcceptAction.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd()); + } + } + + private boolean isInEventAutomaton(ASTSysMLTransition node) { + var scope = node.getEnclosingScope(); + + while (scope != null) { + if (scope.isPresentSpanningSymbol()) { + var sym = scope.getSpanningSymbol(); + if (sym instanceof EventAutomatonSymbol) return true; + } + scope = scope.getEnclosingScope(); + } + return false; + } + +} diff --git a/language/src/test/java/cocos/EventTransitionRequiresAcceptTest.java b/language/src/test/java/cocos/EventTransitionRequiresAcceptTest.java new file mode 100644 index 00000000..84c80924 --- /dev/null +++ b/language/src/test/java/cocos/EventTransitionRequiresAcceptTest.java @@ -0,0 +1,108 @@ +package cocos; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2.cocos.EventTransitionRequiresAccept; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class EventTransitionRequiresAcceptTest { + + @BeforeAll + public static void init() { + LogStub.init(); + } + + @BeforeEach + public void clear() { + Log.clearFindings(); + } + + @Test + void eventAutomaton_withAccept_mustNotLogError() { + parseAndCheck(valid); + var errors = Log.getFindings().stream() + .filter(s -> s.isError()) + .collect(Collectors.toList()); + assertTrue(errors.isEmpty(), + "Expected no errors, but got:\n" + errors); + } + + @Test + void eventAutomaton_withoutAccept_mustLogError() { + parseAndCheck(invalid); + assertFalse(Log.getFindings().isEmpty()); + } + + void parseAndCheck(String model) { + var tool = new SysMLv2Tool(); + tool.init(); + ASTSysMLModel ast = null; + try { + ast = SysMLv2Mill.parser().parse_String(model).get(); + } + catch (Exception e) { + fail("Model was not parsable"); + } + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new EventTransitionRequiresAccept()); + checker.checkAll(ast); + } + + String valid = "part def TestWithAccept {\n" + + " port input: Booleans;\n" + + " port output: ~Booleans;\n" + + "\n" + + " exhibit state behavior {\n" + + " entry;\n" + + " then S;\n" + + "\n" + + " state S;\n" + + "\n" + + " transition\n" + + " first S\n" + + " accept input.val\n" + + " if input.val == true\n" + + " do action {\n" + + " send false to output.val;\n" + + " }\n" + + " then S;\n" + + " }\n" + + "}"; + + String invalid = "part def TestWithoutAccept {\n" + + " port input: Booleans;\n" + + "\n" + + " exhibit state behavior {\n" + + " entry; then S;\n" + + "\n" + + " state S;\n" + + "\n" + + " transition ok\n" + + " first S\n" + + " accept input.val\n" + + " then S;\n" + + "\n" + + " transition bad\n" + + " first S\n" + + " then S;\n" + + " }\n" + + "}"; + +} From e617df166ce9b8e2c67c9a71750f52da559e00c0 Mon Sep 17 00:00:00 2001 From: Jana Nefedova <116279327+JanaNefedova@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:46:01 +0100 Subject: [PATCH 24/50] In/accept dataport (#71) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Übergänge mit „accept … via …“ werden jetzt korrekt erkannt * update version --- gradle.properties | 2 +- .../adapters/StateUsage2AutomatonAdapter.java | 29 +++++++++++++++--- .../StateUsage2EventAutomatonAdapter.java | 15 ++++++---- .../EventAutomatonSymbolAdapterTest.java | 30 +++++++++++++++++++ 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5af3d3ae..7886dac0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.22 +version = 7.8.23 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2AutomatonAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2AutomatonAdapter.java index 874e6eec..8cfd8784 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2AutomatonAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2AutomatonAdapter.java @@ -11,6 +11,7 @@ import de.monticore.lang.sysmlstates._symboltable.StateUsageSymbol; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.se_rwth.commons.logging.Log; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -93,10 +94,30 @@ public List getInitialConfigurationList() { return initialConfiguration; } - private String getTrigger(ASTSysMLTransition transition) { - var trigger = transition.getInlineAcceptActionUsage(); + public static String getAcceptTrigger(ASTSysMLTransition transition) { + if (transition == null || !transition.isPresentInlineAcceptActionUsage()) { + return ""; + } + var accept = transition.getInlineAcceptActionUsage(); + var payload = accept.getPayload(); + if (accept.isPresentReceiver() && payload.isPresentPayloadHandle()) { + return accept.getReceiver().getQName() + "." + payload.getPayloadHandle(); + } + if (payload.isPresentPayloadType() && payload.getPayloadType() instanceof ASTMCQualifiedType) { + return String.join(".", ((ASTMCQualifiedType) payload.getPayloadType()) + .getMCQualifiedName().getPartsList()); + } + return ""; + } - return String.join(".", ((ASTMCQualifiedType)trigger.getPayload() - .getPayloadType()).getMCQualifiedName().getPartsList()); + private String getTrigger(ASTSysMLTransition transition) { + String trigger = getAcceptTrigger(transition); + if (trigger.isEmpty()) { + Log.error( + "0xB0003 Missing or unsupported transition trigger (expected an 'accept' clause).", + transition.get_SourcePositionStart(), + transition.get_SourcePositionEnd()); + } + return trigger; } } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2EventAutomatonAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2EventAutomatonAdapter.java index 3bd4cec4..cbb8c8dc 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2EventAutomatonAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2EventAutomatonAdapter.java @@ -6,9 +6,11 @@ import de.monticore.lang.sysmlactions._ast.ASTSysMLSuccession; import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; +import static de.monticore.lang.sysmlv2.symboltable.adapters.StateUsage2AutomatonAdapter.getAcceptTrigger; import de.monticore.lang.sysmlstates._symboltable.StateUsageSymbol; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.se_rwth.commons.logging.Log; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -115,10 +117,13 @@ public List getInitialConfigurationList() { } private String getTrigger(ASTSysMLTransition transition) { - //TODO nochmal richtig machen - var trigger = transition.getInlineAcceptActionUsage(); - - return String.join(".", - ((ASTMCQualifiedType)trigger.getPayload().getPayloadType()).getMCQualifiedName().getPartsList()); + String trigger = getAcceptTrigger(transition); + if (trigger.isEmpty()) { + Log.error( + "0xB0002 Unsupported or missing transition trigger (expected 'accept ' or 'accept : via ').", + transition.get_SourcePositionStart(), + transition.get_SourcePositionEnd()); + } + return trigger; } } diff --git a/language/src/test/java/symboltable/EventAutomatonSymbolAdapterTest.java b/language/src/test/java/symboltable/EventAutomatonSymbolAdapterTest.java index 92202cb7..74e77603 100644 --- a/language/src/test/java/symboltable/EventAutomatonSymbolAdapterTest.java +++ b/language/src/test/java/symboltable/EventAutomatonSymbolAdapterTest.java @@ -143,4 +143,34 @@ public void testEventTransition() throws IOException { assertThat(output.getPortSymbol().getName()).isEqualTo("o.val"); assertThat(output.getValue()).isInstanceOf(ASTLogicalNotExpression.class); } + + @Test + public void testEventTransition_TypedAcceptViaMapsToPort() throws IOException { + var as = process("port def B {\n" + + " in attribute val: boolean;\n" + + "}\n" + + "\n" + + "part def A {\n" + + " port i: B;\n" + + " port o: ~B;\n" + + "\n" + + " exhibit state aut {\n" + + " state S;\n" + + " transition t\n" + + " first S\n" + + " accept val: boolean via i\n" + + " if true\n" + + " do action { send !i.val to o.val; }\n" + + " then S;\n" + + " }\n" + + "}"); + + var aut = as.resolveEventAutomaton("A").get(); + + var evTransitions = aut.getEventTransitionsList(); + assertThat(evTransitions).isNotEmpty(); + + var trans = evTransitions.get(0); + assertThat(trans.getPortSymbol().getName()).isEqualTo("i.val"); + } } From 74c921f7e0993d06414b84f991cd7898e00c7468 Mon Sep 17 00:00:00 2001 From: Jana Nefedova <116279327+JanaNefedova@users.noreply.github.com> Date: Sun, 8 Mar 2026 00:41:46 +0100 Subject: [PATCH 25/50] Grammatik angepasst, damit 'metadata def delayed' erlaubt wird (#72) * Grammatik angepasst, damit 'metadata def delayed' erlaubt wird * update version --- gradle.properties | 2 +- .../lang/SysMLImportsAndPackages.mc4 | 2 +- .../grammars/de/monticore/lang/SysMLParts.mc4 | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 2 + .../sysmlv2/_symboltable/ISysMLv2Scope.java | 8 +++ .../cocos/ValidCausalityTimingCoCo.java | 24 ++++++++ .../MetadataDef2TypeSymbolAdapter.java | 53 ++++++++++++++++ .../completers/CausalityCompleter.java | 6 +- .../cocos/ValidCausalityTimingCoCoTest.java | 60 +++++++++++++++++++ .../MetadataDefinitionSymbolTest.java | 47 +++++++++++++++ 10 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ValidCausalityTimingCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/MetadataDef2TypeSymbolAdapter.java create mode 100644 language/src/test/java/cocos/ValidCausalityTimingCoCoTest.java create mode 100644 language/src/test/java/symboltable/MetadataDefinitionSymbolTest.java diff --git a/gradle.properties b/gradle.properties index 7886dac0..c5eb4f77 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.23 +version = 7.8.24 diff --git a/language/src/main/grammars/de/monticore/lang/SysMLImportsAndPackages.mc4 b/language/src/main/grammars/de/monticore/lang/SysMLImportsAndPackages.mc4 index 69b2e9fb..2e426e08 100644 --- a/language/src/main/grammars/de/monticore/lang/SysMLImportsAndPackages.mc4 +++ b/language/src/main/grammars/de/monticore/lang/SysMLImportsAndPackages.mc4 @@ -43,7 +43,7 @@ component grammar SysMLImportsAndPackages extends SysMLBasis { * Metadata is additional data that can be used to annotate * the elements of a model. */ - SysMLMetaDataDefinition implements SysMLElement = + symbol scope SysMLMetaDataDefinition implements SysMLType, SysMLElement = Modifier UserDefinedKeyword* "metadata" "def" SysMLIdentifier? Name SysMLCardinality? Specialization* ("{" diff --git a/language/src/main/grammars/de/monticore/lang/SysMLParts.mc4 b/language/src/main/grammars/de/monticore/lang/SysMLParts.mc4 index 19bf0cf9..48f02081 100644 --- a/language/src/main/grammars/de/monticore/lang/SysMLParts.mc4 +++ b/language/src/main/grammars/de/monticore/lang/SysMLParts.mc4 @@ -8,7 +8,7 @@ component grammar SysMLParts extends SysMLBasis { * Defaults to "delayed". */ SysMLCausality implements SysMLElement = - "timing" (["instant"] | ["delayed"]) ";" ; + "timing" timing:Name ";" ; /* * ################################################################## diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 1096b91e..9b9ace6f 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -41,6 +41,7 @@ import de.monticore.lang.sysmlv2.cocos.SubcomponentOutputConnectionDirectionCoCo; import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; +import de.monticore.lang.sysmlv2.cocos.ValidCausalityTimingCoCo; import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; import de.monticore.lang.sysmlv2.symboltable.completers.CausalityCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectRefinementCompleter; @@ -123,6 +124,7 @@ public void runDefaultCoCos(ASTSysMLModel ast) { checker.addCoCo(new QualifiedPortNameExistsCoCo()); // Check ambiguous names checker.addCoCo(new UniqueSubPartNamesInParentCoCo()); + checker.addCoCo(new ValidCausalityTimingCoCo()); checker.checkAll(ast); } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 3711631a..d4a3ac4d 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -11,6 +11,7 @@ import de.monticore.lang.sysmlconstraints._ast.ASTRequirementUsage; import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; import de.monticore.lang.sysmlconstraints.symboltable.adapters.RequirementSubject2VariableSymbolAdapter; +import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLMetaDataDefinitionSymbol; import de.monticore.lang.sysmloccurrences.symboltable.adapters.ItemDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; @@ -28,6 +29,7 @@ import de.monticore.lang.sysmlstates.symboltable.adapters.StateDef2TypeSymbolAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.AttributeUsage2PortSymbolAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Constraint2SpecificationAdapter; +import de.monticore.lang.sysmlv2.symboltable.adapters.MetadataDef2TypeSymbolAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.PartDef2ComponentAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Requirement2RequirementCCAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Requirement2SpecificationAdapter; @@ -251,6 +253,12 @@ default List resolveAdaptedTypeLocallyMany( adapted.add(new ItemDef2TypeSymbolAdapter(itemDef.get())); } + // MetadataDef zu Types + var metadataDef = resolveSysMLMetaDataDefinitionLocally(name); + if (metadataDef.isPresent()) { + adapted.add(new MetadataDef2TypeSymbolAdapter(metadataDef.get())); + } + return adapted; } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ValidCausalityTimingCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ValidCausalityTimingCoCo.java new file mode 100644 index 00000000..18f43fe9 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ValidCausalityTimingCoCo.java @@ -0,0 +1,24 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlparts._ast.ASTSysMLCausality; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTSysMLCausalityCoCo; +import de.se_rwth.commons.logging.Log; + +import java.util.Set; + +public class ValidCausalityTimingCoCo implements SysMLPartsASTSysMLCausalityCoCo { + protected static final Set VALID_TIMINGS = Set.of("instant", "delayed"); + + @Override + public void check(ASTSysMLCausality node) { + if (!VALID_TIMINGS.contains(node.getTiming())) { + Log.error( + "0x10AA8 Illegal timing value '" + node.getTiming() + + "'. Only 'instant' and 'delayed' are allowed.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } +} \ No newline at end of file diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/MetadataDef2TypeSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/MetadataDef2TypeSymbolAdapter.java new file mode 100644 index 00000000..2442fe41 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/MetadataDef2TypeSymbolAdapter.java @@ -0,0 +1,53 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.symboltable.adapters; + +import com.google.common.base.Preconditions; +import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLMetaDataDefinitionSymbol; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; +import de.se_rwth.commons.SourcePosition; + +public class MetadataDef2TypeSymbolAdapter extends TypeSymbol { + protected SysMLMetaDataDefinitionSymbol adaptee; + + public MetadataDef2TypeSymbolAdapter(SysMLMetaDataDefinitionSymbol adaptee) { + super(Preconditions.checkNotNull(adaptee.getName())); + this.adaptee = adaptee; + } + + protected SysMLMetaDataDefinitionSymbol getAdaptee() { + return adaptee; + } + + @Override + public void setName(String name) { + Preconditions.checkNotNull(name); + Preconditions.checkArgument(!name.isBlank()); + getAdaptee().setName(name); + } + + @Override + public String getName() { + return getAdaptee().getName(); + } + + @Override + public String getFullName() { + return getAdaptee().getFullName(); + } + + @Override + public IBasicSymbolsScope getSpannedScope() { + return getAdaptee().getSpannedScope(); + } + + @Override + public IBasicSymbolsScope getEnclosingScope() { + return getAdaptee().getEnclosingScope(); + } + + @Override + public SourcePosition getSourcePosition() { + return getAdaptee().getSourcePosition(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/CausalityCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/CausalityCompleter.java index e32b0043..229e4c36 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/CausalityCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/CausalityCompleter.java @@ -11,6 +11,8 @@ * anhand der besitzenden (umliegenden) PartDefinition. */ public class CausalityCompleter implements SysMLPartsVisitor2 { + protected static final String INSTANT = "instant"; + @Override public void visit(ASTPortUsage node) { if (node.getEnclosingScope().isPresentSpanningSymbol()) { @@ -18,7 +20,9 @@ public void visit(ASTPortUsage node) { if(enclosingSymbol instanceof PartDefSymbol && enclosingSymbol.isPresentAstNode()) { var ast = (ASTPartDef) enclosingSymbol.getAstNode(); node.getSymbol().setStrong( - ast.getSysMLElements(ASTSysMLCausality.class).stream().noneMatch(ASTSysMLCausality::isInstant) + ast.getSysMLElements(ASTSysMLCausality.class).stream() + .map(ASTSysMLCausality::getTiming) + .noneMatch(INSTANT::equals) ); } } diff --git a/language/src/test/java/cocos/ValidCausalityTimingCoCoTest.java b/language/src/test/java/cocos/ValidCausalityTimingCoCoTest.java new file mode 100644 index 00000000..7b049007 --- /dev/null +++ b/language/src/test/java/cocos/ValidCausalityTimingCoCoTest.java @@ -0,0 +1,60 @@ +/* (c) https://github.com/MontiCore/monticore */ +package cocos; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2.cocos.ValidCausalityTimingCoCo; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ValidCausalityTimingCoCoTest { + private final SysMLv2Parser parser = new SysMLv2Parser(); + + @BeforeAll + public static void init() { + LogStub.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + Log.getFindings().clear(); + } + + @Test + void testDelayedTimingAndMetadataNameCanCoexist() throws IOException { + var ast = parser.parse_String("package Demo { metadata def delayed; part def P { timing delayed; } }"); + + assertThat(ast).isPresent(); + assertThat(parser.hasErrors()).isFalse(); + + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ValidCausalityTimingCoCo()); + checker.checkAll(ast.get()); + + assertThat(Log.getFindings()).isEmpty(); + } + + @Test + void testInvalidTimingValueProducesFinding() throws IOException { + var ast = parser.parse_String("part def P { timing asap; }"); + + assertThat(ast).isPresent(); + assertThat(parser.hasErrors()).isFalse(); + + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ValidCausalityTimingCoCo()); + checker.checkAll(ast.get()); + + assertThat(Log.getFindings()).isNotEmpty(); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AA8"); + } +} \ No newline at end of file diff --git a/language/src/test/java/symboltable/MetadataDefinitionSymbolTest.java b/language/src/test/java/symboltable/MetadataDefinitionSymbolTest.java new file mode 100644 index 00000000..55731040 --- /dev/null +++ b/language/src/test/java/symboltable/MetadataDefinitionSymbolTest.java @@ -0,0 +1,47 @@ +/* (c) https://github.com/MontiCore/monticore */ +package symboltable; + +import de.monticore.lang.sysmlimportsandpackages._ast.ASTSysMLMetaDataDefinition; +import de.monticore.lang.sysmlimportsandpackages._ast.ASTSysMLPackage; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MetadataDefinitionSymbolTest { + + private static final String LOG_NAME = MetadataDefinitionSymbolTest.class.getName(); + + @Test + public void testMetadataDefinitionCreatesTypeSymbol() throws Exception { + LogStub.init(); + Log.getFindings().clear(); + + var tool = new SysMLv2Tool(); + tool.init(); + + String model = "package Demo {\n" + + " metadata def delayed;\n" + + " part def P {\n" + + " timing delayed;\n" + + " }\n" + + "}\n"; + + var ast = SysMLv2Mill.parser().parse_String(model); + assertThat(ast).isPresent(); + + var artifactScope = tool.createSymbolTable(ast.get()); + + var pkg = (ASTSysMLPackage) ast.get().getSysMLElement(0); + + var metadataDef = (ASTSysMLMetaDataDefinition) pkg.getSysMLElement(0); + assertThat(metadataDef.getName()).isEqualTo("delayed"); + + assertThat(artifactScope.getSubScopes()).hasSize(1); + assertThat(artifactScope.getSubScopes().get(0).resolveSysMLMetaDataDefinition("delayed")).isPresent(); + assertThat(artifactScope.getSubScopes().get(0).resolveType("delayed")).isPresent(); + } +} From ed060ecdab3b000a9505b09ba93a57815ca04ab2 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Sun, 8 Mar 2026 22:48:39 +0100 Subject: [PATCH 26/50] 7.8.25: Implemented MildComponentSymbol.isHistoryBased() --- gradle.properties | 2 +- .../adapters/PartDef2ComponentAdapter.java | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index c5eb4f77..a178dd01 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.24 +version = 7.8.25 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/PartDef2ComponentAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/PartDef2ComponentAdapter.java index c6333124..97a5c6d1 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/PartDef2ComponentAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/PartDef2ComponentAdapter.java @@ -144,6 +144,23 @@ public List getConnectorsList() { } } + @Override + public boolean isHistoryBased() { + if(!getSpannedScope().getLocalMildSpecificationSymbols().isEmpty()) { + return true; + } + // TODO only "require" + else if(!getSpannedScope().getLocalRequirementUsageSymbols().isEmpty()) { + return true; + } + // TODO only "assert" + else if(!getSpannedScope().getLocalConstraintUsageSymbols().isEmpty()) { + return true; + } + else { + return false; + } + } /** * Since we might not know the name of the constraint or requirement, and thus From 0e5ed612f7be0b32726a36380de155c5942af0ab Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Thu, 12 Mar 2026 13:43:29 +0200 Subject: [PATCH 27/50] =?UTF-8?q?7.8.26:=20TypesCompleter=20f=C3=BCr=20MCT?= =?UTF-8?q?uples=20(#73)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SymTypeExpression fuer MCTupleType * type.hasTypeInfo() check * Version erhoeht --- gradle.properties | 2 +- .../symboltable/completers/TypesCompleter.java | 13 ++++++++++++- .../SysMLv2DeriveSymTypeOfCommonExpressions.java | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index a178dd01..631a7c8b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.25 +version = 7.8.26 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index 0c1f1baa..8b9247a5 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -25,6 +25,7 @@ import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionFactory; import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; +import de.monticore.types.mcstructuraltypes._ast.ASTMCTupleType; import de.se_rwth.commons.logging.Log; import java.util.ArrayList; @@ -47,7 +48,17 @@ private List getTypeCompletion(List specia for(var mcType: astTyping.getSuperTypesList()) { SymTypeExpression res = null; - if(mcType instanceof ASTMCGenericType) { + if(mcType instanceof ASTMCTupleType) { + var tupleType = (ASTMCTupleType) mcType; + List componentTypes = new ArrayList<>(); + for(var componentMcType : tupleType.getMCTypeList()) { + componentTypes.add(SymTypeExpressionFactory.createTypeExpression( + componentMcType.printType(), + (IBasicSymbolsScope) componentMcType.getEnclosingScope())); + } + res = SymTypeExpressionFactory.createTuple(componentTypes); + } + else if(mcType instanceof ASTMCGenericType) { // We still have to print when the type is generic because the defining symbol does not give info about the // instantiation with type arguments res = SymTypeExpressionFactory.createTypeExpression( diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java index 2cbd75bb..cbacad46 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java @@ -69,7 +69,7 @@ public boolean isIntegralType(SymTypeExpression type) { protected void calculateFieldAccessAboutPortUsage(SymTypeExpression type) { if (this.isStream) { //case for isStream == true - if (type.getTypeInfo().getName().contains("Stream")) { + if (type.hasTypeInfo() && type.getTypeInfo().getName().contains("Stream")) { //type is already Stream, set TypeCheckResult getTypeCheckResult().setResult(type); } else { From 0a0150266d67fc73ff7f150e36f68bf12946f18e Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Mon, 16 Mar 2026 13:43:45 +0200 Subject: [PATCH 28/50] #201 tsyn Flag von dem Part Def ablesen (#74) * #201 tsyn Flag von dem Part Def ablesen * #201 Check if present AST node * #201 PartDefSymbol Type check --- .../adapters/AttributeUsage2PortSymbolAdapter.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java index 4350c499..d0efcb49 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java @@ -1,6 +1,7 @@ package de.monticore.lang.sysmlv2.symboltable.adapters; import de.monticore.lang.componentconnector._symboltable.MildPortSymbol; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; @@ -75,7 +76,11 @@ private Timing determineTiming(PortUsageSymbol container) { var scope = (ISysMLv2Scope) container.getEnclosingScope(); boolean hasTsyn = scope.getLocalStateUsageSymbols().stream() - .anyMatch(sym -> sym.getUserDefinedKeywordsList().contains("tsyn")); + .anyMatch(sym -> sym.getUserDefinedKeywordsList().contains("tsyn")) + || scope.getSpanningSymbol() instanceof PartDefSymbol && scope.getSpanningSymbol().isPresentAstNode() && + ((ASTPartDef) scope.getSpanningSymbol().getAstNode()) + .getUserDefinedKeywordList().stream() + .anyMatch(kw -> kw.getMCQualifiedName().getQName().equals("tsyn")); return hasTsyn ? Timing.TIMED_SYNC : Timing.TIMED; } From b8db2b1a24edbd91b557c5d60a0eecb3fba16340 Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Tue, 17 Mar 2026 14:18:07 +0200 Subject: [PATCH 29/50] Version erhoeht (#76) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 631a7c8b..fa0e56fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.26 +version = 7.8.27 From 74293c8fdb8fbe7c9a910cd9be500f82f422ae76 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 18 Mar 2026 20:48:27 +0100 Subject: [PATCH 30/50] 7.8.28: Extending CC-Requirement (#79) * Extending CC-Requirement * Version bump to 7.8.28 --- .../de/monticore/lang/ComponentConnector.mc4 | 13 ++++- .../_symboltable/RequirementSymbolDeSer.java | 33 +++++++++++++ gradle.properties | 2 +- .../Requirement2RequirementCCAdapter.java | 49 +++++++++++++++++++ 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java diff --git a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 index e0ccf2a1..55af991a 100644 --- a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 +++ b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 @@ -159,6 +159,17 @@ component grammar ComponentConnector /** * Requirements: Wir berücksichtigen primär die Namen der Requirements */ - interface symbol Requirement = Name; + interface symbol Requirement = + name:Name + [isStateInvariant:"invariant"]? + subject:MildComponent + assumptions:Expression* + guarantee:Expression + ; + + symbolrule Requirement = + assumptions:Expression* + guarantee:Expression + ; } diff --git a/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java b/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java new file mode 100644 index 00000000..d85afdc8 --- /dev/null +++ b/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java @@ -0,0 +1,33 @@ +package de.monticore.lang.componentconnector._symboltable; + +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.symboltable.serialization.json.JsonObject; + +import java.util.List; + +public class RequirementSymbolDeSer extends RequirementSymbolDeSerTOP { + + @Override + protected void serializeAssumptions(List assumptions, + ComponentConnectorSymbols2Json s2j) { + // not implemented + } + + @Override + protected void serializeGuarantee(ASTExpression guarantee, + ComponentConnectorSymbols2Json s2j) { + // not implemented + } + + @Override + protected List deserializeAssumptions(JsonObject symbolJson) { + // not implemented + return List.of(); + } + + @Override + protected ASTExpression deserializeGuarantee(JsonObject symbolJson) { + // not implemented + return null; + } +} diff --git a/gradle.properties b/gradle.properties index fa0e56fe..9726f10e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.27 +version = 7.8.28 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java index a54e28e5..fa08a7a6 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java @@ -1,13 +1,62 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.lang.sysmlv2.symboltable.adapters; +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.lang.componentconnector._symboltable.MildComponentSymbol; import de.monticore.lang.componentconnector._symboltable.RequirementSymbol; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlconstraints._ast.ASTRequirementSubject; import de.monticore.lang.sysmlconstraints._symboltable.RequirementUsageSymbol; +import de.monticore.lang.sysmlv2._symboltable.SysMLv2Scope; + +import java.util.List; public class Requirement2RequirementCCAdapter extends RequirementSymbol { + private RequirementUsageSymbol adaptee; + public Requirement2RequirementCCAdapter(RequirementUsageSymbol requirementUsageSymbol) { super(requirementUsageSymbol.getFullName()); + this.adaptee = requirementUsageSymbol; } + public MildComponentSymbol getSubject() { + var subject = this.adaptee.getAstNode().getSysMLElementList() + .stream() + .filter(e -> e instanceof ASTRequirementSubject) + .map(e -> (ASTRequirementSubject) e) + .map(s -> s.getSymbol()) + .findFirst().orElse(null); + + if(subject.getTypesList().size() != 1) { + return null; + } + + var subjectTypeName = subject.getTypes(0).printFullName(); + return ((SysMLv2Scope) this.adaptee.getEnclosingScope()) + .resolveMildComponent(subjectTypeName) + .orElse(null); + } + + @Override + public List getAssumptionsList() { + return this.adaptee.getAstNode().getSysMLElementList() + .stream() + .filter(e -> e instanceof ASTConstraintUsage) + .map(e -> (ASTConstraintUsage) e) + .filter(usage -> usage.isAssume()) + .map(ASTConstraintUsage::getExpression) + .collect(java.util.stream.Collectors.toList()); + } + + @Override + public ASTExpression getGuarantee() { + return this.adaptee.getAstNode().getSysMLElementList() + .stream() + .filter(e -> e instanceof ASTConstraintUsage) + .map(e -> (ASTConstraintUsage) e) + .filter(usage -> usage.isAssert()) + .map(ASTConstraintUsage::getExpression) + .findFirst().orElse(null); + } } From 2dea29818fc99a154ede606a4ddb6ae65d799c3b Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Sun, 22 Mar 2026 12:13:30 +0100 Subject: [PATCH 31/50] 7.8.29: Added new option for co co checker (#81) * update generator * version bumb to 7.8.29 --- gradle.properties | 4 ++-- .../_lsp/language_access/SysMLv2LspCoCoRunner.java | 12 ------------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9726f10e..c87a5880 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,10 +19,10 @@ sysmlGitlab = https://git.rwth-aachen.de/api/v4/projects/37093/packages/m # Dependencies mc_version = 7.8.0 -mclsg_version = 7.8.3 +mclsg_version = 7.8.5 se_commons_version = 7.8.0 assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.28 +version = 7.8.29 diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java index 329ad223..833c407d 100644 --- a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java @@ -15,18 +15,6 @@ public boolean needsSymbols() { return true; } - @Override - public void runAllCoCos(ASTSysMLModel ast){ - if(System.getenv("SYSML_DEFAULT_COCOS") == null) { - tool.runDefaultCoCos(ast); - } - // Runs additional (verification-specific) CoCos when variable is set. - // Defaults to not running them. - if(System.getenv("SYSML_ADDITIONAL_COCOS") != null) { - tool.runAdditionalCoCos(ast); - } - } - @Override public void runCoCosForAllDocuments(){ documentManager.getAllDocumentInformation(new SysMLv2DocumentInformationFilter()).forEach(di -> { From 592b664068789c756904eae61288e542fa4bd61a Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 25 Mar 2026 14:45:52 +0100 Subject: [PATCH 32/50] 7.8.30 Extending PortUsageSymbol by hasCardinality flag (#84) * #190 Extending PortUsageSymbol by hasCardinality flag, using flag in var-resolving * Version bump to 7.8.30 --- gradle.properties | 2 +- .../lang/sysmlparts/_symboltable/PortUsageSymbol.java | 10 ++++++++++ .../symboltable/completers/SysMLPartsCompleter.java | 11 +++++++++++ .../java/de/monticore/lang/sysmlv2/SysMLv2Tool.java | 2 ++ .../lang/sysmlv2/_symboltable/ISysMLv2Scope.java | 2 +- 5 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/SysMLPartsCompleter.java diff --git a/gradle.properties b/gradle.properties index c87a5880..2ab0ba49 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.29 +version = 7.8.30 diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/_symboltable/PortUsageSymbol.java b/language/src/main/java/de/monticore/lang/sysmlparts/_symboltable/PortUsageSymbol.java index 790097b7..909a2465 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/_symboltable/PortUsageSymbol.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/_symboltable/PortUsageSymbol.java @@ -10,6 +10,8 @@ public class PortUsageSymbol extends PortUsageSymbolTOP { + private boolean hasCardinality; + public PortUsageSymbol(String name) { super(name); } @@ -112,6 +114,14 @@ public List getOutputAttributes() { return res; } + public boolean hasCardinality() { + return this.hasCardinality; + } + + public void setHasCardinality(boolean hasCardinality) { + this.hasCardinality = hasCardinality; + } + /** * @return true if the given ports have the same type and access modifier */ diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/SysMLPartsCompleter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/SysMLPartsCompleter.java new file mode 100644 index 00000000..013cfcb9 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/SysMLPartsCompleter.java @@ -0,0 +1,11 @@ +package de.monticore.lang.sysmlparts.symboltable.completers; + +import de.monticore.lang.sysmlparts._ast.ASTPortUsage; +import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; + +public class SysMLPartsCompleter implements SysMLPartsVisitor2 { + + public void visit(ASTPortUsage node) { + node.getSymbol().setHasCardinality(node.getCardinality().isPresent()); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 9b9ace6f..9572b29f 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -12,6 +12,7 @@ import de.monticore.lang.sysmlparts.coco.PortDefHasOneType; import de.monticore.lang.sysmlparts.coco.PortDefNeedsDirection; import de.monticore.lang.sysmlparts.symboltable.completers.ConvertEnumUsagesToFields; +import de.monticore.lang.sysmlparts.symboltable.completers.SysMLPartsCompleter; import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTStateDefCoCo; import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTStateUsageCoCo; import de.monticore.lang.sysmlstates.cocos.NoDoActions; @@ -205,6 +206,7 @@ public void completeSymbolTable(ASTSysMLModel node) { traverser.add4SysMLBasis(new DirectionCompleter()); traverser.add4SysMLParts(new DirectionCompleter()); traverser.add4SysMLParts(new ConvertEnumUsagesToFields()); + traverser.add4SysMLParts(new SysMLPartsCompleter()); traverser.add4SysMLParts(new IdentifierCompletion()); // Visiting artifact scope _and_ the AST requires two calls diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index d4a3ac4d..855c509e 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -107,7 +107,7 @@ default List resolveAdaptedVariableLocallyMany( // we omit to set the ASTNode var variable = new PortUsage2VariableSymbolAdapter(portUsage); - if (portUsage.getAstNode().getCardinality().isPresent()) { + if (portUsage.hasCardinality()) { variable.setType(SymTypeExpressionFactory.createTypeArray(resolved, 1, SymTypeExpressionFactory.createTypeObject(resolved))); } From ec725b77c6bee61edc32243a0ecd7b633d586607 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:34:23 +0200 Subject: [PATCH 33/50] 7.8.31 Extending CC-Requirement-Symbol by invariant and subject fields (#86) * #156 Extending CC-RequirementSymbol by invariant and subject fields * Version bump to 7.8.31 --- .../de/monticore/lang/ComponentConnector.mc4 | 2 ++ .../_symboltable/RequirementSymbolDeSer.java | 12 ++++++++++++ gradle.properties | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 index 55af991a..13d85ddd 100644 --- a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 +++ b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 @@ -168,6 +168,8 @@ component grammar ComponentConnector ; symbolrule Requirement = + stateInvariant: boolean + subject:MildComponentSymbol assumptions:Expression* guarantee:Expression ; diff --git a/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java b/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java index d85afdc8..bda64393 100644 --- a/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java +++ b/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java @@ -7,6 +7,12 @@ public class RequirementSymbolDeSer extends RequirementSymbolDeSerTOP { + @Override + protected void serializeSubject(MildComponentSymbol subject, + ComponentConnectorSymbols2Json s2j) { + // not implemented + } + @Override protected void serializeAssumptions(List assumptions, ComponentConnectorSymbols2Json s2j) { @@ -19,6 +25,12 @@ protected void serializeGuarantee(ASTExpression guarantee, // not implemented } + @Override + protected MildComponentSymbol deserializeSubject(JsonObject symbolJson) { + // not implemented + return null; + } + @Override protected List deserializeAssumptions(JsonObject symbolJson) { // not implemented diff --git a/gradle.properties b/gradle.properties index 2ab0ba49..f94cb124 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.30 +version = 7.8.31 From bd5827e9e39bf33ab4c3d1f09f056d0d9b1cb2a9 Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Thu, 2 Apr 2026 08:14:11 +0300 Subject: [PATCH 34/50] 7.8.32 Eps als Variable statt als Typ definiert (#88) * Eps als Variable statt als Typ definiert * Fixed function call * Removed tsyn type test * #214 Version erhoeht --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Mill.java | 17 ++++--- .../test/java/symboltable/TsynTypeTest.java | 50 ------------------- 3 files changed, 11 insertions(+), 58 deletions(-) delete mode 100644 language/src/test/java/symboltable/TsynTypeTest.java diff --git a/gradle.properties b/gradle.properties index f94cb124..aa4e27a5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.31 +version = 7.8.32 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java index d9dc1f6b..42c13525 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java @@ -32,7 +32,7 @@ public static void prepareGlobalScope() { SysMLv2Mill.initializePrimitives(); SysMLv2Mill.addStringType(); SysMLv2Mill.addCollectionTypes(); - SysMLv2Mill.addTsynTypes(); + SysMLv2Mill.addTsynVariables(); } /** @@ -172,17 +172,20 @@ protected void _addCollectionTypes() { } } - public static void addTsynTypes() { - getMill()._addTsynTypes(); + public static void addTsynVariables() { + getMill()._addTsynVariables(); } - protected void _addTsynTypes() { - if (SysMLv2Mill.globalScope().resolveType("Eps").isEmpty()) { - var eps = typeSymbolBuilder() + protected void _addTsynVariables() { + if (SysMLv2Mill.globalScope().resolveVariable("Eps").isEmpty()) { + var eps = variableSymbolBuilder() .setName("Eps") .setEnclosingScope(globalScope()) .setFullName("Eps") - .setSpannedScope(scope()) + // createTopType wird verwendet, da TopType ein übergeordneter Typ + // aller anderen Typen ist. Dadurch schlägt TypeCheck3TransitionGuards + // nicht bei Guards wie 'if input.val == Eps' fehl + .setType(SymTypeExpressionFactory.createTopType()) .setAccessModifier(AccessModifier.ALL_INCLUSION) .build(); SysMLv2Mill.globalScope().add(eps); diff --git a/language/src/test/java/symboltable/TsynTypeTest.java b/language/src/test/java/symboltable/TsynTypeTest.java deleted file mode 100644 index 6b7eed4e..00000000 --- a/language/src/test/java/symboltable/TsynTypeTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package symboltable; - -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class TsynTypeTest { - - @BeforeAll - static void setup() { - SysMLv2Mill.init(); - } - - @BeforeEach - public void init() { - LogStub.init(); - SysMLv2Mill.globalScope().clear(); - SysMLv2Mill.initializePrimitives(); - SysMLv2Mill.addCollectionTypes(); - SysMLv2Mill.addTsynTypes(); - Log.clearFindings(); - } - - @Test - public void testEpsInModel() throws IOException { - var tool = new SysMLv2Tool(); - - var model = "part def Valid { attribute e: Eps; }"; - var optAst = SysMLv2Mill.parser().parse_String(model); - - assertThat(optAst).isPresent(); - ASTSysMLModel ast = optAst.get(); - - tool.createSymbolTable(ast); - tool.completeSymbolTable(ast); - - assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); - } - -} From 96061524c980fe65fb46a8f5680d3d85b3877bd7 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Fri, 3 Apr 2026 14:58:18 +0200 Subject: [PATCH 35/50] removing TC3 CoCos (#90) --- .../src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 9572b29f..8957d344 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -110,10 +110,7 @@ public void prettyPrint(ASTSysMLModel ast, String file) { @Override public void runDefaultCoCos(ASTSysMLModel ast) { var checker = new SysMLv2CoCoChecker(); - // Type Check - checker.addCoCo(new SendActionTypeCheck3()); - checker.addCoCo(new AssignActionTypeCheck3()); - checker.addCoCo(new TypeCheck3TransitionGuards()); + // Check that Defs exist checker.addCoCo(new PartTypeDefinitionExistsCoCo()); checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); From 36cfc5e87c9cd920b9f7ae0f67cabb266265b388 Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Wed, 8 Apr 2026 13:27:04 +0300 Subject: [PATCH 36/50] =?UTF-8?q?Typ-Ableitung=20f=C3=BCr=20SysMLSequenceE?= =?UTF-8?q?xpression=20(Tupel)=20(#92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../types3/SysMLCommonExpressionsTypeVisitor.java | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index aa4e27a5..1fbd6d30 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.32 +version = 7.8.33 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java index f7071ddf..d2711f10 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java @@ -21,6 +21,7 @@ import de.monticore.lang.sysmlexpressions._ast.ASTSupersetExpression; import de.monticore.lang.sysmlexpressions._ast.ASTSysMLFieldAccessExpression; import de.monticore.lang.sysmlexpressions._ast.ASTSysMLInstantiation; +import de.monticore.lang.sysmlexpressions._ast.ASTSysMLSequenceExpression; import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsHandler; import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsTraverser; import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; @@ -323,4 +324,13 @@ public void endVisit(ASTSysMLInstantiation expr) { getType4Ast().setTypeOfExpression(expr, getType4Ast().getPartialTypeOfTypeId( expr.getMCType())); } + + @Override + public void endVisit(ASTSysMLSequenceExpression expr) { + var elementTypes = expr.getExpressionList().stream() + .map(e -> getType4Ast().getPartialTypeOfExpr(e)) + .collect(java.util.stream.Collectors.toList()); + + getType4Ast().setTypeOfExpression(expr, SymTypeExpressionFactory.createTuple(elementTypes)); + } } From 3c12c20f9bb03e97d83c8ce4f52b65a94708b8ab Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Thu, 16 Apr 2026 12:08:57 +0200 Subject: [PATCH 37/50] 7.8.34: Make Packages First-class Citizens in Scope Delegation (#97) * pass on Context when searching in EnclosingScope * Documentation * version bumb to 7.8.34 * add Notice to Documentation * Documentation and Formatting --- gradle.properties | 2 +- .../sysmlv2/_symboltable/ISysMLv2Scope.java | 82 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1fbd6d30..e9c0e8ff 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.33 +version = 7.8.34 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 855c509e..328a6565 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -12,6 +12,7 @@ import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; import de.monticore.lang.sysmlconstraints.symboltable.adapters.RequirementSubject2VariableSymbolAdapter; import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLMetaDataDefinitionSymbol; +import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLPackageSymbol; import de.monticore.lang.sysmloccurrences.symboltable.adapters.ItemDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; @@ -55,6 +56,87 @@ public interface ISysMLv2Scope extends ISysMLv2ScopeTOP { + /** + * In SysML, namespaces live inside SysML models (keyword "package") and + * there can be multiple namespaces in a single model. This is sometimes + * referred to as "first class support" of namespaces. In Java-like + * programming languages, the namespace of an artifact is handled implicitly + * through the file system path (in conjunction with a package declaration + * for easier inside-out-resolving). Blocks, methods, or classes are not + * considered full namespaces (resolving "bar" from within a class "Foo" + * does not yield the potential qualified name "Foo.bar" at the global scope). + * MontiCore's default resolve-mechanism is built to behave Java-like, i.e., + * it assumes that namespaces exist only at the file level and only package + * declarations matter for the calculation of potential names. Therefore, the + * logic of looking for all potential qualified names is only executed when + * leaving the artifact scope and does not account for any scope names passed + * on the way up. + *
+ * This override changes this. It explicitly adds one new potential name to + * the list of potential names every time a package is passed while continuing + * with the enclosing scope. Assume we look for "bar", we pass "package Foo", + * then the list of potential names we are resolving for is now + * ["bar", "Foo.bar"]. + *
+ * Notice: SysML comes with a large number of keywords + * (e.g., occurrence, item, attribute, part) that have no or very little + * meaning wrt. to symbol resolution. In MontiCore, we already established the + * basic set of symbols (aptly named "BasicSymbols"), namely Types, Variables, + * and Functions. To avoid re-implementing resolving functionality for all + * keywords, we use symbol adapters from SysML definitions to MontiCore types, + * SysML usages to MontiCore variables, and SysML constraints (including + * calc defs) to MontiCore functions. This method here handles resolving of + * MontiCore types, i.e., SysML definitions. + */ + @Override + default List continueTypeWithEnclosingScope( + boolean foundSymbols, + String name, + AccessModifier modifier, + Predicate predicate + ) { + final LinkedHashSet result = new LinkedHashSet<>(); + if ( + checkIfContinueWithEnclosingScope(foundSymbols) + && getEnclosingScope() != null + ) { + + Set potentialNames = calcQNamesForEnclosingScope(name); + + for (String potentialName : potentialNames) { + result.addAll(getEnclosingScope().resolveTypeMany( foundSymbols, + potentialName, + modifier, + predicate) + ); + } + } + + return new ArrayList<>(result); + } + + /** + * This method is essentially copied from artifact scopes. See explanation + * on continueTypeWithEnclosingScope(4): MontiCore's symbol resolution is + * Java-like out-of-the-box and needs to be extended for SysMLv2's usage + * of packages (namespaces) as proper modeling elements. + */ + default Set calcQNamesForEnclosingScope(String name) { + Set potentialSymbolNames = new LinkedHashSet<>(); + potentialSymbolNames.add(name); + + if ( + this.isPresentSpanningSymbol() + && this.getSpanningSymbol() instanceof SysMLPackageSymbol + ) { + potentialSymbolNames.add(this.getSpanningSymbol().getName() + "." + name); + } + + // import statements are not yet considered + + return potentialSymbolNames; + } + @Override default List resolveRequirementLocallyMany( boolean foundSymbols, From 84ba9e7fd27b079ff776275115b3a2db9d38a80c Mon Sep 17 00:00:00 2001 From: Jana Nefedova <116279327+JanaNefedova@users.noreply.github.com> Date: Thu, 16 Apr 2026 12:12:09 +0200 Subject: [PATCH 38/50] =?UTF-8?q?Refinement-Targets=20korrekt=20aufl=C3=B6?= =?UTF-8?q?sen=20(#95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit version update pr polishing Support #refinement dependency syntax in part definitions --- gradle.properties | 2 +- .../grammars/de/monticore/lang/SysMLBasis.mc4 | 2 +- .../lang/sysmlbasis/_ast/ASTDependency.java | 10 ++++++ .../lang/sysmlparts/_ast/ASTPartDef.java | 25 +++++++++++++-- .../lang/sysmlv2/cocos/RefinementCyclic.java | 18 +++++++---- .../cocos/RefinementInterfaceNotMatching.java | 16 ++++------ .../RefinementTargetDefinitionExistsCoCo.java | 19 +++++++---- .../completers/DirectRefinementCompleter.java | 26 ++++++--------- .../test/java/astrules/ASTPartDefTest.java | 20 ++++++++++++ ...inementTargetDefinitionExistsCoCoTest.java | 32 ++++++++++++++----- 10 files changed, 119 insertions(+), 51 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlbasis/_ast/ASTDependency.java diff --git a/gradle.properties b/gradle.properties index e9c0e8ff..63d27708 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.34 +version = 7.8.35 diff --git a/language/src/main/grammars/de/monticore/lang/SysMLBasis.mc4 b/language/src/main/grammars/de/monticore/lang/SysMLBasis.mc4 index b6a7538b..fc9c1016 100644 --- a/language/src/main/grammars/de/monticore/lang/SysMLBasis.mc4 +++ b/language/src/main/grammars/de/monticore/lang/SysMLBasis.mc4 @@ -284,7 +284,7 @@ component grammar SysMLBasis interface IInlineOccurrenceUsage ; Dependency implements SysMLElement = - Modifier UserDefinedKeyword* "dependency" (Name? "from")? (MCQualifiedName || ",")+ "to" (MCQualifiedName || ",")+ + Modifier UserDefinedKeyword* "dependency" (Name? "from")? sources:(MCQualifiedName || ",")* "to" targets:(MCQualifiedName || ",")+ ("{" SysMLElement* "}" | ";"); diff --git a/language/src/main/java/de/monticore/lang/sysmlbasis/_ast/ASTDependency.java b/language/src/main/java/de/monticore/lang/sysmlbasis/_ast/ASTDependency.java new file mode 100644 index 00000000..c708c5f6 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlbasis/_ast/ASTDependency.java @@ -0,0 +1,10 @@ +package de.monticore.lang.sysmlbasis._ast; + +public class ASTDependency extends ASTDependencyTOP { + + public boolean isRefinementDependency() { + return getUserDefinedKeywordList().stream() + .map(keyword -> keyword.getMCQualifiedName().toString()) + .anyMatch("refinement"::equals); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/_ast/ASTPartDef.java b/language/src/main/java/de/monticore/lang/sysmlparts/_ast/ASTPartDef.java index 838246d7..b896943d 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/_ast/ASTPartDef.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/_ast/ASTPartDef.java @@ -1,5 +1,6 @@ package de.monticore.lang.sysmlparts._ast; +import de.monticore.lang.sysmlbasis._ast.ASTDependency; import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; import de.monticore.lang.sysmlbasis._ast.ASTSysMLElement; import de.monticore.lang.sysmlbasis._ast.ASTSysMLRefinement; @@ -30,9 +31,19 @@ public List getSysMLElements(Class type) { .collect(Collectors.toList()); } + public List getRefinementDependencies() { + return getSysMLElements(ASTDependency.class).stream() + .filter(ASTDependency::isRefinementDependency) + .filter(dependency -> dependency.isEmptySources() + || dependency.getSourcesList().stream() + .map(Object::toString) + .anyMatch(this.getName()::equals)) + .collect(Collectors.toList()); + } + /** - * Löst die als Specialization verpackten Refinement-Relationen auf. Ist dabei nicht transitiv, sondern rein AST- - * orientiert: Wenn etwas nicht explizit im AST steht, wird es auch nicht zurückgegeben. + * Löst Refinement-Relationen auf. Ist dabei nicht transitiv, sondern rein AST-orientiert: Wenn etwas nicht explizit + * im AST steht, wird es auch nicht zurückgegeben. */ public List getRefinements() { List refinements = new ArrayList<>(); @@ -50,6 +61,16 @@ public List getRefinements() { } } } + + for (ASTDependency dependency : getRefinementDependencies()) { + dependency.getTargetsList().stream() + .map(Object::toString) + .map(name -> this.getEnclosingScope().resolvePartDef(name)) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(refinements::add); + } + return refinements; } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementCyclic.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementCyclic.java index 39b78152..4e90088f 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementCyclic.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementCyclic.java @@ -23,15 +23,19 @@ public void check(ASTPartDef node) { var refiners = node.getSymbol().getTransitiveRefiners(); var refinements = node.getSymbol().getTransitiveRefinements(); - var cyclicRefinements = refiners.stream().filter(refinements::contains).map(SysMLTypeSymbol::getName).collect(Collectors.toList()); - var pos = node.getSpecializationList().stream() - .filter(s -> s instanceof ASTSysMLRefinement) - .map(ASTNode::get_SourcePositionStart) - .findFirst() - .orElse(node.get_SourcePositionStart()); + var cyclicRefinements = refiners.stream().filter(refinements::contains) + .map(SysMLTypeSymbol::getName) + .collect(Collectors.toList()); + var pos = node.get_SourcePositionStart(); if (cyclicRefinements.size() > 0) { - Log.error("0x90030 Cyclic refinement detected: " + node.getName() + " <-> " + String.join(", ", cyclicRefinements), pos); + Log.error( + "0x90030 Cyclic refinement detected: " + + node.getName() + + " <-> " + + String.join(", ", cyclicRefinements), + pos + ); } if (node.getRefinements().contains(node.getSymbol())) { diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementInterfaceNotMatching.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementInterfaceNotMatching.java index 95e194c5..264ae735 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementInterfaceNotMatching.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementInterfaceNotMatching.java @@ -1,7 +1,5 @@ package de.monticore.lang.sysmlv2.cocos; -import de.monticore.ast.ASTNode; -import de.monticore.lang.sysmlbasis._ast.ASTSysMLRefinement; import de.monticore.lang.sysmlparts._ast.ASTPartDef; import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartDefCoCo; import de.se_rwth.commons.logging.Log; @@ -25,14 +23,14 @@ public void check(ASTPartDef node) { .collect(Collectors.toList()); if (notMatching.size() > 0) { - var pos = node.getSpecializationList().stream() - .filter(s -> s instanceof ASTSysMLRefinement) - .map(ASTNode::get_SourcePositionStart) - .findFirst() - .orElse(node.get_SourcePositionStart()); - for (var refinement : notMatching) { - Log.error("0x9004 Interface of refinement " + refinement.getName() + " is incompatible.", pos); + Log.error( + "0x9004 Interface of refinement " + + refinement.getName() + + " is incompatible.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); } } } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java index 3b7338d3..6210b972 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java @@ -9,9 +9,10 @@ import de.se_rwth.commons.logging.Log; import java.util.stream.Collectors; +import java.util.stream.Stream; /** - * CoCo2: Jeder im "part def X refines Name" verwendete Name muss eine existierende Part-Definition sein. + * CoCo2: Jeder in einer Refinement-Relation verwendete Name muss eine existierende Part-Definition sein. */ public class RefinementTargetDefinitionExistsCoCo implements SysMLPartsASTPartDefCoCo { @@ -21,17 +22,23 @@ protected String printPartType(ASTMCType type) { @Override public void check(ASTPartDef node) { - var nonExistent = node.streamSpecializations() + var nonExistentSpecializations = node.streamSpecializations() .filter(s -> s instanceof ASTSysMLRefinement) .flatMap(ASTSpecialization::streamSuperTypes) - .filter(t -> - node.getEnclosingScope().resolvePartDef(printPartType(t)).isEmpty() - ) + .map((ASTMCType t) -> t.printType()) + .filter(name -> node.getEnclosingScope().resolvePartDef(name).isEmpty()); + + var nonExistentDependencies = node.getRefinementDependencies().stream() + .flatMap(dep -> dep.getTargetsList().stream()) + .map(Object::toString) + .filter(name -> node.getEnclosingScope().resolvePartDef(name).isEmpty()); + + var nonExistent = Stream.concat(nonExistentSpecializations, nonExistentDependencies) .collect(Collectors.toList()); for (var problem : nonExistent) { Log.error( - "0x10AA2 The name used in 'refines' \"" + printPartType(problem) + "0x10AA2 The name used in 'refines' \"" + problem + "\" does not exist as a part definition.", node.get_SourcePositionStart(), node.get_SourcePositionEnd() diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java index a0ce4819..b971fcd6 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java @@ -7,7 +7,7 @@ import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.types.SysMLSynthesizer; import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.TypeCheckResult; +import de.monticore.types.check.SymTypeExpressionFactory; import java.util.ArrayList; import java.util.stream.Collectors; @@ -29,25 +29,17 @@ public void visit(ASTPartDef node) { new ArrayList() ); - var refinementTypes = node.getSpecializationList().stream() - .filter(r -> r instanceof ASTSysMLRefinement) - .flatMap(r -> r.getSuperTypesList().stream()).collect(Collectors.toList()); - - for (var refinementType : refinementTypes) { - // Check existence of refinement before actually synthesizing it to avoid - // FATAL errors thrown by the synthesizer - if (refinementType.getDefiningSymbol().isEmpty()) { - continue; - } - var result = syn.synthesizeType(refinementType); - if (result.isPresentResult()) { - node.getSymbol().addDirectRefinements(result.getResult()); - } - } + node.getRefinements().stream() + .map(refinement -> SymTypeExpressionFactory.createTypeObject( + refinement.getFullName(), + node.getEnclosingScope() + )) + .forEach(node.getSymbol()::addDirectRefinements); var specializationTypes = node.getSpecializationList().stream() .filter(r -> r instanceof ASTSysMLSpecialization) - .flatMap(r -> r.getSuperTypesList().stream()).collect(Collectors.toList()); + .flatMap(r -> r.getSuperTypesList().stream()) + .collect(Collectors.toList()); for (var specializationType : specializationTypes) { // Check existence of refinement before actually synthesizing it to avoid diff --git a/language/src/test/java/astrules/ASTPartDefTest.java b/language/src/test/java/astrules/ASTPartDefTest.java index 56128bb1..cb27476d 100644 --- a/language/src/test/java/astrules/ASTPartDefTest.java +++ b/language/src/test/java/astrules/ASTPartDefTest.java @@ -47,4 +47,24 @@ public void test_getRefinements() throws IOException { assertThat(C.getRefinements().get(1)).isEqualTo(B.getSymbol()); } + @Test + public void test_getRefinements_dependencyBased() throws IOException { + Optional ast = SysMLv2Mill.parser().parse_String( + "part def A; part def C; " + + "part def D { #refinement dependency to A; " + + "#refinement dependency to C; }"); + assertThat(ast).isPresent(); + + SysMLv2Mill.scopesGenitorDelegator().createFromAST(ast.get()); + + ASTPartDef A = (ASTPartDef) ast.get().getSysMLElement(0); + ASTPartDef C = (ASTPartDef) ast.get().getSysMLElement(1); + ASTPartDef D = (ASTPartDef) ast.get().getSysMLElement(2); + + // Dependency-based refinement + assertThat(D.getRefinements()).hasSize(2); + assertThat(D.getRefinements().get(0)).isEqualTo(A.getSymbol()); + assertThat(D.getRefinements().get(1)).isEqualTo(C.getSymbol()); + } + } diff --git a/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java b/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java index a9e924de..be0ec8fd 100644 --- a/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java +++ b/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java @@ -5,7 +5,6 @@ import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; -import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; import de.se_rwth.commons.logging.Finding; @@ -23,11 +22,6 @@ import static org.assertj.core.api.Assertions.assertThat; public class RefinementTargetDefinitionExistsCoCoTest { - - private static final String MODEL_PATH = "src/test/resources/parser"; - - private SysMLv2Parser parser = SysMLv2Mill.parser(); - @BeforeAll public static void init() { Log.init(); @@ -46,8 +40,7 @@ public void reset() { public class RefinementTargetDefinitionExistsCoCoTests { @Test public void testValid() throws IOException { - String validModel = - "part def BasePart;" + String validModel = "part def BasePart;" + "part def Refining refines BasePart;"; var ast = parse(validModel); @@ -67,6 +60,29 @@ public void testInvalid() throws IOException { assertThat(errors.get(0).getMsg()).contains("0x10AA2"); } + @Test + public void testValidDependencyTarget() throws IOException { + String validModel = "part def BasePart;" + + "part def Refining2 { #refinement dependency to BasePart; }"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalidDependencyTarget() throws IOException { + String invalidModel = + "part def Refining2 { #refinement dependency to UndefinedBasePart; }"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA2"); + } + private ASTSysMLModel parse(String model) throws IOException { var optAst = SysMLv2Mill.parser().parse_String(model); assertThat(optAst).isPresent(); From 065830b9db8eab1fac4489f91a162cfd235fe7f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Gr=C3=BCn?= Date: Thu, 16 Apr 2026 12:54:01 +0200 Subject: [PATCH 39/50] =?UTF-8?q?7.8.36:=20CoCo=20f=C3=BCr=20Connections?= =?UTF-8?q?=20von=20Ports=20(#236)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marcel Grün --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 4 +- .../sysmlv2/cocos/ConnectedPortsFitCoCo.java | 141 +++++++++++ ...ComponentInputConnectionDirectionCoCo.java | 220 ------------------ .../java/cocos/ConnectedPortsFitCoCoTest.java | 182 +++++++++++++++ ...onentInputConnectionDirectionCoCoTest.java | 202 ---------------- .../resources/symSymbolTables/Booleans.sym | 1 + .../test/resources/symSymbolTables/Inner.sym | 1 + .../resources/symSymbolTables/MyBooleans.sym | 1 + .../resources/symSymbolTables/MyInner.sym | 1 + 10 files changed, 330 insertions(+), 425 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConnectedPortsFitCoCo.java delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java create mode 100644 language/src/test/java/cocos/ConnectedPortsFitCoCoTest.java delete mode 100644 language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java create mode 100644 language/src/test/resources/symSymbolTables/Booleans.sym create mode 100644 language/src/test/resources/symSymbolTables/Inner.sym create mode 100644 language/src/test/resources/symSymbolTables/MyBooleans.sym create mode 100644 language/src/test/resources/symSymbolTables/MyInner.sym diff --git a/gradle.properties b/gradle.properties index 63d27708..de6dee01 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.35 +version = 7.8.36 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 8957d344..e73655f9 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -25,11 +25,11 @@ import de.monticore.lang.sysmlv2._symboltable.SysMLv2Symbols2Json; import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck3; +import de.monticore.lang.sysmlv2.cocos.ConnectedPortsFitCoCo; import de.monticore.lang.sysmlv2.cocos.EventTransitionRequiresAccept; import de.monticore.lang.sysmlv2.cocos.FlowCheckCoCo; import de.monticore.lang.sysmlv2.cocos.NameCompatible4Isabelle; import de.monticore.lang.sysmlv2.cocos.OneCardinality; -import de.monticore.lang.sysmlv2.cocos.ParentComponentInputConnectionDirectionCoCo; import de.monticore.lang.sysmlv2.cocos.PartBehaviorCoCo; import de.monticore.lang.sysmlv2.cocos.PartTypeDefinitionExistsCoCo; import de.monticore.lang.sysmlv2.cocos.PortDefinitionExistsCoCo; @@ -39,7 +39,6 @@ import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck3; import de.monticore.lang.sysmlv2.cocos.StateSupertypes; import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; -import de.monticore.lang.sysmlv2.cocos.SubcomponentOutputConnectionDirectionCoCo; import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; import de.monticore.lang.sysmlv2.cocos.ValidCausalityTimingCoCo; @@ -169,6 +168,7 @@ public void runAdditionalCoCos( checker.addCoCo(new PortDefinitionExistsCoCo()); checker.addCoCo(new PartBehaviorCoCo()); checker.addCoCo(new EventTransitionRequiresAccept()); + checker.addCoCo(new ConnectedPortsFitCoCo()); checker.checkAll(ast); } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConnectedPortsFitCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConnectedPortsFitCoCo.java new file mode 100644 index 00000000..2342162f --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConnectedPortsFitCoCo.java @@ -0,0 +1,141 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; +import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; +import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; +import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; +import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; +import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; +import de.monticore.types.check.SymTypeExpression; +import de.se_rwth.commons.logging.Log; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * Checks that the ends of connections are ports, exist, and have the same type + */ +public class ConnectedPortsFitCoCo implements SysMLPartsASTConnectionUsageCoCo { + + @Override + public void check(ASTConnectionUsage node) { + // Skip validation if endpoints are missing + if (!node.isPresentSrc() || !node.isPresentTgt()) { + return; + } + ISysMLPartsScope mainScope = node.getEnclosingScope(); + ASTEndpoint src = node.getSrc(); + ASTEndpoint tgt = node.getTgt(); + + String srcQName = src.getMCQualifiedName().toString(); + String tgtQName = tgt.getMCQualifiedName().toString(); + + boolean tgtIsSub = tgtQName.contains("."); + boolean srcIsSub = srcQName.contains("."); + + if(!tgtIsSub && mainScope.resolvePortUsage(tgtQName).isEmpty()){ + Log.error("0x10AC0 Illegal connection: The port with the name " + + tgtQName + " does not exist in the Parent Part: " + mainScope.getName(), + node.get_SourcePositionStart(),node.get_SourcePositionEnd() + );return; + } + if(!srcIsSub && mainScope.resolvePortUsage(srcQName).isEmpty()) { + Log.error("0x10AC1 Illegal connection: The port with the name " + + srcQName + " does not exist in the Parent Part: "+ mainScope.getName(), + node.get_SourcePositionStart(), node.get_SourcePositionEnd() + );return; + } + + // If target is a subcomponent port, check if the port exists + PortUsageSymbol tgtPort; + PortUsageSymbol srcPort; + if(tgtIsSub ) { + tgtPort = resolveSubPortPart(mainScope, tgtQName); + } + else { + tgtPort = resolveParPortPart(mainScope, tgtQName); + } + if(srcIsSub ) { + srcPort = resolveSubPortPart(mainScope, srcQName); + } + else { + srcPort = resolveParPortPart(mainScope, srcQName); + } + + if(tgtPort == null){ + Log.error("0x10AC2 Illegal connection: The port with the name " + + tgtQName + " does not exist in the Sub Part: " + tgtQName, + node.get_SourcePositionStart(),node.get_SourcePositionEnd() + ); + return; + } + else if (srcPort == null) { + Log.error("0x10AC2 Illegal connection: The port with the name " + + srcQName + " does not exist in the Sub Part: " + srcQName, + node.get_SourcePositionStart(), node.get_SourcePositionEnd() + ); + return; + } + else{ //Vorbereitung für Typecheck + String tgtPortType = getPortType(tgtPort); + String srcPortType = getPortType(srcPort); + if(!Objects.equals(tgtPortType, srcPortType)){ + Log.error("0x10AC4 Illegal connection: The type of the Ports " + + srcQName + " and " + tgtQName + " are not the same. ", + node.get_SourcePositionStart(), node.get_SourcePositionEnd() + ); + } + } + } + + protected String getPortType(PortUsageSymbol port) { + List types = new ArrayList<>(port.getTypesList()); + types.addAll(port.getConjugatedTypesList()); + if (types.size() != 1) { + Log.error("0x10AC3 Illegal connection: The port with the name " + + port.getName() + " does not have exactly 1 Type " + ); + return null; + } + return types.get(0).printFullName(); + } + + protected PortUsageSymbol resolveParPortPart( + ISysMLPartsScope scope, + String name) + { + Optional portUsageSymbol = scope.resolvePortUsage(name); + return portUsageSymbol.orElse(null); + } + + protected PortUsageSymbol resolveSubPortPart( + ISysMLPartsScope scope, + String name) + { + int lastDot = name.lastIndexOf('.'); + if (lastDot < 0) { + return null; + } + String partName = name.substring(0, lastDot); + String portName = name.substring(lastDot + 1); + Optional partSymbol = scope.resolvePartUsage(partName); + if (partSymbol.isEmpty()) { + return null; + } + PartUsageSymbol pus = partSymbol.get(); + if(pus.getPartDef().isEmpty()){ + return null; + } + PartDefSymbol partDef = pus.getPartDef().get(); + ISysMLPartsScope partScope = partDef.getSpannedScope(); + Optional ps = partScope.resolvePortUsage(portName); + if (ps.isEmpty()) { + return null; + } + PortUsageSymbol partPortSymbol = ps.get(); + return partPortSymbol; + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java deleted file mode 100644 index a05e694c..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java +++ /dev/null @@ -1,220 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.lang.sysmlbasis._ast.ASTModifier; -import de.monticore.lang.sysmlbasis._ast.ASTSysMLTyping; -import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; -import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; -import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; -import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; -import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; -import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; -import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; -import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; -import de.monticore.symboltable.modifiers.AccessModifier; -import de.se_rwth.commons.logging.Log; - -import java.util.List; -import java.util.Optional; - -/** - * Checks that Inputs of the parent component can only be connected to: - * 1. Inputs of subcomponents, or - * 2. Outputs of the parent component. - */ -public class ParentComponentInputConnectionDirectionCoCo implements SysMLPartsASTConnectionUsageCoCo { - - @Override - public void check(ASTConnectionUsage node) { - // Skip validation if endpoints are missing - if (!node.isPresentSrc() || !node.isPresentTgt()) { - return; - } - - ASTEndpoint src = node.getSrc(); - ASTEndpoint tgt = node.getTgt(); - - String srcQName = endpointQName(src); - String tgtQName = endpointQName(tgt); - - ISysMLPartsScope scope = node.getEnclosingScope(); - - // Determine if endpoints reference subcomponents - boolean tgtIsSub = isSubcomponentEndpoint(tgtQName); - boolean srcIsSub = isSubcomponentEndpoint(srcQName); - - // Resolve port symbols - PortUsageSymbol tgtPort = resolvePortSymbol(scope, tgtQName, tgtIsSub); - PortUsageSymbol srcPort = resolvePortSymbol(scope, srcQName, srcIsSub); - - // If any port is unresolvable, let other CoCos handle it - if (srcPort == null || tgtPort == null) { - return; - } - - // Classify ports - boolean tgtIsInput = portIsInput(tgtPort); - boolean tgtIsOutput = portIsOutput(tgtPort); - boolean srcIsInput = portIsInput(srcPort); - boolean srcIsOutput = portIsOutput(srcPort); - - // Allowed connections: - // 1. Subcomponent with Input ports - // 2. Parent component with Output ports - // 3. Connection does not imply flow directions. - // This information must be inferred by port attributes - boolean allowed = true; - - if (!((srcIsInput && !srcIsSub) || (tgtIsInput && !tgtIsSub))) { - // Both Endpoints are not a Parent input - // CoCo does not apply - return; - } else { - // At least one endpoint is of the Parent component - // Check if the OTHER endpoint satisfies the rule - - // If src is parent input - if (srcIsInput && !srcIsSub) { - allowed = allowed && ( - (tgtIsInput && tgtIsSub) || // tgt is sub input - (tgtIsOutput && !tgtIsSub) // tgt is parent output - ); - } - - // If tgt is parent input - if (tgtIsInput && !tgtIsSub) { - allowed = allowed && ( - (srcIsInput && srcIsSub) || // src is sub input - (srcIsOutput && !srcIsSub) // src is parent output - ); - } - } - - if( - (portIsInOutput(srcPort)) || - (portIsInOutput(tgtPort)) - ) { - Log.warn("0x10AA6 Warning: Connection involves an 'inout' port which may have ambiguous directionality.", - node.get_SourcePositionStart(), - node.get_SourcePositionEnd()); - } - - if (!allowed) { - Log.error( - "0x10AA6 Illegal connection: inputs of parent components can only be " + - "connected to inputs of subcomponents or outputs of the parent component.", - node.get_SourcePositionStart(), - node.get_SourcePositionEnd() - ); - } - } - - // -------- Hilfsmethoden -------- - - /** Qualified Name des Endpunkts als String. */ - protected String endpointQName(ASTEndpoint ep) { - if (ep.getMCQualifiedName() != null) { - return ep.getMCQualifiedName().toString(); - } - return ""; - } - - /** - * Heuristik: ein Name mit '.' steht für einen Port einer Subkomponente, - * z.B. "a.out". Ohne Punkt = Port der Oberkomponente. - */ - protected boolean isSubcomponentEndpoint(String qname) { - return qname.contains("."); - } - - /** Resolve port symbol based on whether it's in a subcomponent */ - protected PortUsageSymbol resolvePortSymbol(ISysMLPartsScope scope, - String qname, boolean isSub) { - if (isSub) { - return resolvePortOfSubPart(scope, qname); - } else { - return resolvePort(scope, qname); - } - } - - /** Resolve PortUsageSymbol by qualified name */ - protected PortUsageSymbol resolvePort(ISysMLPartsScope scope, String qname) { - List result = scope.resolvePortUsageSubKinds( - true, // search in enclosing scopes - qname, // qualified name, e.g., "a.out" - AccessModifier.ALL_INCLUSION, // ignore visibility - p -> true // no additional filtering - ); - - if (result.isEmpty()) { - return scope.resolvePortUsage(qname).orElse(null); - } - // If multiple candidates, take the first (should be unique in your models) - return result.get(0); - } - - /** Resolve port within a subcomponent */ - protected PortUsageSymbol resolvePortOfSubPart(ISysMLPartsScope scope, - String qname) { - // Split "a.out" into part "a" and port "out" - int lastDot = qname.lastIndexOf('.'); - if (lastDot == -1) { - return null; - } - - String partName = qname.substring(0, lastDot); - String portName = qname.substring(lastDot + 1); - - // Resolve the subcomponent - Optional partSymbol = scope.resolvePartUsage(partName); - if (partSymbol.isEmpty()) { - return null; - } - - Optional partDef = partSymbol.get().getPartDef(); - if (partDef.isPresent()) { - ISysMLPartsScope partScope = partDef.get().getSpannedScope(); - return resolvePort(partScope, portName); - } - - return null; - } - - /** Extract modifiers from PortUsageSymbol */ - protected ASTModifier getModifiersFromPortUsageSymbol(PortUsageSymbol symbol) { - ASTAttributeUsage portAttributeUsageAST = (ASTAttributeUsage) - symbol.getAstNode() - .getPortDefs() - .get(0) - .getSysMLElementList() - .get(0); - return portAttributeUsageAST.getModifier(); - } - - protected boolean portIsInput(PortUsageSymbol symbol) { - ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); - boolean portIsInAndNotConjugated = mods.isIn() && !portIsConjugated(symbol); - boolean portIsOutAndConjugated = mods.isOut() && portIsConjugated(symbol); - return (portIsInAndNotConjugated || portIsOutAndConjugated); - } - - protected boolean portIsOutput(PortUsageSymbol symbol) { - ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); - boolean portIsOutAndNotConjugated = mods.isOut() && !portIsConjugated(symbol); - boolean portIsInAndConjugated = mods.isIn() && portIsConjugated(symbol); - return (portIsOutAndNotConjugated || portIsInAndConjugated); - } - - protected boolean portIsInOutput(PortUsageSymbol symbol) { - ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); - return mods.isInout(); - } - - protected boolean portIsConjugated(PortUsageSymbol symbol) { - return - ((ASTSysMLTyping) symbol - .getAstNode() - .getSpecialization(0)) - .isConjugated(); - } -} diff --git a/language/src/test/java/cocos/ConnectedPortsFitCoCoTest.java b/language/src/test/java/cocos/ConnectedPortsFitCoCoTest.java new file mode 100644 index 00000000..63e42788 --- /dev/null +++ b/language/src/test/java/cocos/ConnectedPortsFitCoCoTest.java @@ -0,0 +1,182 @@ +package cocos; + +import de.monticore.io.paths.MCPath; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2.cocos.ConnectedPortsFitCoCo; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Paths; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests für die SymbolTable Serialisierung und Deserialisierung. + * Serialisierungstests werden nicht ausgeführt, damit kein AST erstellt wird. + * Die vorproduzierten .sym Dateien befinden sich in resources/jsonSymbolTables. + * Ziel: Testen, dass CoCos auch ohne direkten Zugriff auf das AST funktionieren, + * wenn nur die SymbolTable zur Verfügung steht. + */ +public class ConnectedPortsFitCoCoTest { + + private static final String JSON_OUTPUT_DIR = "src/test/resources/symSymbolTables"; + private static final SysMLv2Tool tool = new SysMLv2Tool(); + + @BeforeAll + public static void init() { + LogStub.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + Log.clearFindings(); + } + + //@Test + public void testCreateSymFiles() throws IOException { + List models = List.of( + "port def Booleans { in attribute val: Boolean; }", + "port def MyBooleans { in attribute val: Boolean; }", + "part def Inner { port i: Booleans; port o: ~Booleans; }", + "part def MyInner { port i: MyBooleans; port o: ~MyBooleans; }" + ); + + // Model verarbeiten + for (var model : models) { + var ast = SysMLv2Mill.parser().parse_String(model).get(); + var artifactScope = tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + tool.storeSymbols(artifactScope, + JSON_OUTPUT_DIR + "/" + artifactScope.getName() + ".sym"); + } + } + + // Tests to show if Ports in a connection exists in the corresponding part + @Test + public void testValidParOutAndSubInPortExist() throws IOException { + String model = + "part def Outer { port i: Booleans;" + + "port o: ~Booleans; part a: Inner;" + + "connect o to a.i; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings()).isEmpty(); + } + + @Test + public void testParentPortDoesNotExist() throws IOException { + String model = + "part def Outer { port i: Booleans;" + + " part a: Inner;" + + "connect o to a.i; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AC1"); + } + + @Test + public void testSubPortDoesNotExist() throws IOException { + String model = + "part def Outer { port i: Booleans;" + + "port o: ~Booleans; part a: Inner;" + + "connect o to a.k; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AC2"); + } + + // In Arbeit + @Test + public void testInvalidParSubPortTypes() throws IOException { + String model = + "part def Outer { port i: Booleans;" + + "port o: ~Booleans; part a: MyInner;" + + "connect o to a.i; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AC4"); + } + + @Test + public void testInvalidParPortTypes() throws IOException { + String model = + "part def Outer { port i: MyBooleans;" + + "port o: ~Booleans; part a: MyInner;" + + "connect i to o; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AC4"); + } + + @Test + public void testInvalidSubPortTypes() throws IOException { + String model = + "part def Outer { port i: Booleans;" + + "port o: ~Booleans; part a: MyInner; part b: Inner;" + + "connect a.o to b.i; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AC4"); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } +} diff --git a/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java b/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java deleted file mode 100644 index 11aedaa9..00000000 --- a/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java +++ /dev/null @@ -1,202 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package cocos; - -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; -import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; -import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; -import de.monticore.lang.sysmlv2.cocos.ParentComponentInputConnectionDirectionCoCo; -import de.se_rwth.commons.logging.Finding; -import de.se_rwth.commons.logging.Log; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ParentComponentInputConnectionDirectionCoCoTest { - - private static final String MODEL_PATH = "src/test/resources/parser"; - - private SysMLv2Parser parser = SysMLv2Mill.parser(); - - @BeforeAll - public static void init() { - Log.init(); - SysMLv2Mill.init(); - } - - @BeforeEach - public void reset() { - SysMLv2Mill.globalScope().clear(); - SysMLv2Mill.initializePrimitives(); - SysMLv2Mill.addCollectionTypes(); - Log.clearFindings(); - } - - @Nested - public class InputConnectionTests { - @Test - public void testValid() throws IOException { - String validModel = - "port def InPort { in attribute data: int; }" - + "port def OutPort { out attribute data: int; }" - + "part def A { port input: InPort; }" - + "part def B { port output: OutPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "port sysInAnother: InPort;" - + "port sysOut: OutPort;" - + "part a: A;" - + "part b: B;" - + "connect sysIn to a.input;" - + "connect sysInAnother to sysOut;" - + "}"; - - var ast = parse(validModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - @Test - public void testValidSwitchTgtAndSrc() throws IOException { - String validModel = - "port def InPort { in attribute data: int; }" - + "port def OutPort { out attribute data: int; }" - + "part def A { port input: InPort; }" - + "part def B { port output: OutPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "port sysInAnother: InPort;" - + "port sysOut: OutPort;" - + "part a: A;" - + "part b: B;" - + "connect a.input to sysIn;" - + "connect sysOut to sysInAnother;" - + "}"; - - var ast = parse(validModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - @Test - public void testValidConjugatedModel() throws IOException { - String validModel = - "port def InPort { in attribute data: int; }" - + "part def A { port input: InPort; }" - + "part def B { port output: ~InPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "port sysInAnother: InPort;" - + "port sysOut: ~InPort;" - + "part a: A;" - + "part b: B;" - + "connect sysIn to a.input;" - + "connect sysInAnother to sysOut;" - + "}"; - - var ast = parse(validModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - @Test - public void testInvalid() throws IOException { - String invalidModel = - "port def InPort { in attribute data: int; }" - + "port def OutPort { out attribute data: int; }" - + "part def A { port output: OutPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "part a: A;" - + "connect sysIn to a.output;" - + "}"; - - var ast = parse(invalidModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMsg()).contains("0x10AA6"); - } - - @Test - public void testInvalidConjugatedModel() throws IOException { - String invalidModel = - "port def InPort { in attribute data: int; }" - + "part def A { port output: ~InPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "part a: A;" - + "connect sysIn to a.output;" - + "}"; - - var ast = parse(invalidModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMsg()).contains("0x10AA6"); - } - - @Test - public void testInvalidConjugatedModelSwitchTgtAndSrc() throws IOException { - /* (Sub) Output -> (main) Input - * (also caught by SubcomponentOutputConnectionDirectionCoCo, so the - * connection would throw 0x10AA5 and 0x10AA6 in the actual Server) - */ - String invalidModel = - "port def InPort { in attribute data: int; }" - + "part def A { port output: ~InPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "part a: A;" - + "connect a.output to sysIn;" - + "}"; - - var ast = parse(invalidModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMsg()).contains("0x10AA6"); - } - - private ASTSysMLModel parse(String model) throws IOException { - var optAst = SysMLv2Mill.parser().parse_String(model); - assertThat(optAst).isPresent(); - return optAst.get(); - } - - private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { - var tool = new SysMLv2Tool(); - var scope = tool.createSymbolTable(ast); - tool.completeSymbolTable(ast); - return scope; - } - - private List check(ASTSysMLModel ast) { - var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); - Log.enableFailQuick(false); - checker.checkAll(ast); - return Log.getFindings().stream().filter(Finding::isError).collect( - Collectors.toList()); - } - - @AfterEach - void clearLog() { - Log.clearFindings(); - Log.enableFailQuick(true); - } - } -} diff --git a/language/src/test/resources/symSymbolTables/Booleans.sym b/language/src/test/resources/symSymbolTables/Booleans.sym new file mode 100644 index 00000000..d507eff0 --- /dev/null +++ b/language/src/test/resources/symSymbolTables/Booleans.sym @@ -0,0 +1 @@ +{"generated-using":"www.MontiCore.de technology","name":"Booleans","symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PortDefSymbol","name":"Booleans","fullName":"Booleans","spannedScope":{"symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol","name":"val","fullName":"Booleans.val","in":true}]}}]} \ No newline at end of file diff --git a/language/src/test/resources/symSymbolTables/Inner.sym b/language/src/test/resources/symSymbolTables/Inner.sym new file mode 100644 index 00000000..a37adf5c --- /dev/null +++ b/language/src/test/resources/symSymbolTables/Inner.sym @@ -0,0 +1 @@ +{"generated-using":"www.MontiCore.de technology","name":"Inner","symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PartDefSymbol","name":"Inner","fullName":"Inner","requirementType":"UNKNOWN","spannedScope":{"symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol","name":"i","fullName":"Inner.i","types":[{"kind":"de.monticore.types.check.SymTypeOfObject","objName":"Booleans"}],"strong":true},{"kind":"de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol","name":"o","fullName":"Inner.o","conjugatedTypes":[{"kind":"de.monticore.types.check.SymTypeOfObject","objName":"Booleans"}],"strong":true}]}}]} \ No newline at end of file diff --git a/language/src/test/resources/symSymbolTables/MyBooleans.sym b/language/src/test/resources/symSymbolTables/MyBooleans.sym new file mode 100644 index 00000000..26966b85 --- /dev/null +++ b/language/src/test/resources/symSymbolTables/MyBooleans.sym @@ -0,0 +1 @@ +{"generated-using":"www.MontiCore.de technology","name":"MyBooleans","symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PortDefSymbol","name":"MyBooleans","fullName":"MyBooleans","spannedScope":{"symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol","name":"val","fullName":"MyBooleans.val","in":true}]}}]} \ No newline at end of file diff --git a/language/src/test/resources/symSymbolTables/MyInner.sym b/language/src/test/resources/symSymbolTables/MyInner.sym new file mode 100644 index 00000000..d06b5c36 --- /dev/null +++ b/language/src/test/resources/symSymbolTables/MyInner.sym @@ -0,0 +1 @@ +{"generated-using":"www.MontiCore.de technology","name":"MyInner","symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PartDefSymbol","name":"MyInner","fullName":"MyInner","requirementType":"UNKNOWN","spannedScope":{"symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol","name":"i","fullName":"MyInner.i","types":[{"kind":"de.monticore.types.check.SymTypeOfObject","objName":"MyBooleans"}],"strong":true},{"kind":"de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol","name":"o","fullName":"MyInner.o","conjugatedTypes":[{"kind":"de.monticore.types.check.SymTypeOfObject","objName":"MyBooleans"}],"strong":true}]}}]} \ No newline at end of file From 329c4c3bbd7c585d448b8ab8def942829d5a060b Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Mon, 20 Apr 2026 14:39:57 +0200 Subject: [PATCH 40/50] 7.8.37 SysMLArtifactsScope is initialized by SysML-Imports (#100) * feat(imports): Initializing imports for ArtifactsScopes * feat(imports): Added tests for fqn and import-resolving * feat(imports): Documentation about SysML-Imports and our current implementation * renamed documentation file for imports * Version bump to 7.8.37 --------- Co-authored-by: Justus R --- doc/ImporteUndResolvingDocs.md | 91 ++++++ doc/sysmlv2-imports.png | Bin 0 -> 111457 bytes gradle.properties | 2 +- .../_symboltable/SysMLv2ScopesGenitor.java | 51 ++++ .../java/symboltable/ImportResolveTest.java | 285 ++++++++++++++++++ 5 files changed, 428 insertions(+), 1 deletion(-) create mode 100644 doc/ImporteUndResolvingDocs.md create mode 100644 doc/sysmlv2-imports.png create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java create mode 100644 language/src/test/java/symboltable/ImportResolveTest.java diff --git a/doc/ImporteUndResolvingDocs.md b/doc/ImporteUndResolvingDocs.md new file mode 100644 index 00000000..b3b46331 --- /dev/null +++ b/doc/ImporteUndResolvingDocs.md @@ -0,0 +1,91 @@ +# Dokumentation: Import-Mechanismus und Namensauflösung +In der MontiCore-basierten Implementierung von SysMLv2 ist die effiziente +Auflösung von Symbolen über Modellgrenzen hinweg entscheidend. Da Modelle in der +Regel in Pakete unterteilt sind, benötigt der `ArtifactScope` einen Mechanismus, +um lokale Referenzen auf externe Symbole (Cross-References) korrekt zuzuordnen. +Dies betrifft in der aktuellen Implementierung so nur Imports auf root-Ebene +eines Modells. Eine Fortsetzung hierfür folgt. + +## 1. SysMLv2 Import-Typen +SysMLv2 definiert verschiedene Strategien, um Elemente aus anderen Namensräumen +verfügbar zu machen. In unserer aktuellen Implementierung werden diese wie folgt +auf die MontiCore-Symboltabelle abgebildet: + +### Normaler Import +Ein expliziter Import eines einzelnen Elements. +* **Syntax:** `import MyPackage::MyPart;` +* **Verhalten:** Nur das spezifische Symbol `MyPart` wird im lokalen Scope unter \ + seinem einfachen Namen bekannt gemacht. + +### Wildcard Import (*) +Importiert alle direkt in einem Paket enthaltenen Elemente. +* **Syntax:** `import MyPackage::*;` +* **Verhalten:** Alle Symbole, die sich unmittelbar in `MyPackage` befinden, \ + können ohne Qualifizierung angesprochen werden. + +### Rekursiver Import (**) +Importiert die gesamte Hierarchie eines Pakets inklusive aller Unterpakete. +* **Syntax:** `import MyPackage::**;` +* **Aktueller Status:** In der aktuellen Version werden rekursive Imports +* **wie Wildcard-Imports (*) behandelt**. Das bedeutet, dass nur die direkte \ + Ebene unterhalb von `MyPackage` aufgelöst wird. Eine tiefe Suche durch alle \ + Unterpakete findet derzeit nicht statt, da dies eine Anpassung des globalen \ + Resolve-Algorithmus erfordert. + +### Wildcard & Rekursiv +Wildcard und Rekursive Imports können ebenfalls gemischt werden. Jedes Sub-Paket +von MyPackage wird hierbei rekursiv importiert. +* **Syntax**: `import MyPackage::*::**` +* **Aktueller Status**: Sie werden wie Wildcard-Imports behandelt + +## 2. Visuelle Darstellung der Sichtbarkeiten +Das folgende Diagramm illustriert, welche Elemente je nach Import-Strategie für +den aktuellen Scope "sichtbar" werden: +![SysML-Import-Typen-Visualisiert](sysmlv2-imports.png) + +## 3. Technische Umsetzung im ArtifactScope +Die Namensauflösung basiert auf der Delegation vom lokalen `ArtifactScope` an +den `GlobalScope`. Der zentrale Mechanismus ist dabei die Generierung von +Kandidaten-Namen. + +### Die Methode `continuePartDefWithEnclosingScope` +Wenn ein Symbol (z. B. eine `PartDef`) lokal nicht gefunden wird, ruft MontiCore +diese Methode auf. Sie berechnet eine Menge von voll-qualifizierten Namen (FQNs), +nach denen der `GlobalScope` suchen soll. + +### Namensqualifizierung mit `calculateQualifiedNames` +Diese Methode nutzt die im `ArtifactScope` hinterlegten `ImportStatements`. +Sie prüft für jeden Import: +1. **Bei Wildcards:** Ist der gesuchte Name ein Kind des importierten Pakets? \ + (z.B. `ImportPfad + "." + gesuchterName`) +2. **Bei expliziten Importen:** Entspricht der einfache Name des Imports dem \ + gesuchten Namen? + +```java +// Logik-Ausschnitt aus der Generierung +for (ImportStatement importStatement : imports) { + if (importStatement.isStar()) { + potentialSymbolNames.add(importStatement.getStatement() + "." + name); + } else if (getSimpleName(importStatement.getStatement()).equals(name)) { + potentialSymbolNames.add(importStatement.getStatement()); + } +} +``` + +### SysMLv2ScopesGenitor +Um die Namensqualizifierung zu ermöglichen, inizialisieren wir die Imports des +ArtifactsScopes innerhalb des ScopesGenitors. Wir verwenden die Hookpoint +`initArtifactScopeHP1`, um vor der Genitor-Traversierung des AST sicherzustellen, +dass der ArtifactScope vollständig konfiguriert ist und Import- Auslösungen +potentiell verfügbar sind. + +## 4. Einschränkungen und Roadmap +Da `calculateQualifiedNames` in aktuellen MontiCore-Versionen als `@deprecated` +markiert ist, sollte langfristig auf eine explizite Qualifizierung während der +Symbolerstellung im `ScopesGenitor` umgestellt werden. + +**Rekursive Imports:** Um `**` korrekt zu unterstützen, muss die Logik so +erweitert werden, dass bei Vorhandensein eines rekursiven Imports der +`GlobalScope` angewiesen wird, eine Präfix-Suche durchzuführen, anstatt nur +nach exakten FQNs zu suchen. Alternativ könnte hierfür auch eine iteration der +Sub-Pakete in calculateQualifiedNames angestrebt werden. diff --git a/doc/sysmlv2-imports.png b/doc/sysmlv2-imports.png new file mode 100644 index 0000000000000000000000000000000000000000..ede784b580b7e00a856f23ea17e6e8b8d8e3e7d1 GIT binary patch literal 111457 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 z z089*cB#-V%Jwf0fHYfufzW-;i#{XW=o}l|&9MK}(uux;;0}A_J(VG2ZFNIW9Z-uSX zi~xkm|0wRqz{#mEzy%FLqi~fcTBi_lWgZ^$J9Hia#<9(c!Lfbz*{fQiDL@RL?==rE zbZhTEJ@($)ymF(qj^W;h`F=e2W!&KTuCl-l3BwVuJU5|?nY-f>Lmd}zIO+dG*L%QI z{eKVq?zQ)|MOOAEBKs<3ugFNGGPANb7a1iZBV=79BC=OzgAmu25lXVM_x``$RG;tf z|9|`+JsuwM;CCC3{=506}et4Nww!xR-JWM%8CLsOEbe zpZujrmZ&uc(#$o19eX6XO$2S&CEU3RN;jLwE_u)0g4OycxaQ6SL0^Ov&KDz~jJC-vFmoyokDnjbUQ4iDe5sC?|d(|A$Pdu%)LPC3h#2xcKODj?Zx zx9bB{Z%lnxIWq=HwcOu1SyA#%*f+-U5taiJ7km8N;jXPaw0mXBaSs4P3HEHP`XJ;0}sMRJ74$5tr;HQ@xuH1 zN@Cn(*%g3K{vZl?O6ssyRH4eZ^a@ZL1Hml2pMt&+^&x~4ZT3`a^3i`}@{`}ZojM;v zN4nRjKZnqfU`ClVg0;9Qm~;UBxJEqPAUIlpBK;Ql=5lv_6V^`J0Sg8`Ht@vv%Tcs1 z1|pn5l4P4wAaWCIewWY=%RY<-xTQdgj)UZO*oBGy`ofXuh`$^;u;ji$H3L!4+aP8C zx)H}sfKWOSCtVGc)8bU-h^h7Ha^6EGLo9u<7wpXqvr-Y}siV$sYgg7tN;LnJ%YtAk z#gu6$5a7y`7df3Q}6=lc7|%>>mdW$VbnRZ2-F0F!hJF} zrmNDAdyOs9-Qbkc$v8|p7o^b;jX$kd7M1}Ewg#xVsSL5*W-(;RxB5{Ns8Yi`7?nz7 zA=G@3yd&0fAT?@l572mgtMYlIDyz{k9;|@GHEr})ub_c6<*|Vx;tP6Z@I0ECNnScg zsh0h-{DNlNGc=X)vQgRT?3LqsF?(IV@by*ecwh!@u=S%;Q0u9U_^gNWytHB;ydw$O zPC#qDI`2K%Z@^)L-D3b@*v_orpZv~lsC?&3dk&~ZF%DBR{ETxJ2f|9v0Z%lj(a zrRRa#yZ_XKU{xa_lcwsm6b6R54#?wY!W__O{sD@yfg>QbB$s`dVGS7|tyC0fY9Ya? zm>T2|eDt4Hv3Ui?)>Z#@NG&LgsN(G{w+;g72TBlfH60lm&8)~B8v&b~!zqiIe!5Mt zYQLJMRHC`$P1}JX_-|?U+=fl;R1iP5!S6AHtldC{1UAHuj<5*?bZuKfb5|HEg`* zT?PuI*{4dUap!C(+{y@~jRocbvbh%;tBu=Gc7N-s1GPju<^6r+u{k3}26+Yz!0@=8 zxes6qC99#f;SSot5=s>c5L0os&k>Ny)O(m8SJ=d#0$b5?@F8#%UjQH}MgQeQ&YMUG ztRr<{PK2V@`yTLI7XUJKIq3-i5*?$$xI#`&vTidrw3eUX+Qj!RyA{4-%FwQ{B zX$Vi50bKx&`k;oScijkF>7`?(BZA3@6!AkXYeTMthXLxYQh2y~-{YYc{zv#w*CJGFPCD_B`@F5O_4b%c=VN@Gn&FrZvav=oJfOaz_L@Corroj87nC zMY|LjTt!EPhcl*B@#zQ9%KB{P%#ext2J~e97*jb&iS2oY73CisjisoJn)w)wm5wh> zqeRkOrsbndx6XG7Lc_d4Dkc7woYv{kcuEExmFzG8{LMiz>hv| z);X3QdG@bd+3B=xb!YJd^gPg9;zwjAO++|fvdQ4$KM5K301y;da3TU}5+yf=(@q6w zHCRT27qc<9Q%2=u49kBz4UMdXSG)s<$&MvqXm`=1oM*LpCwdoI!sJkMx!bZI_YIT_ z+#?T}Hcw1ZDLe{+&eBrC&fo+PYEHn2T^07kgU(CzSAz<0y^g(T=k)<;%Wn0{+99Aw z0lZ@~0=NG35)#ReYZKn9%xaVLiJY_)tVQz~b~J4O)nKSeOeKjuz?RA0zwHdP5m{d$G(rbbNPCev=_KRpt|q=AaEBIs$n4~$Efa?dd!^xf){w{St3zXzl%b8r-J$wrNxe%9ZTM!lft z#63J*_fVIfzob}Inoh;@to^PjeL#vE#@4)H9AL(ajp4xXf+G}AH(yw%9M8fR3>T0G zF~A-N5VuITH0E;wYw4iMMFQwUJ*`it|MVLYu>nf~PjI4a(byChfo@UnA&71jIrSZ; zQ(y+c*DrNGj(QLcYOgD>FgzGL*?0DB8w?n}u@Ir8;nM^AU(X|eL@|?VG}4}`*YTxh zJEWoP0Jm1wPQw57_^Cz#RnQ=Z-g{D@5?+ZwJ2Qq9i2LMZspll~(i?pH8w)_UXei~R zh-cF#md8fXO?l7MavJ5mm(7$d2M*0S;D|NzolZ8`m~`+8MreI2Uq1>t! zKyB$TwzBX3LQKz=Ur!;HgBtLNxk!MQuzjr&9A7Im0bB}DHrw>e|Fp-b0*w@VhGd)? zXp%#*LSErS_1nBG)4C;P!cZ-m-w_ukq$}U*jthD;#M5BJFc&d=7{PQvLz}%}(3#cz z21oX9qq8z<^odf>_EQNSpoFg3=Jh#p+PnjBu-~0!_h>~jF7s%qQiUA=5SmCv|LJY=mn2mO7ogQx$e4M?=m zJN&)REnQGklBcusOl-;Q-xN7NJ+;mMx`=sq;@S`Z%w|af-UanO0vj8RRy1#v1~}XR zHlq$VEW<9tIoQ2JEARE8Jj&?7gD2~`lVdV`p0{u)G`z`S7 z;;&zz2+0+&WsPfv1Vy}>)&_mTCCud(pY%nmk?_-+NpKE?yrJs^Jv;2l0su>yU8KSI zq8;|0Fy#8U3qK?z4e;=mm*QM}I@&=tA4NqNqAvFlJW#qH1M72vz*|9F1gmd04yoR3 z__b|x`%o>|F#VZd@bCg^5n&vlA8ll0?xG@~$5ki;M|gYO&Tdo(hNpOrB#ICg@IFMm zpcBPIDjR&A8AyK{6sKQ9S!ZBiEz+3F7?~Cyy#-r2E8Z#47xAyunFs-5tS2M7kz=g4 z>Q$HKWIS3}twhVs4Mu+2%klGd^fM})k-1w4(A2IO$rB~=T)ex6I_gsPc*Olw^QJ7M z9_|m<=JM_h?UIRs{aeCk+7J@PP57}4J#2JH1JTnhq)i`7%L!ckhycDtr8D9lC~yG> z74Hc;_1xymFfJ^5tf*F+F&z9}ot$R|fK6-71CrJ<0_CZ66*BgANkHgRh>_FW@;{+m zq(FCd0o9iw!kT`e&n)jmErFXvn-hE}yyAwwZB|GhFOa* z0)T>b_!+cjTB(6&NP;`c(QF-zQE{W+J-<4F4(a8>|I_3Oa+0~sy{YH)Q4+FCo}+6T z^d(xcTFez&XE4I;v%P%;75+3e{wf9?!9~BS=7cM1R}nH?R}xP)Dr>lf$Hmh_36rPu zyG}5)C%an9YUD(CRcNr{{QrzWpQ{;iuo?lXlJ0a~#TGXS?=_tof}jN)E)9f!QmGU# zx)~cTZbAR^X)Ed2Z_C(tv@UfE#5x`oK;ok?B$+hwQ~~m%hvNTA$mU{DwS2KLSn;?x z@wgR7#(6AA!g(sC6O{a=GhiH8StB6OC*ph6Rmc1Wj6sy-VIK;pJN&-SYye|e(gn6s z74fRn_YF$Y0BJlwt;45Z*4tOz{w+-4Ctg5~DeS`_(I~CW^CNnPt>m^(yExtw?!g9& zQVtF97w;Fzy2~}xJ=>#6fq>b5;atqTs*d)f%1|8W<5Ob|7Inesu**9l>C)Vx@5pxr2m#UXV{a6c53;H($hh6 z!LRbZ0xeJO?tp$_=rzR;A?E4m(kmi00N*E`)i|UW6hP2p9)m#uxl8soue5D_`PW_d ztV9u%NN+Ml0Dj(2%{w6v%dkkH19S2%ple<`jOT#Wq5&64R>cnC96L{qol4?JdFnbg z{{(clU6Nk&SptTwsH5LHivP~pki)XihXlO=%218Ci@lP0lZrh_)~cJ8B31x3wM3n7 zTa?b4KOa^8HH0c6NP~fr#HOrk(AK7BE}|9xG$J9=fEBg2E3j7k-BoGYf4}_9!GSc` zPj++Ak%`p_wtsF@bk45F8Z>)Q(+qrsj={vSo`T{=AqUcArG6_z7hK5Ui4qP;1>s#2 z7Xf}56sAfi?AhhI{NlO~sk}1v;GfX{nJ#A_R+_y3sy%q_V7R7$7LeY2=xml!z_sl5 zkjdISjt#Yjgy@v{FSiHFdH_f)uQ$^UW0>#H{0<#IPv;8F0{;cV#}2e;mMfF;T*U8# z8;Sg%?{>jkaqne9`vlz%oj>-LZ&gR*dad;%SbuN?$gnby3XDVp<)njl4chf9{V5=? zE#6_g;_G$#TK~S76T$X5HK;Xy=X|t)0s5D=b6q=VA{>vhoHquul`$_{N(d)0T7S=N z6eBHq4v8IP`4TK~0O{Yo{b@E56Q5bQOe*(xnp%l#PIH|Ek#{(`h>a+3ha8ho;jEe9 zp85jdb{E|6k1|!tGZC%=SSEiMbw2*cnfNaA=Pgh9@}v39~(=K0`xe zlYx~f%+NFN6z|d>3MZIu2fC7D@K|v7KG%j2wL);_y`^fpiJatyNQHnM13913o?RC` z1)GUeRbj#IT<~OiR-+Z^tJ+{|@#5}2T{BkCQSM3Rx^4)Sk^j%T>X^XxFNp>q)B&UL zpoHUri4<{hvpueC)8GEayD2#I`4$G5bP|j8A5*AVjWXx`cKFdqPq<(AZoM-tsm&jP z2blU7Z03TeYv4w9rrvQ89C%BuEJhEYq!f^}dDd)sv=m8lqZP>+57Qt*yzxwX25@0! zLB)2=nKD{0TQvS4a{s-dCN&zPm%)RM)<9g=MLp656v|N-;GEt%#u6{u7e%&z#9GwA z6X8XcOjPXOV!?HxoN`t6w&D0k8$Dear}@YP_Cdsu`yiE!*<@u)jO?XwVM@pMuD{W8jdyc6L}@EkOodi&Ffn)U9cX7f{; zWC$o#jo%myCm8>X2Z0Cb;I;Re(BK5-~e83Q8eulOLtN6d(p=`*e{PPJfiKpIdn(zn5wScFwImVyd?D8=^No)Hub z^~7E2NzN_sJMJJg{XcF$pyiWu^2l=Jpw`i*!NRhRk=i83X%ft zP;`7vmwKM>n`nc1L&MZ{xa1@Ml9FBsn14IdC;4h9`GJp*;jJ>+F*gU@Pn+%j1tVF_ z!Rt9vZsxHbR$QdQuGazJt9+y8-*t#7*U#2vk$STKr4*gY3Yd{&>S@N_ynDYx=)cXJ z;ImKN1Oaq?Fi2gTlgw%?VddZ(T7KSfPzb^tcUPA3b|QvD{Y+Z~)#D1BHnaq(CPX5j zCAH#a(VX4d7|tP0sI0pEYoOR{p#d&MOT3Xk90JcO_|zE(77(y`o}g1RX1Y1Q;ZO3x zndrrDqmF5)a5d<42G_j^##%YxAO{P{2_B;V-iGT4F=a_F_N$)5+jx6g8d9n0#3FZ< zABJVBQlB2Pf)ok7{@mh^vNr!jdLM=~()EVbnJ9y4&H$_FL-|feKY>Qt`6*7RuJ6ka zqEVOHZ?iJwX^~k3L;!Ny#`L_s*VPY`Q$|Pka?Qpkd^cF7j*srdM4lC zc+FE-ypQZ@hjBchrmgG+*YC)ymAy2TE`QeH>0(49@!(G%3z$?1l)hAWKFFbnCr=Cb zkbj{wuaPLQlHa7AN4Ds&3IjXQce$(3;w;Ap;Jwd4N8mvpXd*-@xe3F3S?cRR#|WSx zUwc+rZT;Y+3yC>&E34zJ8~Gaxz>d9I8)T*r^yH6?c36PCuE^QC`?K$ZS_t)JRYhuo zeK`RwzznRE-%h$RMD$HuZ9lPkqi>n01E$8*YQR|$9;>A|{YwRH{5{G+yJ`F9me|XT{{$VNT?qyuMnLUf z)_Z?0ha#u&_zsY9^4|jY5u(+L?4QF^9zwLhxf!AT(8Fz7SzHL|8$xT`W$@d6t)KKvbh+nX`Vv~m_pCB%~`%* zpxES3X9B4W>Gd0(^$}up7}eNX=)*r7qgZ}im@B7{N*XK! zo2e0Ork}n}45npYxbPVq9A>DKqmbekZQZ)LSTO$tb^7ra5jM9eeuN9%Ps??tskj2{ zgD0>w`&z$oxu{k@T}tUF5XZBi6E;iZisS^P&iL*w8qVmynVh#^{Qo+%i{D`lNRD)d zXYXBtdJg^F0(T7IqW#|nRjJ55eAAHPWUZXwxD*5LZQiV1py=uU9}(!FrD3iw^jY`q zjzxaGl;r|tfFxiXU$A~IF8~l6jd01rTb-5j?yq-_$~RA!${;~<EmDP%BMRazuXqqo6XA_~d_=j5A$I3pLV3gGSl`H3Eune!$h zF*5(b0UP^>iu^wFziSWlruvik4(ekBL<$Lm6;AfTENptZ#2)T^tEOeiqv3yUz4!a) z?Z&HQBh@95fuQ(J+n8Zp_F*6|cZNOV)=|ckJZ0^~)sE{wZ^?JwY_gv8ecmQF?W*ae zuwKJ5fxmK<27|S9MSi$~s_-*L)=vn3i==1e$B3m=zMW6HU#3&z2QTJbt*oj^KCfVfevi4@e zV~o749=|qe<*~K~NT*LQ0@WHUoqe$@xXZ$l4BAyu`vHb7ERS!muvxN0$r=SKSbV^Ov2Od>)f5cKL$j(cvu1bg!nsfxqAe=EVD#%v1c} zm5TE#hJbg|E0A|_P42_Sr;B+m*Nk}#yJsR@s@&U+Z0e`}M_JN4brBf25ULLL)ZH{r@X76oE z(4JtnCa6OhkGO}|jf)i(`pw?*V#ep%>UIP57VgU(+V7Lt$Jx-Wx4cTv56^roEr$(i z|H)z;Z{2q@&T}ytItKna*>up9jG*%LcxO@$DCYm+8#WthsWtPYOs6=llWxX-%*Ddu z(b&bp^ybl&c1*~^#ZplTy<;hiudl8ZUQdY zU$ZTX6DFz{tK20R`d2gk+hm)1&Gmm$T3B6yioe*TNUMFev3v-O)c!r=uUX1ZMecwc zl)|i;|7$S7XMtm-?BBB_19USq?NmzhC#Bm87W2QadiDXoh&A41QQ=Ts8~=ahoa>;E z;X`0he6%&cUa-(g34vjq4G2vLd6nOVZb5B$k>Hlb$p8QIiU2#b1p#(^^j!bs2!oGH z4n-d7n;j-h2$ZesgFitx!k+_L{F#X8Q9y-ZBey9}^~50Y$L6~v90q}*;2@C*eavI{ zZ01Qyh1VMKlidZwB+c=qDoBu^6Gd_DFXc~(_O7%fXD|^F^`P_Gp24hb@9w3XJsTQ! z7}vwC!Ab3dWncYK|DBL0uzmXcN&g)>K&vs1Ba_?QvYqcc(EwGY@7%zTNsH3l8y_}B z)e6sM2CDkZ@K45py1r#;J>%_tA|sc-<3-Z~Q4IW$FjfISF<*rrKMKhE#SE;4CKV_N z_w54}dT|DCj6{nc@Eg3*ko@LmvVXi2_@Y~GhsyTkC`J{Z$<1$nyV~%`ZN4Uiu>t^R zIyM_tjyTfY`i$p6dFoBhON)7;@z_xL$rIJ{L;SoYDX03p!mRmNcaa4KqgLU)MAbqV zY&BtM_s{4J7?}5Fr#~rER<8d_->2X@+pU`FSa)~yUSxQ5>nn)-LT?yn_qIWZ$$#_p z{Ca1Tlu!dNW8hxrIw+&Je))mS_iEij!Afo-f8j~gW4@>);U?~eMbp_lG0b80M<2cA zkS+RPRMOwyOr^qF)qYv6slc2)Nzv#xz*2DHZ_833c zx~bq3wZkgqJH!sZPM1g#RRqiJ2o?()CKQbUILaB^g%09eo}#A+F|d&s=TatFBlDUC zaA*ZbYcIBdG9*YJSHhDbkNM8P~{9SzByV`JrC&!+*VbNOD z1gt15_}LfzXe?};M7^PB?YxB7uwXa{B>0leTC!Ycck8X$7-#(c@j+$^b9?;lW~B+Z z;JMC&FJf;?7vDBvth)BQZdE?89JAMRa2Ts% zg|~#?4<_#vF#13Z|3qVsLf15c`+PWol7V?km(EgoGkYopCHTQz#AiOz7EN6pa?46r zLP;$S%BtS$iySe#AIQbxFb$b9o*AGj_P}Gpd)PRJS=nf~_>z!K-JPbO?fu1-(Zjus z_ya4MEaekW{%}=D>y!WC8uss`J65?-*E353_va0NH)CT;9KUUQ9@tmjWLfN=)!4b5 zaVPMos5hY8>d4Xmz|7*?I~IGVrlTwq1=nA1Jyu(+YmeMDLWzazdyDvo)Gzc_lt%N0 zPf@5a+V_kw`>j5Z`IS6T)pMn&^2M1zku5mcJ>Div*^|zE^s*FeC}b}#Ju8p2b1oC= z@WNlA?-A=84hP&2`yGPwT56D--tgwl5yLy0B>-da4b&4;`YzWFJG4H{j8C=QkCHsT z4@!$u0P84J!hK<<-F-x(ezVW!-N`ZcHz8o#%C=Sl(*&!GWF#~9*O%Y1n5<0XjpEXg zlsZp0mU?gesvTqy-~CZG zM2ue+-)Df<06H0-NaNYVML5cnnCR;gi3NA2HAk^_=c-SD1rkJ0tn{5qR`eIQT_P7U zAeA~<{;2JzwA|1u_eF!MFBjFhWEN#SZcnfXd>zCill>G5$XqR>m3E8U0I?%q3N*m* zrUQ00>xZNm`Th5RBI2>*fGbyc5=C zuT>s!L{`z~pnN%Mrpih#Qj&|MK_c77=IG3R{ywE*}b z)6ZGDUk&G230&tB*c{GN0+~cS0gamS6R78vSS5q*N56KK@tJtI!`w>e{yT=rJ657_@MVgHp? z=5V#4NI9l!Dfa62!}%VUqG3s*;&;pPsh6D#BGobL!`vLz-#o-5r?Ntc1qVhYzPVvn zH~r8t3OuT;EU?Mqot{EHRtgS+O|!rWsMT3*oM`!vUD`U=j4nvO{2L1pqa)}JU8qyu zwP@rvftKxeIxzc(mP$kvVD`%hRtb;FN?dhtp0FX)t|5A+y^gou&i>9#YOVP?=-oK; zJkY)0XT+s5%3;{_UEWgt^1$m5z(m*{{jzy@0x%OFHLEwXC+TZ`#+i(>KfP61P(Fid8^gCW`)vPm?9SJK-uTq(z za{ZAy_pv6S=&SahWAPdMvlT3>ugCBEqrzE^t4$hzmn|K&1br(4d)l$_d*>s%guf2!ZWW@eT=-@T}-5E^6I!>_DfPqr&n*D`$K*-V6GAn)`8~1+6fI8KT&W<<6O(QkVlSZpc zA-sC8QmZ`q`|JIH`ldbPDK%JB_GR&zOR?~~^_+oABRTG=$>e2#DGM2IRucK#yXrri z9#cwqj1K;>JD->7(4E#thM23-4E^;qbu@eiSV?3S?vq~8+jHWSch+zV*jEp*2iu*@ z18(~vqIGoP;~{PDYR<7nc<#l?K$FBBgiCj_E_oR@Uk62@XyElKm^R7I7u-Rsy~R?A{HFyxKM_uPwh<7R7Y%jEfPMsj2rp z37y+q$(u^MVTlh##O209t)WsEOCd3L5#tOqo8rHijH`5}UG=KhNsCOXXG5Wco3Vmo zbdpa#21A~K4qwpJ;>7ryM76YOR-J&LsbBR2yuIu`c;xb9%z=Ip#2>;)%Qi48ivcLF zc1}8{gtV|G8nj|4+tu!BV7?|s*u56$5$joRzACs7wv%gxKXBr4dh?vL5# zFRTSSCjZ#Bt$%GN~ASz;7(k`bnKolpVY} zG0qE?^F}31dTXaIUQe7n4qlwf9MvqkdivI}d?iz1JZUkj#up5bno(2^k2z^wC#}BP<`vx* zUuoERtYEX2ovP)p8}2Le78bd^lq7QGsK|A9?GqiT#|#s&3i&ocxJz9RtHSx~9(Kg; zEfC0><&y}UFGInJ7t$V1Os}&wz-c`Qa_*tf#X4SBAqOiW4EdE&t5=63kw8fqUFRb= z%v;=aG^OWvSL+DuV+%2>!{2c=z1IUvAw$={SHC%5?z=8}egEz~{{!<+G)a}fs*fG* zDBQi{zva*{XK0)o!iea34^}|mD~&y~cpOOS1xdpu5TEs%Bfn0E4mjSJ7;x;9VUvd6 z6)rEy6PD&=>Q17OZAnvP2FV*$H}RVHzPX@j4iLpOrgGMI4?31S5F=br^o9Cz^FUjnYy^sBADf}8wffhVS#w!McA)uh#d#~a3}3W1GQ zi@1W2W41Jt)HYzk{G|f85(antEhP(`1fJ5b-D+qds1BwBqDQ}k=gJv9JmLivKey;{ z>LdJp(OJe1wTB-{Z4g-SBhu6d!bdu;S^MG53N1NqcDI4KjVq}qmL)|gHEdABgR+xL#pT#0e zu+K+*&gqpHLWO$ymi2<9iwoZ zEqCzS&ZGC5CGOU@%;rz20+JGCzzsgz2*klw=g1*YNmxGVlxZ9q@ObK7*h^S`<^ zPd?|6N*Ikr%epA+sIWU60N-pB1(ST|q$s=hv-8z`YnkROF9M(&Q{cLv-Ftq$A=}H5 z&o)2zNxa~&AtKP1^~rK##;>W=^})f#o6@*@!XdzPTO!{+y1EcNs!y;!Ip8BmUd21~ zF1lBrAbRBVyVpNGrNn9ANw0?Nyh}(|2rSqUX)<@u*MH_>p(zs_Q9@6_TP7PFM??0} zQ~12dM+^2W;&TEr^Djdj_GXftMHfmH3X7`Z4hBxxV{Th7d|esa!IJr1(g0cIG4`0l zu|{xAsCIZI{G?nv)2!;plg>KRFmjf=nF0Hiso+5Kti++}byXWPz7WFmEr72mNpef`Q9G)IgRNJV0%)FhDFp$Nkxc=6=LOd=ne zar=HuLr-5Q`bN7&>b*Tnm){yyyaxN(ly5sOnx3;uIZTMrsOt52^pG%rJRw^|{ynz} zBPmrP0v6Ok)iW9Ju$*}S|C7$#L_=W|lgxN1;H5Q>Ru&#<2H8jFc5j4`PkhMm{zXfN znd>DVX*zZ%{Xjn{VAw0$Fa`orLYCfRf$U zd5#`qjk`a-4dr$+L{;@q2SEnS(=Yd`^MYxc>}*<&!_n5T)-l34Cw-BYgOU)kBuhc~ z#bv!YC-c#g4+eAs&8K}NchU6&4ljCB*I&Bv{CqGz5M;p`dGF)50a4?O6x4B8rR6HG zswP!77vf|SZ|7o%E&bRBHM%S>c!uPcU{}_HnLDOCT}iAgpZYKSxaT+i8pq}tdn?RmOW+8QdI;($9vD6MElK{ z))hbA`;}fpfkYdy=I6+saLLboer@`J9||`hUE$!bki)bNH%+@-n`d-X*?4>_#jg%*S_%vJg3T&?&;s%!)*1BR?PS(jx$U+wHxf95IKW9TU zHWDWx=Phi3Vs*N5L4{i}4>C@T6Pa4B-}fDKww$!{ za(8%qS@sr>4GV61_jesG8eJNKZuZKCoEP|g-^ze85o9dA77ZVfD5&t~uIF`h1@>Ba<#(Mzs0fTp0b4p%D5+ zZZ{#|VU&P={a)*bz4*80VF%&nVt52sbO@X^gZU&vOMYqF>JixOXU7%WGwO<0eK09& z`J^y*QP3lLz=k}!WseHf;9U;;z(|aD|i}!+v3aMIU5>F|bi|%}` zZj)-r$E1&(pcj3y*JZV z@Z6=2XN?+t2Fng^Ful(lOfFw6WU6>$nuA-NFK4c?WNqZh;(pep$k&0HhHPrWE$>K* zW=LwBxk)gbGRoBj=_iF(cS%;?Tzubpj&Pvr+yj=k1qV-SzOCTTmaeBz5HKccvVO6o z9*A^4IN*7Bx9x&79>G1`r{BAjE;U_4OuXkc?-)RLa7YXBrSK$LGrldpD%f8paFZ`l z=6lIl}w~3KGiv?$w2bin*Cb)a;1BpoO~bVG+-Wm%_NuTa8(_>J(GO zx;af#B?lE+s>$3>sM;>R-9EUNFgDeD=>^v#J>+c8jaRO^D|ZPM8|c&2@2b+x^FRT- zPtKe})Irbrq>6-RagE!wRULCwi-fKB88~?!5xceM*a+FW*gMKCcJL#H!g7+%pU>xI zLMVgaoC?vL^hZ`jj>u>w$i=p#Lw6Z(Ul0%ETKpRe;4y{|oMYT+35vVxf_{R?FJ}B2 z<6zaEeCBuG&Q0f znDR8=vf01-pVs@ED@jPu_&C3v2a7}{6=Z!3~MmN=gbrH8iUZ%TRcj_ua z9a4m>i01nS6P)TCj17EXmlE6uN)q*YSZx>TZ@lQop#@R7P~!Y<6($ZHWuy+~=4H|m zWyqmaVFzom{|%T}99gI2*P3X7`9^M%BZQi|XvnD2lT43T>i3Mn>x3QrB)o%@k$qWB zG!5aGV=Lfj4e^cmJnlEw-4;Y{`VN(*+y1*9~BCmQ+CK_@ld_xTU{a5jU) z@}&CN*Px0`} z1E1UP7tF+2UTqF?@((!G<@3Jex)J>v6mY9ItItP}U+Xwj;?XoKgJFix`BNUVqma?? zeJ;g^Og9>S3=VorU2k&)`T;8lT}1Epgql??8_8-7ivcuD58aW{?W^z)rY?hA`7eDB z7wW9r^d{?mkk6>=NGKYIvOQCa5AM6M*+j?m2tgENM2-OqLrVsY!)ZofG65r%J1Rp1i+lm}h7ZjUm8%xTQF4KFp>#**oW;uRA2ymr-@<5p%A1c^?j0kuXd(LfsJ=A@{qH55< ziobZ*ey)T2_k84gDLL#yC+$grJbb@Hf|4&ER!-UhOSGFT5xwX@0+r%+o!Sa%PW73E0k*Ur3-_zj;_yN~;o3SGCL;>@s-ts6#@4sW`OTNoWn1wyeW4aGN(8 z`M?{;GGXQ!QC;mUIhmLHR?g^W+^DqA7uY~(jpNBW$}n(p;|)B}4jxReZ= zH&*Q2x(r4Nw0fIS#q+&gx@$LtSUw5yH&As5BNDECUC1fP%{%10Da8vecw9POq+I~+ z6|P!>1ZL&1FYEoo?>mRr8w`_}FU=(i!J!Bf8O)tW{7@oDnn|`PgHPG#G8a6N6&Ze$ zGr`4ceQvN)Y7oyLoh2jTS)4uYKtDCT94n<)!s7xMMSub3?m>JJ|+tFL8AukG#bp7)#r@!0^i1iaWo_=1K(dhzzFg}wE>2WM`D|{@ybgkOR9I>nSJu;*B&e}gI-CnDBMivAV1u315j6cs9jN4oiTJM-v4U)f z9?1_rc;w~Iv_9kb$Sc4))i87@ zxCMJkcF#f|o54wC;wzsbU3|bh;CdP|4y-b=#eMgm~g?JYcU-m2usYun-6i( z4=*V08ekboVz(MerLiLy_Es2wXB7UK$Lz>dP(@wy`ay}V9~6Rj8i^AFey2X`ud(@l ziH>ZBfrZsRH>u#+$(P>ktvXSOVuCZD721>_A>|j}Xp39WnL%zPOY_S%Y4yv(U^p&R z1k!~AiqA|)eupCa;RQJjbsl*OtFNjpH0g2mh3A;Lc&-l8@hO|ee@LF-dC6PJL>0P8 zdnwBD>3E@?0^W>n>&s+ALuEd}eMWxkTbDidpzFB6bFpv`eX7}+Xwzh(CVJZ_Es=LQ zyQY70USZVCH+^n>qI%_;gx%1J?w9NBeZTie5tmBbn_VRG6Ul^gVK=%fJ_mz+1rF=z zRIWjjx*(!$z4Tvu?)D-W-(4IP-Cf+x>Rf$12O3Q(#AidKd%5B8vVNY+!;Be5;RCum zNcSM1U&V{c^v?0w)a~*{tWdxeYWY4&=6&xr){#tKRl@e1=xo&r(!tzFw>LXM9ZOf!@R(Jd_wHzOAU8AxN}N?Z{jRuzm|5SAN7x~F6tetTtyo}IL? z&49$gs$&KlY%^1Pr#Z-r53^oBoA`_eox3&a`Ak#W$0o5w>zmy&EQ?V(TtVpb9d5fn!wC|j&3p21+kUV4 zP6000WGxldE^w^&spn{Bb{pi?#CN53`%dS?WJGb84?i4OxC@Pes`kn&Xeqg|j&?sm!BA+U?F`WIAgYG^l z79awmEqq2RjK6|L30KFgGnw9i09*WQe)nV$wp{;S+IS6$YWyV)B0e8nUnIaus2`OX zsZhfS^wC&L-8M9Jc-Z1RXtZsv8B^kZE2_BY1vj-BvX$tfAySE~(LxbMGsBZiE{3%y1l&JDWpi2WWi2~U-7t~8BdP8}-;@A*ZndUQI5 zywuRFwvE~Qr%#iZhw|9H$SC{QxwOMpr6ftW`!F-cd(2Yn9=?l3;lH=X@W0|Qx@rCL z+?*pnq*%Cn?I^)#-JCNcS;n(?o{{~Nti4d{zCV#%fyz8cyK&I8bnVxi9jl#XwgZA` zl-nB6bZka0x-(A(p6KDSeANB$L0tm%U{~?pT`Dl{DtKK>!BNHisLq^)CbhuL*pMmQ zAX=OO#VpMM<19}w-2`3%;YrHx#OUhEeoybsBs!WSL$DRob)G-E`Bkx@t|^76(_^G; zac{PPtXO+#vEjU;?dn2DL)tu#@`RLCC!7RPVgHeqV1R1(N90MZ^1RLW7j_V#p-Yr!{9>L<6;ug)kXB<++ZEv|` zJRZlrb#ePJ43wrux!`~G80&fycrtC@dyUSo@EZSfqkEzu-5Bl>?k{!$6B+d6D6&VJ;8d@6`Tm#__t^5g9rv}4=}&Z%>oG5mPfm^{dqLg<*JAH9L3P6$UvLWy z+Pz4}&u0b#5WaF^XqC*?0Ds(KhR?#x&*NKp7Y&TLC3)T}U7fbh^zUNgj1LQE7Tg3~ zrD~SIRYKO!6-p!KlYw1wh7^YLIv>Ph4!b71{>B34zS00K7*UUsE_}hjv%26&%buxv z5rxcvSJ18Fyy^LNGu+3W$?Sn=L1U556CEp)9h^EzU;rpzH@PP!2EPJ1LHB~{KFkN` z#O}gigkfgWnWzg-Bu3Wu`ulbMO_J!S)BW4 z{A#D8!eX#%Wab5mLp2OHR4Qv|dl4I=(kmbTAG*FeEXwT* zSCB?RK~UNv1r&ji9zsA#3F#7p8j#KzN?$P5p z{_b<{KRg5TvG@9Rti9r0?+%4VlMH%j`wT_&f#6##$>8edp`_l}x7BC`uONJczARPz zz0OTYp^Fa4QJe;mo9N(9)zrG27dzi%8Vj=6I!$r%8gU|vyXI!_oQ5DB4y5%hg4Jmg z!<<7C_{rGby#z3HcV|49|7w9d#ydTSV?JI(1XP^VfDniP>z~7Gv^lDU*NHt zUPx~oB!hb|dPH@o;<@zHpH+OvP#=9e1LgE$)t4KYdAtI7#{?4i;Tz*#+9NVqXlruFgI0$&p18teH{o!RgEB?@NK zCv^p7{p(HG4|NdHNsynt8l@cCaQ5eVmlF?XOnDPoA`E0kyZOSCFjJI{CmukX<#?1m zK!A(tv^IO9V+s@_tqV84aOwd=pfa(YqRj<%eH|`Q9{Mt=avGc_-_uKrP6iLtz`1tE zAH{!(RKx!K1>wM;RkrBc+U5k0>MgOk*@B<@#O&rXeB+YTQb?O0gB4_4PI4z^I36<`$Yv+r(<`>6?IHxW~TSvZiuazlD7SEOz& zdp=2f{KLK$U_(FSkJcdL9ss~sLBokCpkebWA)so6Ox?awZucpo-VNJcqPZ#k*_3lJ?9vv$k?Sg_E`fpZi+f zM)4%YE&3ma2j97j%a4MVbn2JablP-`;%0Xx#X++B6unYbzN+nWlFjyb0PE!5<8zha zP>IYL^<6`F^xuxFc4ExFR5N;+`3XR?IKF24Nby1A@|jG{b%4dV4)?L>vhcBe6@Grh zLW4<6J#oJtn39z_Q5NL=kdu-grkYU=qZb`dSU)=(>%5U8ydNSD@RFnadHIV>%gECh zf4OD=b6N)m9d6jROi5yL|^#0<8W3jAQkrNGxtt<7id6_!K z&hY+=TN7`Y&CezJU5+%-o@YM4jHGFDvRq`-jyJgz+tW4OtWu?N&2|iAtHWRod&==& z`Lm0sGfvU=O|`#_3aV=^OhMDF?O4v>(KNko!QJ{D zSq(&&!b8^)E8kjqR_428!gkWR#i^dKLRL{0HbRK@1aUcWbzLq;L4lUNI{Vd^ijbHl zXkeRVpen_6CT;SN66P{tQ4J`RIQMvPd$0_vG87Zf9c>QvPv)mHL+WwIqcDY?m(QK! zh3DS9FH5|S?8lp%sZ?ZAf{=_3+R<*|Ecfu&``?Onk7aL+g%$9d0quQ9?qs`vA+e(z zoXR}855QKD1zO1yM-jsnj@3!_axQbM9^=l;F`L!Lt5Y=QAhYd`t3kLd#aTpD8kHin zdN96gv-tgZWh(%6Q1e*lfjC}s#_ypH*cbgh4;(8-F-P)Iv*4nNwNg(1gry3Hq1;Zm zi6s)2JK={7<8V)J8{b@p^!aSw{M_=bU<`x%bW*Ews#qdt3?g>aCESP>Lyf}*GKV~3 z^9C#$8(%y6%9P5TtI|e`dcAe5wKU4RS1|4*VPhUFfO)(NBZFCF_eK9)YwYz11^%TW zrh(j0(z;TI41Zxh}0&M)NU}#p?@WvV>h=j?H=Da$4|9ywZL;hWpyA%4Im%R`s-_&v-YTgbJXJG{8ZH7pfy-e)W zis#E>v(u9GPV>z~2sB!o-e!fYvep8lLj!ZQ&#yX2R)bTT|8al%68=P!(=Dx+Ndt10 zpKb%7a6QYB>JI?OasVD{e4-EbY^IZF_N*~w|EJDMjHWo8L4M=LV?5UL@HnNT%xZf@ zZUt?>cH>AH`myOoZ=IbB-MlVF?3#%8x?81cTmRHkS)u_`?a-RBCja;11xsbSd1`on z;0sl%2}wv4I5&S;{H8!~`i^!QXUB5^p0oyY)n-Dn6vOf3FeJp0s;rbnV*HdUAx!a; zfkGw1t+_DbBUkyU**9&)YfH!+5h> zjZ0&*;et_M0dxmAQa#8`td@@=2B9f>-oyaMtHFW9W(;l*hB|;|Fz{r^{Z2wM!TO;+$Ng9*gn)Aj_01^ znHqBMH!vtdS|}N<;P!CxMXOc(1HjBE89{2CzGfW|P0Hk z;1yIaU8^Hl%fL%aRPSs!*e+}1DxYb6E_8a{zKr6ANsLacB_YhGm>tg>&KrfP*{$*P3Y7G-sG)E-cy~hY7DfHgPgL z;JpMFn2s@M&76=m%uHus7|llj;>xNrvFbwlv$#xUT7$XuvARtvmg+j_Q5* zf=^~hI?nSw=;EaiU2O_e$h~cyLH$(r*e5{?o7G+For$2(H zpp&pK-cnYBp&EfzHjV-`qvJlAqS}F2xq0wO;8m4@yJ(p*10$R1Fk=sjFw}i%i6DU0 zFjhTowIG0R{Ilk@7m^1m%6FtZwlZ>Pt~0j?JKwU zw5@M>#5?hO;jg>9rfk_=bJ69Z{1rY&5KV0IWj8BtRqHU0pUbsY*{TFVYmhH#OaN-2~Asb@$rwPOHn^wD19!_pR}{{@EF*?J`WUQ|DgOT)2=WM zEqLF)aI_;?WFRf1_0`@djnKXCz_s#>RM%l~t)BAV{Ko9DRv&5W$xJK##B+JvTMUx8 zdd0?)goc$}7ec;N@$ft$+-OL2zv~_p64(Tl?|YH9FLjRh$6?c?!|VfJl1{!9kI;y< zA$LamczS;#cSq8Pg|1L{lS5at2DaS#wLKJhwSbLz&Np`@9D-o&r;3p1O;UBjp2*t7 zzfKIm7nZ5;Enh#PiQ9iC$#DSzOvx`r>dnb%=hC07j(dyy;}5xA*Bg&D$_U8o0)xl9 zodQKunOi087hw+5&zOhP2?+MhU1rF@)UDorPRJ^fOszCIQRKU??^4EfM-{lSMP!`w zjfZ~UK0z(}uAMJQ6kDzg3A+)m1*%@w8l>4p?r_S9e!mEIZWWwsCsKb2?#8NW98s3#vT`V9ogD(ZJutzIbM z0$zsQ{C+E3UhLXtA=w8<+A4W9qWgrZ1^^Di+6|3T)tK|XPr@|i(w}0oIZqV$kvjV* zRWw)dgQr3rsa}u#n65-YL9KBneu>kwG+9ZLWOy+B3ZOr{$T~L;#lVTP>6d9~8 zljw}my-|JA4!nMzBQriDySSzL5qbYEumv5}+|}75>9xR_J7ZKhm)lP4Il1?d{mG~E znVjt!IL6_uA#lsLA_$uZT=k0XAt3RGEgD@#ZV>`Nz~-Lp)=IcJr2NXOellyk{QgT! zj(?9tu;2hu5U7{Cu}5(M$NBXA4gX^K;MIzv#=@hy23c4mKv0u`^RwY_U9Hv{J8##v-!5Q=}Y{thMxq9II;d3Kr#DuU})lAIy^DG(Tdb6#Cw54=VNvYa)8 zqhR2rN%fd>T-Cnkix|{r?0C&r)K$MN&Oa+!FxYO4ga2BzC8TZ~yo+pivmL@$Tshxm zR5X@EUfGZdYJ42?9v^W76D4?B6#%>CeVAj#1+{MVKpZveghIot>)GkFW_^kAXLukuqBRMVi z%MQR>KVmk$_QlRlvzSiqa9lui#Wna^K+gU6OzkxKW4d>ADa+zv?TSmj zt@-Kv;?_a98&+}t&a!EEf#$W%F)*A&-><#7g!yP+SltDYo=ozZxssP_tSzRI zj87Bq z9}S2wKWn9PaNKV|GRjp=?3^=j`9=ZM_4`+F)Ke~_)^r9cZ;z81)%opA49*RMI-QuD zQl4tA<`*H6OvZLOSJW3?kXh<9^JSSjf(7v^xp!LVk(iB*T7}GuTj0T$@U5fRsw>M{h5m@$bZ-Ys!TMtoWr>aJK}XAMk;2`98KAySZET39SlST$je@P5^uB-4i5M>TpB z1Eju5C~a5uo=ZKLHhz!R^D0%Gw_{CSJHcNb11qZ-co4P|H82~LnP&v)NlH4I%~u`L zNYQ0-uc4}MC&D9KQD%{7VE$?`vwA) z_RO(iFLf^MSy>uc0SA238$?LcN za|0XX)Pv4*)kw5e)BVZQ6yX7qq61fyyMlY(xGftonFoeE^jt1r?%%%p#F?};$Nv%w z#q08*Lh^XwA674fxQQhpjBXr!>0Pn0SxFX46)(n0QtAiw8l)RFGTgDjeZJR&7b?f} z$bh!X+|ndemz|<#RJeY}`Soxe>EQHn`z6#U!OJkK$+yBnX)g}VnrwD#$%E?5RK=pQ zAp;9OL;W?g;hhj0meEt7^RVP-8#xBwF|#tOElmFEX=m(IH7yNp z+M@w+A5C|0P;l0Ge55>_6Z?$Jsw@q$Je}mrQ97uJ2UQYZL6yV<;QpxP`|cF>sEzUS z$^fG%hvR5fAGQISyvAq{&QbM$SN<{=1{Io^C? zY=VyVevl@8eV*c-g`7#TqK$iF^dBxv?IjumkIv8C|HF<=y6kw)AST!Wc+k=J_a?D) zpDhJx6f%i(aKVG{pbhnf_{_69s5W>TR7_Iz2DMMCR7MudbBZz$jVE1ytu&j$jee8v2?XGBOR|v0`_=-jag0kBsnF3&9y8;uF`B^eb(SxJ$Tp7J zrVM%8yYWHpIcvbG+TWhQz_P42*ZfV>H1SFor#ZyZiP$sb$M|gad!&SmWp>6JCO^sB z9p()9G#uw-aXiXd2p3G$&WgA10XlQo#84cB)nM-Nr#SeP^7($v^l{Y8%2UtqhC5I zC>Rx?IG)5PAE%M?`eyZx*J*DjoTtb}Xt!JHR=()$-B@Ps&hEK;PzsVP-DlPT1ox=} zILNZ+_$`Lkd{A|CCZ87qnUdpkbKquL-2_m&3F-|CDC?3Reo>aG3&I0# z?i{GgEf?&M1O*D+nl>VrhSZ7-c`MEWn8F4UQ<4ZaBY>3jpD99+&$$k=sENdTUkSnIu=xo?MVAysap zSP}4P*H8CV&u1JaE-)C3@6h0xwszv|&2<}7>A$?$_gvj`&oMCI*f&{Nlh&T8?;~hD zvJ-$WirqHGA{>dOU6!!eAn4B({M`n!$q@= zUv*1FB>j|&$_A(_q%=%6Nc1x5$v{Bqf<+r+Swa9*me?+Baa^ZeoCAGh^yT+Pcuk{k zjFsJ2el@`jEIKz=Q7=yKfp^B|xohl(WJ&RH)|M~rX|q@Q(*qVPfXDo^89APL#$a)+ zFvAa3BZh|ufz7|4IfKH~2N@W|t?vj4DqJT3L^6e(0br8=N5FhV2P)Cf&%T6D?@;#m`@n=gkD_>iu%b6@ou> zEpRXlUh&39Lv)fcYXKs{7{p2?c6l(RFI=gj%?dblgyl|5WTwIx)D&b{ypp)TIw+|h3ZwAie8)O(W_^N4XFaKReS`o!N*{Xi<@Vw7z+`{o3ItlGXHD6gD6S^=}ijAf05GE}FSRD)lK2lQk) zNXh2qp}Obk9ZXIT9l;^Y8hz(8CFOCw^A+J($?tblwU-P`S?IOvb3D5RRza*pJ%lQL zScI6k1#H0#?N?O-5}HGCRD$Opl!VWy7I2DcK~v5V$J~HwpOTqT0wdB-;br8u?^~!S zS6Xzz2T_;Q2#;43HwM@AOgw=YHxd6HH>%4i%dZsFf=Njw6T(_Iik>+J#Tim&Pbl!{ zdxeP(G)l#!VxMZyrGI+yI#6<{?$p?f2D^FiiI?EcD^x|v045Nt3oO4bN(x33=mL^# z`z1Vqx0Uk{KL2(b%S2XEe|79e?v3@^T0-8I$(?6FXuYHpISznXlq8eh3$ytVGkXvg z^H`dvv9!?H)GHT;+inH;0U+N^l0m-gl%9gY2(sSBR?_5%t@XO$CG`AI%fk2b1~&&) zZ{-F^=H%v~)XWCw+%m_+&JziUF!f>L7mg<$mIULK&x(wS-x&k$$L!E~UVp05OpAl; zU@iFpD#=LqNpks((bleQ3PuGeYHiTo^TJI2;LT0X{6^dNOlYobIVyJHpBK0Svrp0U z77%tX*Cw&uiogS;_Jo^gWpbR0_1oLyN&XB2rhf0gG>HQkB#7$*1RZk5GKFjLNuStl z6gLf%*J^z1Xyt-VWYNta@7~59Z-jJ{^x98)?W~uQ2F9Hl++$^oZZ#oqC&AUU~I=04~MD?Q*22I`dc$_3f;Z;&X;e|$@l_8bI8`6 zOcjj+HIa!>9DTbII4jhnN63Kr(XP#9v-`NpyS_WVc4VPHp#5R859NKbzz@_cde=c;rFFN9<)>mPdWie2k;}Iqdj7c(!M^y#(;DDHjh>j|D zs`h<{F%^?0=zGihDvODP(v&+lp!At+QA}W5Q=Su>(?agbyA0B+p|XD*BBLyk4wFME z9qt&1h~|pl16y`EC6JhO0=n$O>;M8B8Z;oe)onlTgBp~?Wi6Z0bAmBdl~G}t=QT6Q znHK*VXE2rMDO-|>f7FF6`5IZc>5DjucBC7UpvqYmE!tO=Kd?1l$nAOPUd3-C>&}^Z znj$Zt5GCo^9N%y)L(Tue>v6L`v4AnE7R@Lu9VxroT8k{lPlF_&m0}F$=gt9W?d2)4 zf#Pq27u=ly7Q~!g-#U(kbd?o3YO@GE<_J`vpeF|^>~&Z`p(hJ(cK!BH z6|Y-CzZlqWN&YhWPXt7~?uI68_gdp3l%ZJ=|2#WAp#m$I+9VXR3|OOl@Mw66F}VX=wkJi(~2NNnV0 zvAB8eu0E}NpWkeOVGtBg{QeaEoIm4zg1V#!1ri?$sq0u6eSr8~Z&}mTz3?=5Ivq5l zn!4|3N|iDIvB9#wb*8Ue3k5Z!b5AQsQS?T%A%i3*q>m-Dm)`-ir6yCsZoyP{?4z_X zv83Ff=F5Az)^E^34;1`+`J023?tNAj$#IHigT)!I@fJy1=qD3Ij|hN91OI;6Zy4hm zy>Yj_O!(STqHb9drqI^5ZR*@0kKpa%hS!9%R;Tpy?EZ#U=^9Uq#NpCH++7K?gz0+!EDX>L@kY$_p3LXMA+4)vlSym*6UV{Vk!1Pu{2Njb%DQrd`X8 zX3*mLlQW!y<~k;s^_T`Kg*Y(?<-^)cLtKW-7vJTrOIHWPv(X7u^0m6(GqxQK$C8(% zkKdV@xRNB|%U$2sld*eam4@6N`4;O-5>2pvsg%2b-YUl@MQ*PN2KyMU`QsZNtSrw& zPA1-4n=~gI9q-D@bDCosugq%5A!mU;f$&k;%2KW1-o6Ls{jB5I-an6}P@Va@A;j|fHMHvqzV?U1it$4&vUhZc==G5u=Vbf1O*biS7p#Lm67y)bY1i3JYKT!oJETlBy7J!i}>!t^0{mp z`e1JjTMPm!_Bj!(B^ld~KAOWcpQTKkZ&`mYIjv=H=wGIXv8g8`(bED``}B}x(kEV0 z>Z|)3?6VY(;R8;KwJ8hhS-7C_SYsp|RCCL1g;WsVQ%7~E z)JA(qESy+?>MlUF8$}PvbUxNqdk#UUx?#;VE2Q!K0LC7+bl$>qP*w8pgmyONd$W;3#lmX+2 zaSd>b{b33lD2&N_TUfm>v_nG-iTbW4bduVL0gF=4aA&S;D@9 zI+K3plsZW=EqqA_aB2M3gW%6ClpvH+w|5ydpeF zF92eY_w^GV5KaMT3L`PwNx}!hmM4&f)b5~%H+^}is^{7_LKaF`4}P6pN=hkb-gcaj zzY;CtO)wq)Jb#~f)U77RT9~4ZP1l-A#>au9m@R5tg!;)Y)!D@%d#T#3VQRB;QXW;L z7YsA^FH^|N=%(sDVExrsCYa1GWtJUGzg|d}`0B4(B#PPqj?q+FiHsYIuLo*l`AFD3 zX{6T64&Pb(9GoPnFR%{%UM59ILbcz9x<@EzXDyn!zf#cN0cNxWdjO!G0Mgyz`gB2r zfGuUXQX&7Jv?l`JQj#RP$S)uzrx*w2vr@LGuBg$IQ#GF8`|q9FZ-X;3VPu4oAY+Ot zF&p#0Z~LdE8DS``+9eQOv`vtp`giPq%>vYiD3;*I{GO0#LR%tDu7-rBL`d7k{`X<< z*cXccHsxF3sbBm$e>(W}5`-ebe})-oWVF{_&*O5MEl(qAHlcC5N{(?fBq*J6UDV(CAq)H3ve-j zhXmxvfmofVxw8I0O_c#}@%cUPH^zT8L{AZRV(G8<<(dJqE7hI24faa3azNUzCH(gf z=pkwQ1>zWPFc29rH~0Rf|02jn3Cbe=6*JolY!-ez;|VZS^jwkuZ<$UIk5YkQC^$Dp zn4CY)K=(*hiT?c!{C!RkbT|2wz!lcQ#D(}<{$CwFZ#*FZ>H+$xK~bHLYsBB%I)nPP z|KHD31Ohwb0x!wi0B9X)JNw_g{CZ8ovH~VFBN)-=_jBGn`s;r?`92l@QeywSB^MK6 z8-6&~K|er?%*hbsX{6%oh`971TrUxWDj zdoDcj96e#*YJlZFK0ZSI-%?+J3JUZ9Ad} z;K={g^A}Yh`?<5+Mtu1viZA>%+5an52M}J*Whsh4vh`~zrIe7g3;x{@P}MI%e|+cE zTW<%{{k=5*rzL{p4@|POwub+N$Y7Wv)K&d07b$^TE+s+f9&g~C@C9t1a9N@U7W>)6 zsopr})Z8y^`&*2!!~h%n0$01XU1;VrYy`(uVjjgv++yPZ(I7Bq>&)86@_lhBh-Zh^ zm&rgC-(|w;&nfG$|3>20oX(mx6_l`4yZx=*>1?*Z`-7uc;di1-Qh-5&lSMukpES3_ zDZMq=?6FczK9VATa#z{n(iJ8~1t6*d?-_Dp8WMD+1sdQBb6QexXI>};*S{Cc{4^VR zJV0Pw@ZFtG-9A`rWZu+f=|-g}0zwOrQ$R$$s?|V>14fJTh31kjAt!zPg7KQ+0_Kv{ z3E$lfy%yT1fQyBq@7mDIY74^>Cd((tGE6=ZuVs? zO}W|@QEavA@kdY|@Lns0NhALG>2`|%Nh$y4`z_ipC4FC9iOokvrpu;r$!#q3mcF@^ z{1LFhJoAx;PS;x!Z{9ikN<{Ybo2WxlP1)+k3HZ*eU#nLtc>r<`r1Y z$47OFOso+sTW=>22kx2HHkJDKjJkztSCoBMicyDQUbsDghPko5IpBmQq}t%y5`8sp zquR(be|Bu(2a4Xvs-eM$U5SrZTsAA>^sz~&;lu}REf(90@Cnz8e#Y-K z7QNk2=hCJCYo01ql?`Z@pTxSE>SeX7EN|J^`e?SNnmp0mNH_aUnn1wlV`5+6zS4e4 ztLzrDS^f;}1QeJT6i+~%5cojF*mp_5-2dp=gB}3yw*f^u<}OK;zrK1xy=X$(#_k#K zzEl#Zwx}g{WN87{uX9SQ4*sFzOwh%J?H%;s+%kqnGWl$N3w8MX^yg}yK+$-IrbI@g zV8iYi$0RVr|0>X+Pa}aA2y^EfOs5pLgfija>f>qxS^D^| z*v%zBhN~}{l;jB^SBgt-xU@NlWIE^f7LqF(;B;kXp14O+xWS?A5o-ZJJSe+*{s8bp z#*16+6O}d7j&Y)y4kEg>m1t zg4OeQ^rJYln$hcRn-x6CY)OZ6brtsfbI3{f&cvkb@gW2A(NoIfQlKbC?CgB1`~;3& zytan?kq!F`;&;5yi?5hhPOy8LCY$Ek0vNQ&8x5D>Q#_gK?;n69_8pgH5b4LL)0k|po7=q$w))6)=o-w< zi9bme?jhD&I~-IIkIn-8Ox0l~xO=cPk00I(TcyYN9Wzt|%qt;eV=r?jzjVKbGfZ#H z_3JwnZgU{gb}*JhuHol)Tu<$vSb#NGGv8Z*2jt!_hAWj+|hoPefn`@SIhDKK{HR=}IUOw){PZSj7+CB71C`L|` z1`<>1o#o~D!1wyZH?G$?0SKFw5o_NueFL+p2J=knknKbn-wOE8mdALSK})IKDRV^I zR^IA|0(Y9=hIqiO*$ZfQq%E_OeA1T~l+hMrN84jpE7w56&lV`H`tb8NIwNFjT0>~- zyTL4GYm9e?B*7sM+Ru7)TzQNxYQ)dPX8H0d`S|ZW%mgqSdvUwLFptla15HQo_u5DrA2ahG%Id z+tJDSHDWk$xJpus5}<^;@joMj0p-^&`cVajmP2ZrMz^gVU5TaWUk{NVW4>5F+X{C8 zhieXBA+^xWZW?u78p))HpYzC~cyvB^J8;vawBOdyV{Tn`!^ryahjH~9>}oaS+G8Lx z`u*(GB1N>~R2yewWtgyR^H5iAmYxM4d#;mv(ea=zU2Vt`S#E>fU?b_mNigO&+ZiU?*nx| zE|zH}_j3O%z!BUvcx+Fvzek}9;Ko`<%d@pYw*e?H6DXwyR|>X)VV|

AFL5?Jx!huLla|e^LT2M@TE%96*E@8d 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 literal 0 HcmV?d00001 diff --git a/gradle.properties b/gradle.properties index de6dee01..63920ed6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.36 +version = 7.8.37 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java new file mode 100644 index 00000000..cfe92cb3 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java @@ -0,0 +1,51 @@ +package de.monticore.lang.sysmlv2._symboltable; + +import de.monticore.lang.sysmlimportsandpackages._ast.ASTSysMLImportStatement; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.symboltable.ImportStatement; +import de.se_rwth.commons.logging.Log; + +import java.util.ArrayList; +import java.util.stream.Collectors; + +public class SysMLv2ScopesGenitor extends SysMLv2ScopesGenitorTOP { + + /** + * Hook point for the first phase of the artifact scope initialization. + * This method is invoked by the generated {@code createFromAST} method + * before the AST traversal (visit/handle) begins. + * It is used to populate the {@link ISysMLv2ArtifactScope} with information + * extracted directly from the root node, such as the package name and + * import statements. + *

Implementation Note: This implementation maps SysMLv2 import statements + * to MontiCore {@link ImportStatement} objects. Please note that recursive + * imports are currently handled and represented as wildcard (star) imports + * within the symbol table.

+ * @param artifactScope the artifact scope currently being initialized. + */ + @Override + protected void initArtifactScopeHP1(ISysMLv2ArtifactScope artifactScope) { + super.initArtifactScopeHP1(artifactScope); + + if(!artifactScope.isPresentAstNode() || + !(artifactScope.getAstNode() instanceof ASTSysMLModel)) { + // We do only initialize scopes created in createFromAST, which do have + // an ast-node and are build upon a ASTSysMLModel. + // For other cases we do abort. This line is not expected to be reached. + Log.info("Initializing artifacts-scope build from non ASTSysMLModel", + SysMLv2ScopesGenitor.class.getName()); + return; + } + + var importsList = ((ASTSysMLModel) artifactScope.getAstNode()) + .getSysMLElementList() + .stream() + .filter(e -> e instanceof ASTSysMLImportStatement) + .map(e -> (ASTSysMLImportStatement) e) + .map(i -> + new ImportStatement(i.getMCQualifiedName().getQName(), + i.isStar() || i.isRecursive())) + .collect(Collectors.toCollection(ArrayList::new)); + artifactScope.setImportsList(importsList); + } +} diff --git a/language/src/test/java/symboltable/ImportResolveTest.java b/language/src/test/java/symboltable/ImportResolveTest.java new file mode 100644 index 00000000..180e7afb --- /dev/null +++ b/language/src/test/java/symboltable/ImportResolveTest.java @@ -0,0 +1,285 @@ +package symboltable; + +import de.monticore.lang.sysmlimportsandpackages._ast.ASTSysMLPackage; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; +import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ImportResolveTest { + + /** + * Tests the general resolution of FQN without using imports. + * That is the main downstream feature the import-tests rely on, because + * while processing the resolve by imports we do try to resolve their FQNs. + * + * @throws IOException Mills parser exception, shall not happen + */ + @Test() + public void testFQNResolving() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { part def Parent; }"; + var model = "part def Child : Other.Parent;"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ast.getSysMLElement(0); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.printType(); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); + assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); + } + + /** + * Tests direct SysML Import "Other::Parent" on root level of the + * SysML-Model / resolve through ArtifactsScope + * + * @throws IOException Mills parser exception, shall not happen + */ + @Test() + public void testArtifactsScopeImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { part def Parent; }"; + var model = "private import Other::Parent; part def Child : Parent;"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ast.getSysMLElement(1); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); + } + + /** + * Tests star/wildcard SysML Import "Other::*" on root level of the + * SysML-Model / resolve through ArtifactsScope + * + * @throws IOException Mills parser exception, shall not happen + */ + @Test() + public void testArtifactsStarImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { part def Parent; }"; + var model = "private import Other::*; part def Child : Parent;"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ast.getSysMLElement(1); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); + } + + /** + * Recursive Imports are currently not handled by our implementation. + * Tests recursive SysML Import "Other::**" on root level of the + * SysML-Model / resolve through ArtifactsScope. + * + * @throws IOException Mills parser exception, shall not happen + */ + @Disabled("Recursive Imports are currently unsupported in our implementation") + @Test() + public void testArtifactsScopeRecursiveImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { package InnerOther { part def Parent; } }"; + var model = "private import Other::**; part def Child : Parent;"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ast.getSysMLElement(1); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.InnerOther.Parent"); + } + + /** + * Tests direct SysML Import "Other::Parent" within a SysML-Namespace / + * resolve through SysMLsScope + * + * @throws IOException Mills parser exception, shall not happen + */ + @Disabled("WIP") + @Test() + public void testSysMLScopeImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { part def Parent; }"; + var model = "package test { private import Other::Parent; part def Child : Parent; }"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ((ASTSysMLPackage) ast.getSysMLElement(0)).getSysMLElement(1 ); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); + } + + /** + * Tests star/wildcard SysML "Other::*" within a SysML-Namespace / + * resolve through SysMLsScope + * + * @throws IOException Mills parser exception, shall not happen + */ + @Disabled("WIP") + @Test() + public void testSysMLScopeStarImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { part def Parent; }"; + var model = "package test { private import Other::*; part def Child : Parent; }"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ((ASTSysMLPackage) ast.getSysMLElement(0)).getSysMLElement(1 ); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); + } + + /** + * Recursive Imports are currently not handled by our implementation. + * Tests star/wildcard SysML Import "Other::**" within a SysML-Namespace / + * resolve through SysMLsScope + * + * @throws IOException Mills parser exception, shall not happen + */ + @Disabled("Recursive Imports are currently unsupported in our implementation") + @Test() + public void testSysMLScopeRecursiveImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { package InnerOther { part def Parent; } }"; + var model = "package test { private import Other::**; part def Child : Parent; }"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ((ASTSysMLPackage) ast.getSysMLElement(0)).getSysMLElement(1 ); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.InnerOther.Parent"); + } + +} From ced16225ca5360553bef86d6f61f8e1bb85dcd49 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 22 Apr 2026 14:49:05 +0200 Subject: [PATCH 41/50] Implement Imports for Type Symbols (#107) * prototype for supporting imports within sysmlscopes * rework on basis of ast traversal for import collecting, removing interfaces * removing imports from artifacts-scopes to prevent duplicate resolution with sysmlv2scopes * import-resolution tests changed to type based resolution instead of specific ones * migrated resolution logics to continueWithEnclosingScope->calcQNamesForEnclosingScope to reduce unecessary replacement of resolveTypeDefMany * cleanup of first iteration test leftovers * removing debug logs from tests --------- Co-authored-by: Justus R --- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 3 -- .../sysmlv2/_symboltable/ISysMLv2Scope.java | 41 +++++++++++++++++-- .../_symboltable/SysMLv2ScopesGenitor.java | 37 ----------------- .../java/symboltable/ImportResolveTest.java | 11 +++-- 4 files changed, 42 insertions(+), 50 deletions(-) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index e73655f9..3b637e83 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -24,7 +24,6 @@ import de.monticore.lang.sysmlv2._symboltable.ISysMLv2GlobalScope; import de.monticore.lang.sysmlv2._symboltable.SysMLv2Symbols2Json; import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; -import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck3; import de.monticore.lang.sysmlv2.cocos.ConnectedPortsFitCoCo; import de.monticore.lang.sysmlv2.cocos.EventTransitionRequiresAccept; import de.monticore.lang.sysmlv2.cocos.FlowCheckCoCo; @@ -36,10 +35,8 @@ import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo; import de.monticore.lang.sysmlv2.cocos.RefinementCyclic; import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; -import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck3; import de.monticore.lang.sysmlv2.cocos.StateSupertypes; import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; -import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; import de.monticore.lang.sysmlv2.cocos.ValidCausalityTimingCoCo; import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 328a6565..d350c14c 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -11,8 +11,9 @@ import de.monticore.lang.sysmlconstraints._ast.ASTRequirementUsage; import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; import de.monticore.lang.sysmlconstraints.symboltable.adapters.RequirementSubject2VariableSymbolAdapter; -import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLMetaDataDefinitionSymbol; +import de.monticore.lang.sysmlimportsandpackages._ast.ASTSysMLImportStatement; import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLPackageSymbol; +import de.monticore.lang.sysmlimportsandpackages._visitor.SysMLImportsAndPackagesVisitor2; import de.monticore.lang.sysmloccurrences.symboltable.adapters.ItemDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; @@ -28,6 +29,7 @@ import de.monticore.lang.sysmlparts.symboltable.adapters.PortUsage2VariableSymbolAdapter; import de.monticore.lang.sysmlstates._symboltable.StateUsageSymbol; import de.monticore.lang.sysmlstates.symboltable.adapters.StateDef2TypeSymbolAdapter; +import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.symboltable.adapters.AttributeUsage2PortSymbolAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Constraint2SpecificationAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.MetadataDef2TypeSymbolAdapter; @@ -41,19 +43,23 @@ import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; import de.monticore.symboltable.IScopeSpanningSymbol; +import de.monticore.symboltable.ImportStatement; import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionFactory; -import de.se_rwth.commons.Names; +import de.se_rwth.commons.logging.Log; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; +import static de.se_rwth.commons.Names.getSimpleName; + public interface ISysMLv2Scope extends ISysMLv2ScopeTOP { /** @@ -101,7 +107,23 @@ default List continueTypeWithEnclosingScope( && getEnclosingScope() != null ) { - Set potentialNames = calcQNamesForEnclosingScope(name); + var importStatements = new LinkedList(); + if(getEnclosingScope().isPresentAstNode()) { + var visitor = new SysMLImportsAndPackagesVisitor2() { + @Override + public void visit(ASTSysMLImportStatement node) { + if (getEnclosingScope().equals(node.getEnclosingScope())) { + importStatements.add(new ImportStatement(node.getMCQualifiedName().getQName(), + node.isStar() || node.isRecursive())); + } + } + }; + var traverser = SysMLv2Mill.inheritanceTraverser(); + traverser.add4SysMLImportsAndPackages(visitor); + getEnclosingScope().getAstNode().accept(traverser); + } + + Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); for (String potentialName : potentialNames) { result.addAll(getEnclosingScope().resolveTypeMany( foundSymbols, @@ -121,10 +143,21 @@ && getEnclosingScope() != null * Java-like out-of-the-box and needs to be extended for SysMLv2's usage * of packages (namespaces) as proper modeling elements. */ - default Set calcQNamesForEnclosingScope(String name) { + default Set calcQNamesForEnclosingScope(String name, + List importStatements) { Set potentialSymbolNames = new LinkedHashSet<>(); potentialSymbolNames.add(name); + // qualified names based on the import statements of enclosing scope + for (var importStatement : importStatements) { + if (importStatement.isStar()) { + potentialSymbolNames.add(importStatement.getStatement() + "." + name); + } + else if (getSimpleName(importStatement.getStatement()).equals(name)) { + potentialSymbolNames.add(importStatement.getStatement()); + } + } + if ( this.isPresentSpanningSymbol() && this.getSpanningSymbol() instanceof SysMLPackageSymbol diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java index cfe92cb3..66007190 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java @@ -10,42 +10,5 @@ public class SysMLv2ScopesGenitor extends SysMLv2ScopesGenitorTOP { - /** - * Hook point for the first phase of the artifact scope initialization. - * This method is invoked by the generated {@code createFromAST} method - * before the AST traversal (visit/handle) begins. - * It is used to populate the {@link ISysMLv2ArtifactScope} with information - * extracted directly from the root node, such as the package name and - * import statements. - *

Implementation Note: This implementation maps SysMLv2 import statements - * to MontiCore {@link ImportStatement} objects. Please note that recursive - * imports are currently handled and represented as wildcard (star) imports - * within the symbol table.

- * @param artifactScope the artifact scope currently being initialized. - */ - @Override - protected void initArtifactScopeHP1(ISysMLv2ArtifactScope artifactScope) { - super.initArtifactScopeHP1(artifactScope); - if(!artifactScope.isPresentAstNode() || - !(artifactScope.getAstNode() instanceof ASTSysMLModel)) { - // We do only initialize scopes created in createFromAST, which do have - // an ast-node and are build upon a ASTSysMLModel. - // For other cases we do abort. This line is not expected to be reached. - Log.info("Initializing artifacts-scope build from non ASTSysMLModel", - SysMLv2ScopesGenitor.class.getName()); - return; - } - - var importsList = ((ASTSysMLModel) artifactScope.getAstNode()) - .getSysMLElementList() - .stream() - .filter(e -> e instanceof ASTSysMLImportStatement) - .map(e -> (ASTSysMLImportStatement) e) - .map(i -> - new ImportStatement(i.getMCQualifiedName().getQName(), - i.isStar() || i.isRecursive())) - .collect(Collectors.toCollection(ArrayList::new)); - artifactScope.setImportsList(importsList); - } } diff --git a/language/src/test/java/symboltable/ImportResolveTest.java b/language/src/test/java/symboltable/ImportResolveTest.java index 180e7afb..8568bc63 100644 --- a/language/src/test/java/symboltable/ImportResolveTest.java +++ b/language/src/test/java/symboltable/ImportResolveTest.java @@ -85,7 +85,7 @@ public void testArtifactsScopeImport() throws IOException { var parentName = parentRef.getNameList().get(0); - var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolveType(parentName); assertThat(optParent).isPresent(); // check if we did resolve assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); @@ -122,7 +122,7 @@ public void testArtifactsStarImport() throws IOException { var parentName = parentRef.getNameList().get(0); - var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolveType(parentName); assertThat(optParent).isPresent(); // check if we did resolve assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); @@ -173,7 +173,7 @@ public void testArtifactsScopeRecursiveImport() throws IOException { * * @throws IOException Mills parser exception, shall not happen */ - @Disabled("WIP") + // @Disabled("WIP") @Test() public void testSysMLScopeImport() throws IOException { LogStub.init(); @@ -199,7 +199,7 @@ public void testSysMLScopeImport() throws IOException { var parentName = parentRef.getNameList().get(0); - var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolveType(parentName); assertThat(optParent).isPresent(); // check if we did resolve assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); @@ -211,7 +211,6 @@ public void testSysMLScopeImport() throws IOException { * * @throws IOException Mills parser exception, shall not happen */ - @Disabled("WIP") @Test() public void testSysMLScopeStarImport() throws IOException { LogStub.init(); @@ -237,7 +236,7 @@ public void testSysMLScopeStarImport() throws IOException { var parentName = parentRef.getNameList().get(0); - var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolveType(parentName); assertThat(optParent).isPresent(); // check if we did resolve assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); From a02f93211eadfdd9be4d1f25bde580be7e637a90 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 22 Apr 2026 16:03:03 +0200 Subject: [PATCH 42/50] 7.8.38 SysMLScopes resolving by imports for Functions and Variables (#108) * prototype for supporting imports within sysmlscopes * rework on basis of ast traversal for import collecting, removing interfaces * cleanup of first iteration test leftovers * removing debug logs from tests * added continueVariableWithEnclosing, continueFunctionWithEnclosing * Version bump to 7.8.38 * formatting --------- Co-authored-by: Justus R --- gradle.properties | 2 +- .../sysmlv2/_symboltable/ISysMLv2Scope.java | 113 ++++++++++++++++-- 2 files changed, 107 insertions(+), 8 deletions(-) diff --git a/gradle.properties b/gradle.properties index 63920ed6..e10d8b5b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.37 +version = 7.8.38 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index d350c14c..71eecaa9 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -39,6 +39,7 @@ import de.monticore.lang.sysmlv2.symboltable.adapters.StateUsage2AutomatonAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.StateUsage2EventAutomatonAdapter; import de.monticore.lang.componentconnector._symboltable.RequirementSymbol; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; @@ -58,6 +59,7 @@ import java.util.Set; import java.util.function.Predicate; +import static de.se_rwth.commons.Names.getQualifier; import static de.se_rwth.commons.Names.getSimpleName; public interface ISysMLv2Scope extends ISysMLv2ScopeTOP { @@ -137,6 +139,98 @@ public void visit(ASTSysMLImportStatement node) { return new ArrayList<>(result); } + /** + * @see ISysMLv2Scope#continueTypeWithEnclosingScope(boolean, String, AccessModifier, Predicate) + */ + @Override + default List continueVariableWithEnclosingScope( + boolean foundSymbols, + String name, + AccessModifier modifier, + Predicate predicate + ) { + final LinkedHashSet result = new LinkedHashSet<>(); + if ( + checkIfContinueWithEnclosingScope(foundSymbols) + && getEnclosingScope() != null + ) { + + var importStatements = new LinkedList(); + if(getEnclosingScope().isPresentAstNode()) { + var visitor = new SysMLImportsAndPackagesVisitor2() { + @Override + public void visit(ASTSysMLImportStatement node) { + if (getEnclosingScope().equals(node.getEnclosingScope())) { + importStatements.add(new ImportStatement(node.getMCQualifiedName().getQName(), + node.isStar() || node.isRecursive())); + } + } + }; + var traverser = SysMLv2Mill.inheritanceTraverser(); + traverser.add4SysMLImportsAndPackages(visitor); + getEnclosingScope().getAstNode().accept(traverser); + } + + Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); + + for (String potentialName : potentialNames) { + result.addAll(getEnclosingScope().resolveVariableMany( foundSymbols, + potentialName, + modifier, + predicate) + ); + } + } + + return new ArrayList<>(result); + } + + /** + * @see ISysMLv2Scope#continueTypeWithEnclosingScope(boolean, String, AccessModifier, Predicate) + */ + @Override + default List continueFunctionWithEnclosingScope( + boolean foundSymbols, + String name, + AccessModifier modifier, + Predicate predicate + ) { + final LinkedHashSet result = new LinkedHashSet<>(); + if ( + checkIfContinueWithEnclosingScope(foundSymbols) + && (getEnclosingScope() != null) + ) { + + var importStatements = new LinkedList(); + if(getEnclosingScope().isPresentAstNode()) { + var visitor = new SysMLImportsAndPackagesVisitor2() { + @Override + public void visit(ASTSysMLImportStatement node) { + if (getEnclosingScope().equals(node.getEnclosingScope())) { + importStatements.add(new ImportStatement(node.getMCQualifiedName().getQName(), + node.isStar() || node.isRecursive())); + } + } + }; + var traverser = SysMLv2Mill.inheritanceTraverser(); + traverser.add4SysMLImportsAndPackages(visitor); + getEnclosingScope().getAstNode().accept(traverser); + } + + Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); + + for (String potentialName : potentialNames) { + result.addAll(getEnclosingScope().resolveFunctionMany( foundSymbols, + potentialName, + modifier, + predicate) + ); + } + } + + return new ArrayList<>(result); + } + /** * This method is essentially copied from artifact scopes. See explanation * on continueTypeWithEnclosingScope(4): MontiCore's symbol resolution is @@ -148,13 +242,18 @@ default Set calcQNamesForEnclosingScope(String name, Set potentialSymbolNames = new LinkedHashSet<>(); potentialSymbolNames.add(name); - // qualified names based on the import statements of enclosing scope - for (var importStatement : importStatements) { - if (importStatement.isStar()) { - potentialSymbolNames.add(importStatement.getStatement() + "." + name); - } - else if (getSimpleName(importStatement.getStatement()).equals(name)) { - potentialSymbolNames.add(importStatement.getStatement()); + // if name is already qualified, no further (potential) names exist by imports + if (getQualifier(name).isEmpty()) { + // qualify names based on the import statements of enclosing scope + // 1. qualify star imports by replacing the start with symbolname + // 2. qualify direct imports when the name matches + for (var importStatement : importStatements) { + if (importStatement.isStar()) { + potentialSymbolNames.add(importStatement.getStatement() + "." + name); + } + else if (getSimpleName(importStatement.getStatement()).equals(name)) { + potentialSymbolNames.add(importStatement.getStatement()); + } } } From 3d7ad5d1d5c36f0802caebfae0be46cbe0573890 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Fri, 24 Apr 2026 12:14:04 +0200 Subject: [PATCH 43/50] 7.8.39 Corrected adaptedResolve for CC-Requirements in ISysMLScope (#101) * followup on correct resolveAdapted for CC-Requirements in ISysMLScope * Version bump to 7.8.39 --- gradle.properties | 2 +- .../lang/sysmlv2/_symboltable/ISysMLv2Scope.java | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index e10d8b5b..5547598f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.38 +version = 7.8.39 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 71eecaa9..3c13281b 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -270,16 +270,19 @@ else if (getSimpleName(importStatement.getStatement()).equals(name)) { } @Override - default List resolveRequirementLocallyMany( + default List resolveAdaptedRequirementLocallyMany( boolean foundSymbols, - String name, AccessModifier modifier, + String name, + AccessModifier modifier, Predicate predicate) { var adapted = new ArrayList(); - var req = resolveRequirementUsageLocally(name); + var usages = resolveRequirementUsageLocallyMany(foundSymbols, name, modifier, x -> true); - if(req.isPresent()) { - var ccReq = new Requirement2RequirementCCAdapter(req.get()); - adapted.add(ccReq); + for(var req : usages) { + var ccAdaptedReq = new Requirement2RequirementCCAdapter(req); + if(predicate.test(ccAdaptedReq)) { + adapted.add(ccAdaptedReq); + } } return adapted; From 5d577e485175ae448c5e942a5c10a28177822280 Mon Sep 17 00:00:00 2001 From: Jana Nefedova <116279327+JanaNefedova@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:44:08 +0200 Subject: [PATCH 44/50] =?UTF-8?q?ScalarValues-Importe=20werden=20im=20Symb?= =?UTF-8?q?oltable=20unterst=C3=BCtzt=20(#110)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ScalarValues-Importe werden im Symboltable unterstützt * update version * fix test --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Mill.java | 63 +++++++++++++++++++ .../java/symboltable/SerializationTest.java | 7 ++- .../SymbolTableCompletionTest.java | 28 +++++++++ 4 files changed, 96 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5547598f..0b6b41dc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.39 +version = 7.8.40 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java index 42c13525..fbd95d84 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java @@ -13,12 +13,14 @@ import de.monticore.symbols.oosymbols.OOSymbolsMill; import de.monticore.symbols.oosymbols._symboltable.OOSymbolsScope; import de.monticore.symbols.oosymbols._symboltable.OOTypeSymbol; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.types.check.SymTypeExpressionFactory; import de.monticore.types.check.SymTypePrimitive; import de.monticore.types.check.SymTypeVariable; import java.util.Arrays; +import java.util.List; import static de.monticore.symbols.basicsymbols.BasicSymbolsMillTOP.getMill; @@ -31,6 +33,7 @@ public class SysMLv2Mill extends SysMLv2MillTOP { public static void prepareGlobalScope() { SysMLv2Mill.initializePrimitives(); SysMLv2Mill.addStringType(); + SysMLv2Mill.addScalarValueTypes(); SysMLv2Mill.addCollectionTypes(); SysMLv2Mill.addTsynVariables(); } @@ -61,6 +64,10 @@ public static void addStringType() { getMill()._addStringType(); } + public static void addScalarValueTypes() { + getMill()._addScalarValueTypes(); + } + protected void _addStringType() { // ensures adding the type symbol only once if (SysMLv2Mill.globalScope().resolveType("String").isPresent()) { @@ -75,6 +82,62 @@ protected void _addStringType() { SysMLv2Mill.globalScope().add(type); } + protected void _addScalarValueTypes() { + if (SysMLv2Mill.globalScope().resolveSysMLPackage("ScalarValues").isPresent()) { + return; + } + + var packageScope = SysMLv2Mill.scope(); + packageScope.setName("ScalarValues"); + packageScope.setEnclosingScope(SysMLv2Mill.globalScope()); + var scalarValues = SysMLv2Mill.sysMLPackageSymbolBuilder() + .setName("ScalarValues") + .setFullName("ScalarValues") + .setPackageName("") + .setEnclosingScope(SysMLv2Mill.globalScope()) + .setSpannedScope(packageScope) + .build(); + packageScope.setSpanningSymbol(scalarValues); + SysMLv2Mill.globalScope().add(scalarValues); + + var scalarValue = createScalarValueType(packageScope, "ScalarValue"); + var bool = createScalarValueType(packageScope, "Boolean"); + var numericalValue = createScalarValueType(packageScope, "NumericalValue"); + var number = createScalarValueType(packageScope, "Number"); + var complex = createScalarValueType(packageScope, "Complex"); + var real = createScalarValueType(packageScope, "Real"); + var rational = createScalarValueType(packageScope, "Rational"); + var integer = createScalarValueType(packageScope, "Integer"); + var natural = createScalarValueType(packageScope, "Natural"); + var positive = createScalarValueType(packageScope, "Positive"); + + setScalarValueSuperTypes(bool, scalarValue); + setScalarValueSuperTypes(numericalValue, scalarValue); + setScalarValueSuperTypes(number, numericalValue); + setScalarValueSuperTypes(complex, number); + setScalarValueSuperTypes(real, complex); + setScalarValueSuperTypes(rational, real); + setScalarValueSuperTypes(integer, rational); + setScalarValueSuperTypes(natural, integer); + setScalarValueSuperTypes(positive, natural); + } + + protected OOTypeSymbol createScalarValueType(ISysMLv2Scope packageScope, String name) { + var type = OOSymbolsMill.oOTypeSymbolBuilder() + .setName(name) + .setFullName("ScalarValues." + name) + .setPackageName("ScalarValues") + .setEnclosingScope(packageScope) + .setSpannedScope(scope()) + .build(); + packageScope.add(type); + return type; + } + + protected void setScalarValueSuperTypes(OOTypeSymbol type, OOTypeSymbol superType) { + type.setSuperTypesList(List.of(SymTypeExpressionFactory.createTypeObject(superType))); + } + protected OOTypeSymbol buildOptionalType() { var typeVar = BasicSymbolsMill.typeVarSymbolBuilder().setName("T").build(); diff --git a/language/src/test/java/symboltable/SerializationTest.java b/language/src/test/java/symboltable/SerializationTest.java index a88c1450..004b710e 100644 --- a/language/src/test/java/symboltable/SerializationTest.java +++ b/language/src/test/java/symboltable/SerializationTest.java @@ -135,7 +135,7 @@ public void loadSymbolTableAndResolve( String usageSymbol) { ASTSysMLModel ast = sysmlTool.parse(modelReferencePath); - sysmlTool.createSymbolTable(ast); + ISysMLv2ArtifactScope artifactScope = sysmlTool.createSymbolTable(ast); var symbolPath = new MCPath(); // MCPath entries correspond to the directories that contain symboltables @@ -149,8 +149,9 @@ public void loadSymbolTableAndResolve( // check if an additional ArtifactScope was found during completion (Specialization completion uses inter-model resolution) Assertions.assertThat(gs.getSubScopes()).size().isGreaterThan(1); - // check inter-model resolution of fqn from usage package scope. - ISysMLv2Scope packageScope = gs.getSubScopes().get(0).getSubScopes().get(0); + // check inter-model resolution of fqn from the package scope of the reference artifact. + Assertions.assertThat(artifactScope.getSubScopes()).isNotEmpty(); + ISysMLv2Scope packageScope = artifactScope.getSubScopes().get(0); Optional resolved = packageScope.resolveSysMLType(fqnSymbol); assertThat(resolved).isPresent(); diff --git a/language/src/test/java/symboltable/SymbolTableCompletionTest.java b/language/src/test/java/symboltable/SymbolTableCompletionTest.java index de00586f..82a84595 100644 --- a/language/src/test/java/symboltable/SymbolTableCompletionTest.java +++ b/language/src/test/java/symboltable/SymbolTableCompletionTest.java @@ -2,6 +2,7 @@ import de.monticore.expressions.commonexpressions._ast.ASTCallExpression; import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; import de.monticore.lang.sysmlparts._ast.ASTPartDef; import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; @@ -250,6 +251,33 @@ public void testAtTime() throws IOException { assertThat(type.getResult().printFullName()).isEqualTo("UntimedStream.UntimedStream"); } + @Test + public void testImportedScalarValueCompletesAttributeTypes() throws IOException { + var model = "" + + "private import ScalarValues::Boolean;\n" + + "private import ScalarValues::Natural;\n" + + "attribute flag: Boolean;\n" + + "attribute size: Natural;"; + + Optional optAst = parser.parse_String(model); + assertThat(optAst).isPresent(); + + var ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + assertThat(Log.getFindings()).isEmpty(); + + var flag = (ASTAttributeUsage) ast.getSysMLElement(2); + var size = (ASTAttributeUsage) ast.getSysMLElement(3); + + assertThat(flag.getSymbol().getTypesList()).hasSize(1); + assertThat(flag.getSymbol().getTypesList().get(0).printFullName()).isEqualTo("ScalarValues.Boolean"); + assertThat(size.getSymbol().getTypesList()).hasSize(1); + assertThat(size.getSymbol().getTypesList().get(0).printFullName()).isEqualTo("ScalarValues.Natural"); + } + /** * TODO Eigentlich weniger Completion und mehr TypeCheck * Checkt, dass "\in" richtig gecheckt wird From 8c6a83ca06802d473a49c3cf67b2a19c42e99846 Mon Sep 17 00:00:00 2001 From: linggd <99347985+linggd@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:56:50 +0200 Subject: [PATCH 45/50] Add typecheck test for SysML calc defs as function symbols (#99) * Add test for calc defs as functions * treat CalcUsage as function symbol with the help of adapter * Handle calc return types in TypesCompleter * change calc def to calc usage since we are actually dealing with usage in this model * move ad-hoc visitor into TypesCompleter and added adapter documentation * documentation formatting * typo fix --------- Co-authored-by: ling guo dei --- .../de/monticore/lang/SysMLActions.mc4 | 2 +- .../_symboltable/CalcUsageSymbol.java | 19 +++++ .../CalcUsage2FunctionSymbolAdapter.java | 60 +++++++++++++++ .../monticore/lang/sysmlv2/SysMLv2Tool.java | 1 + .../sysmlv2/_symboltable/ISysMLv2Scope.java | 16 ++++ .../completers/TypesCompleter.java | 46 +++++++++++- .../typecheck/CalcUsageAsFunctionsTest.java | 75 +++++++++++++++++++ 7 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcUsageSymbol.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcUsage2FunctionSymbolAdapter.java create mode 100644 language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java diff --git a/language/src/main/grammars/de/monticore/lang/SysMLActions.mc4 b/language/src/main/grammars/de/monticore/lang/SysMLActions.mc4 index 8134990d..c83db31a 100644 --- a/language/src/main/grammars/de/monticore/lang/SysMLActions.mc4 +++ b/language/src/main/grammars/de/monticore/lang/SysMLActions.mc4 @@ -225,7 +225,7 @@ component grammar SysMLActions Expression? "}" | ";") ; - symbol CalcUsage implements SysMLElement = + symbol scope CalcUsage implements SysMLElement = Modifier UserDefinedKeyword* "calc" SysMLIdentifier? Name? SysMLCardinality? Specialization* DefaultValue? ("{" diff --git a/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcUsageSymbol.java b/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcUsageSymbol.java new file mode 100644 index 00000000..59d558ef --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcUsageSymbol.java @@ -0,0 +1,19 @@ +package de.monticore.lang.sysmlactions._symboltable; + +import de.monticore.types.check.SymTypeExpression; + +public class CalcUsageSymbol extends CalcUsageSymbolTOP { + protected SymTypeExpression returnType; + + public CalcUsageSymbol(String name) { + super(name); + } + + public SymTypeExpression getReturnType() { + return returnType; + } + + public void setReturnType(SymTypeExpression returnType) { + this.returnType = returnType; + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcUsage2FunctionSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcUsage2FunctionSymbolAdapter.java new file mode 100644 index 00000000..dbf8dcc9 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcUsage2FunctionSymbolAdapter.java @@ -0,0 +1,60 @@ +package de.monticore.lang.sysmlparts.symboltable.adapters; + +import com.google.common.base.Preconditions; +import de.monticore.lang.sysmlactions._symboltable.CalcUsageSymbol; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; +import de.se_rwth.commons.SourcePosition; + +/** + * Adapts a SysML {@link CalcUsageSymbol} to a MontiCore {@link FunctionSymbol}. + * + * MontiCore's expression type checker resolves function calls against + * {@link FunctionSymbol}s from BasicSymbols. SysML calc usages, however, are represented by + * {@link CalcUsageSymbol}s. This adapter exposes a calc usage as a function symbol so that + * expressions such as {@code f.bar()} can be resolved and type-checked using the existing + * function-call infrastructure. + */ +public class CalcUsage2FunctionSymbolAdapter extends FunctionSymbol { + protected CalcUsageSymbol adaptee; + + public CalcUsage2FunctionSymbolAdapter(CalcUsageSymbol adaptee) { + super(Preconditions.checkNotNull(adaptee.getName())); + this.adaptee = adaptee; + + setAccessModifier(adaptee.getAccessModifier()); + + IBasicSymbolsScope spannedScope = BasicSymbolsMill.scope(); + spannedScope.setName(adaptee.getName()); + spannedScope.setShadowing(true); + spannedScope.setEnclosingScope(adaptee.getEnclosingScope()); + setSpannedScope(spannedScope); + + setType(adaptee.getReturnType()); + } + + protected CalcUsageSymbol getAdaptee() { + return adaptee; + } + + @Override + public String getName() { + return adaptee.getName(); + } + + @Override + public String getFullName() { + return adaptee.getFullName(); + } + + @Override + public IBasicSymbolsScope getEnclosingScope() { + return adaptee.getEnclosingScope(); + } + + @Override + public SourcePosition getSourcePosition() { + return adaptee.getSourcePosition(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 3b637e83..376e4f0c 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -216,6 +216,7 @@ public void completeSymbolTable(ASTSysMLModel node) { traverser.add4SysMLBasis(completer); traverser.add4SysMLParts(completer); traverser.add4SysMLConstraints(completer); + traverser.add4SysMLActions(completer); traverser.add4SysMLParts(new RequirementClassificationCompleter()); traverser.add4SysMLParts(new DirectRefinementCompleter()); diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 3c13281b..b6bfd67d 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -22,6 +22,7 @@ import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeUsage2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeUsage2VariableSymbolAdapter; +import de.monticore.lang.sysmlparts.symboltable.adapters.CalcUsage2FunctionSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.EnumDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.PartDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.PartUsage2TypeSymbolAdapter; @@ -665,4 +666,19 @@ default Optional filterPartUsage( return getResolvedOrThrowException(resolvedSymbols); } + @Override + default List resolveAdaptedFunctionLocallyMany( + boolean foundSymbols, + String name, + AccessModifier modifier, + Predicate predicate + ) { + var adapted = new ArrayList(); + + var calcUsage = resolveCalcUsageLocally(name); + if (calcUsage.isPresent()) { + adapted.add(new CalcUsage2FunctionSymbolAdapter(calcUsage.get())); + } + return adapted; + } } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index 8b9247a5..58d84b62 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -1,6 +1,9 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.lang.sysmlv2.symboltable.completers; +import de.monticore.lang.sysmlactions._ast.ASTCalcUsage; +import de.monticore.lang.sysmlactions._symboltable.CalcUsageSymbol; +import de.monticore.lang.sysmlactions._visitor.SysMLActionsVisitor2; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousReference; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousUsage; import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; @@ -13,12 +16,12 @@ import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; import de.monticore.lang.sysmlconstraints._visitor.SysMLConstraintsVisitor2; import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; -import de.monticore.lang.sysmlparts._ast.ASTEnumDef; import de.monticore.lang.sysmlparts._ast.ASTPartUsage; import de.monticore.lang.sysmlparts._ast.ASTPortUsage; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; +import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; import de.monticore.symboltable.modifiers.BasicAccessModifier; @@ -32,7 +35,7 @@ import java.util.List; public class TypesCompleter implements SysMLBasisVisitor2, SysMLPartsVisitor2, - SysMLConstraintsVisitor2 + SysMLConstraintsVisitor2, SysMLActionsVisitor2 { /** @@ -146,6 +149,45 @@ public void visit(ASTAttributeUsage node) { } } + @Override + public void endVisit(ASTCalcUsage node) { + if (node.isPresentSymbol()) { + CalcUsageSymbol symbol = node.getSymbol(); + final SymTypeExpression[] returnType = new SymTypeExpression[1]; + + var traverser = SysMLv2Mill.inheritanceTraverser(); + traverser.add4SysMLBasis(new SysMLBasisVisitor2() { + @Override + public void visit(ASTAnonymousUsage retNode) { + // Store only the first return type declared directly in calc usage + if (returnType[0] == null + && retNode.getModifier().isReturn() + && retNode.getEnclosingScope() == node.getSpannedScope()) { + List types = getTypeCompletion(retNode.getSpecializationList(), false); + returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); + } + } + }); + + traverser.add4SysMLParts(new SysMLPartsVisitor2() { + @Override + public void visit(ASTAttributeUsage retNode) { + if (returnType[0] == null + && retNode.getModifier().isReturn() + && retNode.getEnclosingScope() == node.getSpannedScope()) { + List types = getTypeCompletion(retNode.getSpecializationList(), false); + returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); + } + } + }); + node.accept(traverser); + + if (returnType[0] != null) { + symbol.setReturnType(returnType[0]); + } + } + } + @Override public void endVisit(ASTAnonymousUsage node) { if(node.isPresentSymbol()) { diff --git a/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java new file mode 100644 index 00000000..294c915f --- /dev/null +++ b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java @@ -0,0 +1,75 @@ +package typecheck; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * This class checks the implementation of SysML calc usages + * as MontiCore function symbols. MontiCore establishes the + * set of basic symbols as types, variables, and functions. + * This is different from the plethora of SysML keywords that + * are not meaningful for symbol resolution (and specifically + * not relevant for type checking). + */ +public class CalcUsageAsFunctionsTest { + + @Test + public void testValid() throws Exception { + LogStub.init(); + Log.clearFindings(); + + var model = "attribute def Foo { calc bar { return : boolean; } } \n" + + "attribute f: Foo; \n" + + "constraint { f.bar() } \n"; + + SysMLv2Tool tool = new SysMLv2Tool(); + tool.init(); + + var parser = SysMLv2Mill.parser(); + var ast = parser.parse_String(model).get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.checkAll(ast); + + assertTrue(Log.getFindings().isEmpty(), ()-> Log.getFindings().toString()); + } + + @Test + void testInvalid() throws Exception { + LogStub.init(); + Log.clearFindings(); + + var model = "attribute def Foo { calc bar { return : nat; } } \n" + + "attribute f: Foo; \n" + + "constraint { f.bar() } \n"; + + SysMLv2Tool tool = new SysMLv2Tool(); + tool.init(); + + var parser = SysMLv2Mill.parser(); + var ast = parser.parse_String(model).get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.checkAll(ast); + + assertThat(Log.getFindings()).hasSize(1); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x80002 The expression type is 'nat' but should be boolean!"); + } +} From edf21b982954dd145fcd290fb736a96a28c8b29e Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 29 Apr 2026 13:28:23 +0200 Subject: [PATCH 46/50] 7.8.39 Only resolve first symbol from enclosing scope, updated docs for import-resolving (#111) * fixing resolve logics from PR/97 to stop resolving in enclosing scopes after a matching symbol was found * resolve by imports: adapted (java-) & docs * Version bump to 7.8.41 --------- Co-authored-by: Justus R --- doc/ImporteUndResolvingDocs.md | 32 ++++++++--------- gradle.properties | 2 +- .../sysmlv2/_symboltable/ISysMLv2Scope.java | 35 ++++++++++++------- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/doc/ImporteUndResolvingDocs.md b/doc/ImporteUndResolvingDocs.md index b3b46331..c6fe12fc 100644 --- a/doc/ImporteUndResolvingDocs.md +++ b/doc/ImporteUndResolvingDocs.md @@ -1,10 +1,9 @@ # Dokumentation: Import-Mechanismus und Namensauflösung In der MontiCore-basierten Implementierung von SysMLv2 ist die effiziente Auflösung von Symbolen über Modellgrenzen hinweg entscheidend. Da Modelle in der -Regel in Pakete unterteilt sind, benötigt der `ArtifactScope` einen Mechanismus, -um lokale Referenzen auf externe Symbole (Cross-References) korrekt zuzuordnen. -Dies betrifft in der aktuellen Implementierung so nur Imports auf root-Ebene -eines Modells. Eine Fortsetzung hierfür folgt. +Regel in Pakete unterteilt sind, benötigt der `SysML-Scope` einen Mechanismus, +um lokale Referenzen auf externe Symbole (Cross-References) auch auf Basis der +im Scope vorhandenen Importen korrekt zuzuordnen. ## 1. SysMLv2 Import-Typen SysMLv2 definiert verschiedene Strategien, um Elemente aus anderen Namensräumen @@ -43,18 +42,21 @@ Das folgende Diagramm illustriert, welche Elemente je nach Import-Strategie für den aktuellen Scope "sichtbar" werden: ![SysML-Import-Typen-Visualisiert](sysmlv2-imports.png) -## 3. Technische Umsetzung im ArtifactScope -Die Namensauflösung basiert auf der Delegation vom lokalen `ArtifactScope` an -den `GlobalScope`. Der zentrale Mechanismus ist dabei die Generierung von -Kandidaten-Namen. +## 3. Technische Umsetzung im SysMLv2-Scope +Die Namensauflösung basiert auf der Delegation eines SysML-Scopes an seinen +umschließenden-Scope. Diese delegation erfolgt innerhalb der Funktion +continueXXXWithEnclosing Scope. Das Import-Unterstützte resolving ist hierbei +für Variablen, Typen und Funktionen implementiert. ### Die Methode `continuePartDefWithEnclosingScope` -Wenn ein Symbol (z. B. eine `PartDef`) lokal nicht gefunden wird, ruft MontiCore -diese Methode auf. Sie berechnet eine Menge von voll-qualifizierten Namen (FQNs), -nach denen der `GlobalScope` suchen soll. +Wenn ein Symbol (Variablen, Typen oder Funktionen) lokal nicht gefunden wird, +ruft MontiCore diese Methode auf. Sie berechnet eine Menge von voll-qualifizierten +Namen (FQNs), nach denen im umschließendem Scope gesucht werden. Gesucht wird +hierbei nach dem Namen selbst, dem Namen innerhalb des aktuellen Pakets, +und dem Namen in allen spezifizierten Imports ### Namensqualifizierung mit `calculateQualifiedNames` -Diese Methode nutzt die im `ArtifactScope` hinterlegten `ImportStatements`. +Diese Methode nutzt die im `ASTSysMLScope` hinterlegten `SysMLImportStatements`. Sie prüft für jeden Import: 1. **Bei Wildcards:** Ist der gesuchte Name ein Kind des importierten Pakets? \ (z.B. `ImportPfad + "." + gesuchterName`) @@ -73,11 +75,7 @@ for (ImportStatement importStatement : imports) { ``` ### SysMLv2ScopesGenitor -Um die Namensqualizifierung zu ermöglichen, inizialisieren wir die Imports des -ArtifactsScopes innerhalb des ScopesGenitors. Wir verwenden die Hookpoint -`initArtifactScopeHP1`, um vor der Genitor-Traversierung des AST sicherzustellen, -dass der ArtifactScope vollständig konfiguriert ist und Import- Auslösungen -potentiell verfügbar sind. +Die Symbole der SysML-Scopes werden aktuell nicht mit den Importen initialisiert. ## 4. Einschränkungen und Roadmap Da `calculateQualifiedNames` in aktuellen MontiCore-Versionen als `@deprecated` diff --git a/gradle.properties b/gradle.properties index 0b6b41dc..28212dbd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.40 +version = 7.8.41 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index b6bfd67d..9f56b85a 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -129,11 +129,13 @@ public void visit(ASTSysMLImportStatement node) { Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); for (String potentialName : potentialNames) { - result.addAll(getEnclosingScope().resolveTypeMany( foundSymbols, - potentialName, - modifier, - predicate) + var resolvedEnclosing = getEnclosingScope().resolveTypeMany( foundSymbols, + potentialName, + modifier, + predicate ); + result.addAll(resolvedEnclosing); + foundSymbols = foundSymbols || !resolvedEnclosing.isEmpty(); } } @@ -175,11 +177,13 @@ public void visit(ASTSysMLImportStatement node) { Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); for (String potentialName : potentialNames) { - result.addAll(getEnclosingScope().resolveVariableMany( foundSymbols, - potentialName, - modifier, - predicate) + var resolvedEnclosing = getEnclosingScope().resolveVariableMany( foundSymbols, + potentialName, + modifier, + predicate ); + result.addAll(resolvedEnclosing); + foundSymbols = foundSymbols || !resolvedEnclosing.isEmpty(); } } @@ -221,11 +225,13 @@ public void visit(ASTSysMLImportStatement node) { Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); for (String potentialName : potentialNames) { - result.addAll(getEnclosingScope().resolveFunctionMany( foundSymbols, - potentialName, - modifier, - predicate) + var resolvedEnclosing = getEnclosingScope().resolveFunctionMany( foundSymbols, + potentialName, + modifier, + predicate ); + result.addAll(resolvedEnclosing); + foundSymbols = foundSymbols || !resolvedEnclosing.isEmpty(); } } @@ -237,6 +243,11 @@ public void visit(ASTSysMLImportStatement node) { * on continueTypeWithEnclosingScope(4): MontiCore's symbol resolution is * Java-like out-of-the-box and needs to be extended for SysMLv2's usage * of packages (namespaces) as proper modeling elements. + * Also, the Scopes-Included Imports are used for potential name qualification. + * Therefore: 1. Matching, direct Imports are taken as FQNs + * 2. Star and recursive Imports do try to resolve the import + * where the wildcard is replaced by the resolved Symbols name. + * Therefore, recursive imports are only supported as star-imports. */ default Set calcQNamesForEnclosingScope(String name, List importStatements) { From 5d21a42f114f44c05bddcd4d7cc5ca98d0977eb8 Mon Sep 17 00:00:00 2001 From: linggd <99347985+linggd@users.noreply.github.com> Date: Wed, 29 Apr 2026 13:31:01 +0200 Subject: [PATCH 47/50] Add CoCo to check number of direct return in CalcUsage (#112) Co-authored-by: ling guo dei --- .../cocos/OneDirectReturnInCalcUsageCoCo.java | 46 +++++++++++++++++++ .../completers/TypesCompleter.java | 19 +++----- .../typecheck/CalcUsageAsFunctionsTest.java | 3 ++ 3 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java new file mode 100644 index 00000000..2458f998 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java @@ -0,0 +1,46 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlactions._ast.ASTCalcUsage; +import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTCalcUsageCoCo; +import de.monticore.lang.sysmlbasis._ast.ASTAnonymousUsage; +import de.monticore.lang.sysmlbasis._visitor.SysMLBasisVisitor2; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.se_rwth.commons.logging.Log; + +/** + * Checks that a calc usage contains at most one direct return usage. + * Nested return usages are ignored. + */ +public class OneDirectReturnInCalcUsageCoCo implements SysMLActionsASTCalcUsageCoCo { + @Override + public void check(ASTCalcUsage node) { + final int[] returnCount = {0}; + var traverser = SysMLv2Mill.inheritanceTraverser(); + + traverser.add4SysMLBasis(new SysMLBasisVisitor2() { + @Override + public void visit(ASTAnonymousUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + returnCount[0]++; + } + } + }); + + traverser.add4SysMLParts(new SysMLPartsVisitor2() { + @Override + public void visit(ASTAttributeUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + returnCount[0]++; + } + } + }); + + node.accept(traverser); + + if (returnCount[0] > 1) { + Log.error("0x10384 Calc usage must contain at most one direct return usage.", node.get_SourcePositionStart()); + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index 58d84b62..a6670fd2 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -2,7 +2,6 @@ package de.monticore.lang.sysmlv2.symboltable.completers; import de.monticore.lang.sysmlactions._ast.ASTCalcUsage; -import de.monticore.lang.sysmlactions._symboltable.CalcUsageSymbol; import de.monticore.lang.sysmlactions._visitor.SysMLActionsVisitor2; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousReference; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousUsage; @@ -152,17 +151,16 @@ public void visit(ASTAttributeUsage node) { @Override public void endVisit(ASTCalcUsage node) { if (node.isPresentSymbol()) { - CalcUsageSymbol symbol = node.getSymbol(); + // Use a one-element array because Java does not allow reassigning local variables + // from inside anonymous visitor classes final SymTypeExpression[] returnType = new SymTypeExpression[1]; + returnType[0] = SymTypeExpressionFactory.createTopType(); var traverser = SysMLv2Mill.inheritanceTraverser(); traverser.add4SysMLBasis(new SysMLBasisVisitor2() { @Override public void visit(ASTAnonymousUsage retNode) { - // Store only the first return type declared directly in calc usage - if (returnType[0] == null - && retNode.getModifier().isReturn() - && retNode.getEnclosingScope() == node.getSpannedScope()) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { List types = getTypeCompletion(retNode.getSpecializationList(), false); returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); } @@ -172,19 +170,14 @@ public void visit(ASTAnonymousUsage retNode) { traverser.add4SysMLParts(new SysMLPartsVisitor2() { @Override public void visit(ASTAttributeUsage retNode) { - if (returnType[0] == null - && retNode.getModifier().isReturn() - && retNode.getEnclosingScope() == node.getSpannedScope()) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { List types = getTypeCompletion(retNode.getSpecializationList(), false); returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); } } }); node.accept(traverser); - - if (returnType[0] != null) { - symbol.setReturnType(returnType[0]); - } + node.getSymbol().setReturnType(returnType[0]); } } diff --git a/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java index 294c915f..045db4f7 100644 --- a/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java +++ b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java @@ -4,6 +4,7 @@ import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; +import de.monticore.lang.sysmlv2.cocos.OneDirectReturnInCalcUsageCoCo; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.Test; @@ -41,6 +42,7 @@ public void testValid() throws Exception { SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.addCoCo(new OneDirectReturnInCalcUsageCoCo()); checker.checkAll(ast); assertTrue(Log.getFindings().isEmpty(), ()-> Log.getFindings().toString()); @@ -67,6 +69,7 @@ void testInvalid() throws Exception { SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.addCoCo(new OneDirectReturnInCalcUsageCoCo()); checker.checkAll(ast); assertThat(Log.getFindings()).hasSize(1); From f06723afae84f60aa13c316a2286af2deaf05d37 Mon Sep 17 00:00:00 2001 From: linggd <99347985+linggd@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:32:44 +0200 Subject: [PATCH 48/50] treat calc def as function symbol (#118) * treat calc def as function symbol * formatting * formatting again * formatting again2 --------- Co-authored-by: ling guo dei --- .../_symboltable/CalcDefSymbol.java | 19 +++++ .../CalcDef2FunctionSymbolAdapter.java | 60 +++++++++++++++ .../sysmlv2/_symboltable/ISysMLv2Scope.java | 7 +- .../MaxOneDirectReturnInCalcDefCoCo.java | 46 +++++++++++ ...=> MaxOneDirectReturnInCalcUsageCoCo.java} | 2 +- .../completers/TypesCompleter.java | 35 ++++++++- .../java/typecheck/CalcDefAsFunctionTest.java | 77 +++++++++++++++++++ .../typecheck/CalcUsageAsFunctionsTest.java | 6 +- 8 files changed, 246 insertions(+), 6 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcDefSymbol.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcDef2FunctionSymbolAdapter.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcDefCoCo.java rename language/src/main/java/de/monticore/lang/sysmlv2/cocos/{OneDirectReturnInCalcUsageCoCo.java => MaxOneDirectReturnInCalcUsageCoCo.java} (94%) create mode 100644 language/src/test/java/typecheck/CalcDefAsFunctionTest.java diff --git a/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcDefSymbol.java b/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcDefSymbol.java new file mode 100644 index 00000000..309fbdb9 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcDefSymbol.java @@ -0,0 +1,19 @@ +package de.monticore.lang.sysmlactions._symboltable; + +import de.monticore.types.check.SymTypeExpression; + +public class CalcDefSymbol extends CalcDefSymbolTOP { + protected SymTypeExpression returnType; + + public CalcDefSymbol(String name) { + super(name); + } + + public SymTypeExpression getReturnType() { + return returnType; + } + + public void setReturnType(SymTypeExpression returnType) { + this.returnType = returnType; + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcDef2FunctionSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcDef2FunctionSymbolAdapter.java new file mode 100644 index 00000000..a1f45bb5 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcDef2FunctionSymbolAdapter.java @@ -0,0 +1,60 @@ +package de.monticore.lang.sysmlparts.symboltable.adapters; + +import com.google.common.base.Preconditions; +import de.monticore.lang.sysmlactions._symboltable.CalcDefSymbol; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.se_rwth.commons.SourcePosition; + +/** + * Adapts a SysML {@link CalcDefSymbol} to a MontiCore {@link FunctionSymbol}. + * + * MontiCore's expression type checker resolves function calls against + * {@link FunctionSymbol}s from BasicSymbols. SysML calc def, however, are represented by + * {@link CalcDefSymbol}s. This adapter exposes a calc def as a function symbol so that + * expressions such as {@code f.bar()} can be resolved and type-checked using the existing + * function-call infrastructure. + */ +public class CalcDef2FunctionSymbolAdapter extends FunctionSymbol { + protected CalcDefSymbol adaptee; + + public CalcDef2FunctionSymbolAdapter(CalcDefSymbol adaptee) { + super(Preconditions.checkNotNull(adaptee.getName())); + this.adaptee = adaptee; + + setAccessModifier(adaptee.getAccessModifier()); + + IBasicSymbolsScope spannedScope = BasicSymbolsMill.scope(); + spannedScope.setName(adaptee.getName()); + spannedScope.setShadowing(true); + spannedScope.setEnclosingScope(adaptee.getEnclosingScope()); + setSpannedScope(spannedScope); + + setType(adaptee.getReturnType()); + } + + protected CalcDefSymbol getAdaptee() { + return adaptee; + } + + @Override + public String getName() { + return adaptee.getName(); + } + + @Override + public String getFullName() { + return adaptee.getFullName(); + } + + @Override + public IBasicSymbolsScope getEnclosingScope() { + return adaptee.getEnclosingScope(); + } + + @Override + public SourcePosition getSourcePosition() { + return adaptee.getSourcePosition(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 9f56b85a..5de81787 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -22,6 +22,7 @@ import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeUsage2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeUsage2VariableSymbolAdapter; +import de.monticore.lang.sysmlparts.symboltable.adapters.CalcDef2FunctionSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.CalcUsage2FunctionSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.EnumDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.PartDef2TypeSymbolAdapter; @@ -49,7 +50,6 @@ import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionFactory; -import de.se_rwth.commons.logging.Log; import java.util.ArrayList; import java.util.Arrays; @@ -690,6 +690,11 @@ default List resolveAdaptedFunctionLocallyMany( if (calcUsage.isPresent()) { adapted.add(new CalcUsage2FunctionSymbolAdapter(calcUsage.get())); } + + var calcDef = resolveCalcDefLocally(name); + if (calcDef.isPresent()) { + adapted.add(new CalcDef2FunctionSymbolAdapter(calcDef.get())); + } return adapted; } } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcDefCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcDefCoCo.java new file mode 100644 index 00000000..27a85db5 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcDefCoCo.java @@ -0,0 +1,46 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlactions._ast.ASTCalcDef; +import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTCalcDefCoCo; +import de.monticore.lang.sysmlbasis._ast.ASTAnonymousUsage; +import de.monticore.lang.sysmlbasis._visitor.SysMLBasisVisitor2; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.se_rwth.commons.logging.Log; + +/** + * Checks that a calc def contains at most one direct return. + * Nested return usages are ignored. + */ +public class MaxOneDirectReturnInCalcDefCoCo implements SysMLActionsASTCalcDefCoCo { + @Override + public void check(ASTCalcDef node) { + final int[] returnCount = {0}; + var traverser = SysMLv2Mill.inheritanceTraverser(); + + traverser.add4SysMLBasis(new SysMLBasisVisitor2() { + @Override + public void visit(ASTAnonymousUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + returnCount[0]++; + } + } + }); + + traverser.add4SysMLParts(new SysMLPartsVisitor2() { + @Override + public void visit(ASTAttributeUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + returnCount[0]++; + } + } + }); + + node.accept(traverser); + + if (returnCount[0] > 1) { + Log.error("0x10385 Calc def must contain at most one direct return.", node.get_SourcePositionStart()); + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcUsageCoCo.java similarity index 94% rename from language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java rename to language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcUsageCoCo.java index 2458f998..58783fe4 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcUsageCoCo.java @@ -13,7 +13,7 @@ * Checks that a calc usage contains at most one direct return usage. * Nested return usages are ignored. */ -public class OneDirectReturnInCalcUsageCoCo implements SysMLActionsASTCalcUsageCoCo { +public class MaxOneDirectReturnInCalcUsageCoCo implements SysMLActionsASTCalcUsageCoCo { @Override public void check(ASTCalcUsage node) { final int[] returnCount = {0}; diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index a6670fd2..02b1fe3d 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -1,6 +1,7 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.lang.sysmlv2.symboltable.completers; +import de.monticore.lang.sysmlactions._ast.ASTCalcDef; import de.monticore.lang.sysmlactions._ast.ASTCalcUsage; import de.monticore.lang.sysmlactions._visitor.SysMLActionsVisitor2; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousReference; @@ -29,7 +30,6 @@ import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; import de.monticore.types.mcstructuraltypes._ast.ASTMCTupleType; import de.se_rwth.commons.logging.Log; - import java.util.ArrayList; import java.util.List; @@ -181,6 +181,39 @@ public void visit(ASTAttributeUsage retNode) { } } + @Override + public void endVisit(ASTCalcDef node) { + if (node.isPresentSymbol()) { + // Use a one-element array because Java does not allow reassigning local variables + // from inside anonymous visitor classes + final SymTypeExpression[] returnType = new SymTypeExpression[1]; + returnType[0] = SymTypeExpressionFactory.createTopType(); + + var traverser = SysMLv2Mill.inheritanceTraverser(); + traverser.add4SysMLBasis(new SysMLBasisVisitor2() { + @Override + public void visit(ASTAnonymousUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + List types = getTypeCompletion(retNode.getSpecializationList(), false); + returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); + } + } + }); + + traverser.add4SysMLParts(new SysMLPartsVisitor2() { + @Override + public void visit(ASTAttributeUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + List types = getTypeCompletion(retNode.getSpecializationList(), false); + returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); + } + } + }); + node.accept(traverser); + node.getSymbol().setReturnType(returnType[0]); + } + } + @Override public void endVisit(ASTAnonymousUsage node) { if(node.isPresentSymbol()) { diff --git a/language/src/test/java/typecheck/CalcDefAsFunctionTest.java b/language/src/test/java/typecheck/CalcDefAsFunctionTest.java new file mode 100644 index 00000000..0a2da905 --- /dev/null +++ b/language/src/test/java/typecheck/CalcDefAsFunctionTest.java @@ -0,0 +1,77 @@ +package typecheck; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; +import de.monticore.lang.sysmlv2.cocos.MaxOneDirectReturnInCalcDefCoCo; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * This class checks the implementation of SysML calc defs + * as MontiCore function symbols. MontiCore establishes the + * set of basic symbols as types, variables, and functions. + * This is different from the plethora of SysML keywords that + * are not meaningful for symbol resolution (and specifically + * not relevant for type checking). + */ +public class CalcDefAsFunctionTest { + @Test + public void testValid() throws Exception { + LogStub.init(); + Log.clearFindings(); + + var model = "attribute def Foo { calc def bar { return : boolean; } } \n" + + "attribute f: Foo; \n" + + "constraint { f.bar() } \n"; + + SysMLv2Tool tool = new SysMLv2Tool(); + tool.init(); + + var parser = SysMLv2Mill.parser(); + var ast = parser.parse_String(model).get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.addCoCo(new MaxOneDirectReturnInCalcDefCoCo()); + checker.checkAll(ast); + + assertTrue(Log.getFindings().isEmpty(), ()-> Log.getFindings().toString()); + } + + @Test + void testInvalid() throws Exception { + LogStub.init(); + Log.clearFindings(); + + var model = "attribute def Foo { calc def bar { return : nat; } } \n" + + "attribute f: Foo; \n" + + "constraint { f.bar() } \n"; + + SysMLv2Tool tool = new SysMLv2Tool(); + tool.init(); + + var parser = SysMLv2Mill.parser(); + var ast = parser.parse_String(model).get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.addCoCo(new MaxOneDirectReturnInCalcDefCoCo()); + checker.checkAll(ast); + + assertThat(Log.getFindings()).hasSize(1); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x80002 The expression type is 'nat' but should be boolean!"); + } +} diff --git a/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java index 045db4f7..d50d4fc1 100644 --- a/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java +++ b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java @@ -4,7 +4,7 @@ import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; -import de.monticore.lang.sysmlv2.cocos.OneDirectReturnInCalcUsageCoCo; +import de.monticore.lang.sysmlv2.cocos.MaxOneDirectReturnInCalcUsageCoCo; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.Test; @@ -42,7 +42,7 @@ public void testValid() throws Exception { SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); checker.addCoCo(new ConstraintIsBooleanTC3()); - checker.addCoCo(new OneDirectReturnInCalcUsageCoCo()); + checker.addCoCo(new MaxOneDirectReturnInCalcUsageCoCo()); checker.checkAll(ast); assertTrue(Log.getFindings().isEmpty(), ()-> Log.getFindings().toString()); @@ -69,7 +69,7 @@ void testInvalid() throws Exception { SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); checker.addCoCo(new ConstraintIsBooleanTC3()); - checker.addCoCo(new OneDirectReturnInCalcUsageCoCo()); + checker.addCoCo(new MaxOneDirectReturnInCalcUsageCoCo()); checker.checkAll(ast); assertThat(Log.getFindings()).hasSize(1); From 3c1b4e57b1b1006f830a5d8f115b1ad8cf43042a Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Thu, 30 Apr 2026 22:17:35 +0200 Subject: [PATCH 49/50] 7.8.42: Include StreamTypes in GlobalScope (#122) * prevent Crash during StartUp * load StreamSymbols in GlobalScope during StartUp * version bumb to 7.8.42 --- gradle.properties | 2 +- .../main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java | 1 + .../main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java | 2 +- .../types/SysMLv2DeriveSymTypeOfCommonExpressions.java | 8 ++++++-- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 28212dbd..6a7369e8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.41 +version = 7.8.42 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java index fbd95d84..8375ac2f 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java @@ -36,6 +36,7 @@ public static void prepareGlobalScope() { SysMLv2Mill.addScalarValueTypes(); SysMLv2Mill.addCollectionTypes(); SysMLv2Mill.addTsynVariables(); + SysMLv2Tool.loadStreamSymbolsFromJar(); } /** diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 376e4f0c..f03f1d2e 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -462,7 +462,7 @@ public void run(String[] args) { } } - public void loadStreamSymbolsFromJar() { + public static void loadStreamSymbolsFromJar() { URL streamDefUrl = SysMLv2Tool.class.getClassLoader().getResource( "Stream.symtabdefinitionsym"); diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java index cbacad46..f4cf1a22 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java @@ -78,6 +78,8 @@ protected void calculateFieldAccessAboutPortUsage(SymTypeExpression type) { var streamType = SysMLv2Mill.globalScope().resolveType("EventStream"); if(streamType.isEmpty()) { Log.error("Stream not defined in global scope. Initialize it with 'SysMLv2Mill.addStreamType()'!"); + getTypeCheckResult().setResult(SymTypeExpressionFactory.createObscureType()); + return; } if (type instanceof SymTypeArray) { //for example, type like boolean[], int[]... @@ -158,7 +160,8 @@ protected void calculateFieldAccess(ASTFieldAccessExpression expr, //in superclass is: getTypeCheckResult().setResult(type); if (expr.getExpression() instanceof ASTNameExpression) { //case for expression like f.a,f.a[1] - if (((ASTNameExpression) expr.getExpression()).getDefiningSymbol().get() instanceof PortUsage2VariableSymbolAdapter) { + var definingSymbol = ((ASTNameExpression) expr.getExpression()).getDefiningSymbol(); + if (definingSymbol.isPresent() && definingSymbol.get() instanceof PortUsage2VariableSymbolAdapter) { calculateFieldAccessAboutPortUsage(type); } else { //else-case for SuperClass @@ -169,7 +172,8 @@ protected void calculateFieldAccess(ASTFieldAccessExpression expr, var arrayExpr = expr.getExpression(); if (((ASTArrayAccessExpression) arrayExpr).getExpression() instanceof ASTNameExpression) { var nameExpr = ((ASTArrayAccessExpression) arrayExpr).getExpression(); - if (((ASTNameExpression) nameExpr).getDefiningSymbol().get() instanceof PortUsage2VariableSymbolAdapter) { + var definingSymbol = ((ASTNameExpression) nameExpr).getDefiningSymbol(); + if (definingSymbol.isPresent() && definingSymbol.get() instanceof PortUsage2VariableSymbolAdapter) { calculateFieldAccessAboutPortUsage(type); } else { //else-case for SuperClass From 4b0acb96374554b09613fbe5d34daecbc9b6b2d0 Mon Sep 17 00:00:00 2001 From: ling guo dei Date: Sat, 2 May 2026 15:44:38 +0200 Subject: [PATCH 50/50] create parser test for apollo 11 models --- language/src/test/java/parser/ApolloTest.java | 60 + .../resources/Apollo_11/AnalysisPackage.sysml | 157 +++ .../Apollo11MissionExecutionPackage.sysml | 479 +++++++ .../Apollo_11/AstronautsPackage.sysml | 167 +++ .../Apollo_11/CalculationsPackage.sysml | 149 ++ .../Apollo_11/CapabilitiesPackage.sysml | 156 +++ .../resources/Apollo_11/CoSMAPackage.sysml | 126 ++ .../CoSMAQuantitiesAndUnitsPackage.sysml | 80 ++ .../Apollo_11/CoSMAViewsPackage.sysml | 14 + .../resources/Apollo_11/ContextPackage.sysml | 85 ++ .../FunctionSpecificationPackage.sysml | 243 ++++ .../FunctionalRequirementsPackage.sysml | 945 +++++++++++++ .../Apollo_11/FunctionsPackage.sysml | 528 +++++++ .../Apollo_11/LogicalComponentsPackage.sysml | 89 ++ .../resources/Apollo_11/MissionPackage.sysml | 323 +++++ .../Apollo_11/MissionPhasesPackage.sysml | 154 +++ .../MissionRequirementsPackage.sysml | 673 +++++++++ .../MissionSpecificationPackage.sysml | 113 ++ .../Apollo_11/OperationsPackage.sysml | 137 ++ .../resources/Apollo_11/ProgramPackage.sysml | 107 ++ .../Apollo_11/StakeholderNeedsPackage.sysml | 166 +++ .../Apollo_11/StakeholderPackage.sysml | 225 +++ .../resources/Apollo_11/SystemPackage.sysml | 28 + .../SystemSpecificationPackage.sysml | 247 ++++ .../TechnicalComponentsPackage.sysml | 253 ++++ .../TechnicalIndividualsPackage.sysml | 215 +++ .../Apollo_11/TechnicalPortsPackage.sysml | 124 ++ .../TechnicalRequirementsPackage.sysml | 1208 +++++++++++++++++ 28 files changed, 7251 insertions(+) create mode 100644 language/src/test/java/parser/ApolloTest.java create mode 100644 language/src/test/resources/Apollo_11/AnalysisPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/Apollo11MissionExecutionPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/AstronautsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/CalculationsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/CapabilitiesPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/CoSMAPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/CoSMAQuantitiesAndUnitsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/CoSMAViewsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/ContextPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/FunctionSpecificationPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/FunctionalRequirementsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/FunctionsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/LogicalComponentsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/MissionPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/MissionPhasesPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/MissionRequirementsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/MissionSpecificationPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/OperationsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/ProgramPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/StakeholderNeedsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/StakeholderPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/SystemPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/SystemSpecificationPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/TechnicalComponentsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/TechnicalIndividualsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/TechnicalPortsPackage.sysml create mode 100644 language/src/test/resources/Apollo_11/TechnicalRequirementsPackage.sysml diff --git a/language/src/test/java/parser/ApolloTest.java b/language/src/test/java/parser/ApolloTest.java new file mode 100644 index 00000000..713a9030 --- /dev/null +++ b/language/src/test/java/parser/ApolloTest.java @@ -0,0 +1,60 @@ +package parser; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; +import java.util.stream.Collectors; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ApolloTest { + private static final String APOLLO11_MODEL_PATH = "src/test/resources/Apollo_11"; + + @BeforeAll + public static void init() { + Log.init(); + SysMLv2Mill.init(); + Log.enableFailQuick(false); + } + + @Test + public void testParseApollo11Models() throws IOException { + var models = Files.walk(Path.of(APOLLO11_MODEL_PATH)) + .filter(p -> p.toString().endsWith(".sysml")) + .sorted() + .collect(Collectors.toList()); + + assertFalse(models.isEmpty(), "No .sysml files found in " + APOLLO11_MODEL_PATH); + + StringBuilder failures = new StringBuilder(); + int successful = 0; + + for (Path model : models) { + SysMLv2Parser parser = SysMLv2Mill.parser(); + parser.setError(false); + Log.clearFindings(); + + Optional ast = parser.parse(model.toString()); + + if (parser.hasErrors() || ast.isEmpty()) { + failures.append("\n").append(model); + } + else { + successful++; + } + + Log.clearFindings(); + } + + System.out.println("Apollo 11 parser test result: " + successful + " / " + models.size() + " files parsed successfully."); + assertTrue(failures.length()==0, "Some Apollo 11 SysML files could not be parsed. " + + successful + " / " + models.size() + " files parsed successfully.\nFailed files: " + failures); + } +} diff --git a/language/src/test/resources/Apollo_11/AnalysisPackage.sysml b/language/src/test/resources/Apollo_11/AnalysisPackage.sysml new file mode 100644 index 00000000..ec007348 --- /dev/null +++ b/language/src/test/resources/Apollo_11/AnalysisPackage.sysml @@ -0,0 +1,157 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package AnalysisPackage { + + private import MissionPackage::*; + private import CoSMAPackage::*; + private import CoSMAQuantitiesAndUnitsPackage::*; + private import CoSMAPackage::*; + private import CalculationsPackage::*; + private import ISQ::*; + private import SI::*; + private import TechnicalComponentsPackage::*; + private import Apollo11MissionExecutionPackage::*; + + analysis def SystemPowerAnalysis { + doc /* Analysis to calculate the total power generation, load, and margin for a composite system by iterating over its parts. */ + subject systemToAnalyze : System; + + out totalPowerGenerated :> ISQ::power = rollupPowerGeneration(systemToAnalyze); + out totalPowerLoad :> ISQ::power = rollupPowerConsumption(systemToAnalyze); + out powerMargin :> ISQ::power = calculatePowerMargin(totalPowerGenerated, totalPowerLoad); + + assert constraint { + powerMargin > 0[W] + } + } + + analysis Apollo11MissionSystemPowerAnalysis : SystemPowerAnalysis { + doc /* Runs the iterative power analysis on the entire Apollo 11 Mission System. */ + + subject apollo11MissionSystem : System; + } + + analysis def SystemMassAnalysis { + doc /* An analysis to track the total mass of the spacecraft throughout the mission (mass budget). */ + subject apollo11Mission : Apollo11Mission; + + in initialLaunchMass :> ISQ::mass; + in propellantMassPerStage :> ISQ::mass[*]; + in jettisonedComponentMass :> ISQ::mass[*]; + out massAfterBurn :> ISQ::mass = calculateMassBudgetStep(initialLaunchMass, propellantMassPerStage, jettisonedComponentMass); + } + + analysis Apollo11MissionSuccessAnalysis { + doc /* A top-level analysis to evaluate whether the primary mission objectives were met. */ + subject apollo11Mission : Apollo11MissionIndividual; + + out overallMissionSuccess : ScalarValues::Boolean = evaluateMissionSuccess(apollo11Mission.crewReturnedSafely, apollo11Mission.softLandingAchieved, apollo11Mission.requiredSamplesReturned, apollo11Mission.instrumentsDeployed); + + assert constraint { + overallMissionSuccess = true; + } + } + + analysis Apollo11LifecycleReliabilityAnalysis { + doc /* An analysis to predict the probability of mission success based on the reliability of critical components over time. */ + subject apollo11Mission : Apollo11Mission; + + out cmReliability : RatioValue = calculateReliability( + apollo11Mission.apollo11MissionSystem.spacecraft.csm.commandModule.failureRate, + apollo11Mission.plannedDuration + ); + out smReliability : RatioValue = calculateReliability( + apollo11Mission.apollo11MissionSystem.spacecraft.csm.serviceModule.failureRate, + apollo11Mission.plannedDuration + ); + out lmReliability : RatioValue = calculateReliability( + apollo11Mission.apollo11MissionSystem.spacecraft.lm.failureRate, + apollo11Mission.plannedDuration / 2 // LM is only used for half the mission + ); + } + + analysis def MissionCostAnalysis { + doc /* A budgetary analysis to determine the total financial cost of a mission. */ + subject mission : Mission; + + out totalMissionCost :> currency = sumCosts(mission.researchAndDevelopmentCost, mission.manufacturingCost, mission.operationsCost, mission.personnelCost); + + } + + analysis Apollo11MissionCostAnalysis : MissionCostAnalysis { + subject apollo11Mission : Apollo11Mission; + } + + analysis Apollo11MissionDeltaVBudgetAnalysis { + doc /* Performs a full delta-v budget analysis for the Apollo 11 mission to verify that the propulsive capabilities of the hardware can meet the demands of the mission trajectory. */ + + subject apollo11Mission : Apollo11Mission; + + launchVehicle : SaturnV = apollo11Mission.apollo11MissionSystem.launchVehicle; + spacecraft : ApolloSpacecraft = apollo11Mission.apollo11MissionSystem.spacecraft; + + sic = launchVehicle.stage1; + sii = launchVehicle.stage2; + sivb = launchVehicle.stage3; + iu = launchVehicle.instrumentUnit; + les = spacecraft.launchEscapeSystem; + sla = spacecraft.spacecraftLMAdapter; + cm = spacecraft.commandServiceModule.commandModule; + sm = spacecraft.commandServiceModule.serviceModule; + lmds = spacecraft.lunarModule.lunarModuleDescentStage; + lmas = spacecraft.lunarModule.lunarModuleAscentStage; + + // Define mass stacks for each phase + fullStack = (sii, sivb, iu, sla, sm, cm, lm); + secondStageStack = (sivb, iu, sla, sm, cm, lm); + tliStack = (sla, sm, cm, lm); + spacecraftStack = (sm, cm, lm); + + // Calculate delta-v capability for each stage + dv_stage1 = calculateLaunchStageDeltaV(sic, fullStack); + dv_stage2 = calculateLaunchStageDeltaV(sii, secondStageStack); + dv_stage3_tli = calculateLaunchStageDeltaV(sivb, spacecraftStack); + + dv_csm = calculateSpacecraftBurnDeltaV(sm); + dv_lm_descent = calculateSpacecraftBurnDeltaV(lmds); + dv_lm_ascent = calculateSpacecraftBurnDeltaV(lmas); + + // Required delta-v for phases + dv_required_tli = calculateTliDeltaV(3.986E14 ['m³⋅s⁻²'], 6563 ['km'], 384400 ['km']); + dv_required_loi = calculateLoiDeltaV(1000 ['m⋅s⁻¹'], 4.9E12 ['m³⋅s⁻²'], 1839 ['km']); + dv_required_leo = 9400 ['m⋅s⁻¹']; + dv_required_landing = 2100 ['m⋅s⁻¹']; + dv_required_ascent = 1870 ['m⋅s⁻¹']; + dv_required_tei = 1000 ['m⋅s⁻¹']; + + // S-IC and S-II combine to provide most of the velocity to orbit. + ascentCapability = dv_stage1 + dv_stage2; + ascentMargin = ascentCapability - dv_required_leo; + + // S-IVB performs the final orbit insertion and the TLI burn. + tliMargin = dv_stage3_tli - dv_required_tli; + + // Service module performs LOI and TEI + loiMargin = dv_csm - (dv_required_loi + dv_required_tei); + + // LM Descent Stage must have enough delta-v to land + landingMargin = dv_lm_descent - dv_required_landing; + + // LM Ascent Stage must have enough delta-v to reach orbit + ascentMargin_lunar = dv_lm_ascent - dv_required_ascent; + + // The mission is feasible if all margins are positive. + assert constraint { + ascentMargin > 0 ['m⋅s⁻¹'] and + tliMargin > 0 ['m⋅s⁻¹'] and + loiMargin > 0 ['m⋅s⁻¹'] and + landingMargin > 0 ['m⋅s⁻¹'] and + ascentMargin_lunar > 0 ['m⋅s⁻¹'] + } + } +} diff --git a/language/src/test/resources/Apollo_11/Apollo11MissionExecutionPackage.sysml b/language/src/test/resources/Apollo_11/Apollo11MissionExecutionPackage.sysml new file mode 100644 index 00000000..1746b101 --- /dev/null +++ b/language/src/test/resources/Apollo_11/Apollo11MissionExecutionPackage.sysml @@ -0,0 +1,479 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package Apollo11MissionExecutionPackage { + + private import SI::*; + private import ISQ::*; + private import Time::*; + private import ScalarValues::*; + private import MissionPackage::*; + private import FunctionsPackage::*; + private import SystemPackage::*; + private import LogicalComponentsPackage::*; + private import ContextPackage::*; + private import OccurrenceFunctions::*; + private import TechnicalComponentsPackage::*; + private import AstronautsPackage::*; + private import CoSMAQuantitiesAndUnitsPackage::*; + + individual part def Apollo11MissionIndividual :> Apollo11Mission { + attribute crewReturnedSafely : ScalarValues::Boolean; + attribute softLandingAchieved : ScalarValues::Boolean; + attribute requiredSamplesReturned : ScalarValues::Boolean; + attribute instrumentsDeployed : ScalarValues::Boolean; + } + + individual part apollo11MissionIndividual : Apollo11MissionIndividual { + doc /* A timeline representing the key events of the actual Apollo 11 mission from July 16, 1969, to July 24, 1969. */ + + timeslice crewIngress { + doc /* The flight crew enters the Command Module 'Columbia'. */ + assert constraint { isDuring(apollo11Phases.preparation) } + snapshot atIngress { + doc /* The flight crew begins entering the Command Module 'Columbia'. */ + attribute missionTime :> ISQ::time = -9000 ['s']; + snapshot missionSystemAtIngress :> apollo11MissionSystem { + part :>> spacecraft { + part :>> csm { + part :>> commandModule { + attribute cabinPressure :> ISQ::pressure = 101 ['kPa']; + attribute oxygenLevel :> ratio = 21['%']; + } + } + } + } + snapshot groundSystemAtIngress :> context : Apollo11MissionContext { + part :>> launchControlCenter { + perform GroundSupportSystem::performCrewIngress :>> performCrewIngress; + } + } + snapshot crewAtIngress :> crew { + attribute location: String = "Ingressing Command Module 'Columbia'"; + attribute status: String = "Performing pre-flight checks"; + } + } + snapshot atIngressComplete { + doc /* Crew is secured and the Command Module hatch is sealed. */ + attribute missionTime :> ISQ::time = -3600 ['s']; + snapshot missionSystemAtIngressComplete :> apollo11MissionSystem { + part :>> spacecraft { + part :>> csm { + part :>> commandModule { + attribute cabinPressure :> ISQ::pressure = 34 ['kPa']; + attribute oxygenLevel :> ratio = 100['%']; + } + } + } + } + } + } + + then timeslice liftoff { + doc /* This timeslice covers the ascent through Earth's atmosphere. */ + assert constraint { isDuring(apollo11Phases.launch) } + snapshot atT0 { + doc /* State Activation: LaunchPhase begins with liftoff. */ + attribute missionTime :> ISQ::time = 0 [s]; + snapshot missionSystemAtT0 :> apollo11MissionSystem { + attribute velocity :> ISQ::speed = 0 [SI::'m⋅s⁻¹']; + part :>> launchVehicle { + part :>> stage1 { + attribute thrust :> ISQ::force = 35100 ['kN']; + } + perform LaunchSystem::provideStage1Thrust :>> provideStage1Thrust; + perform LaunchSystem::guideAscentTrajectory :>> guideAscentTrajectory; + } + part :>> crew { + perform Crew::observeAscentDataFromCockpit :>> observeAscentDataFromCockpit; + } + } + snapshot groundSystemAtT0 :> context : Apollo11MissionContext { + part :>> launchControlCenter { + perform GroundSupportSystem::analyzeLaunchTelemetryFromGround :>> analyzeLaunchTelemetryFromGround; + } + } + } + snapshot atSICSeparation { + doc /* Separation Event: The S-IC first stage separates. */ + attribute missionTime :> ISQ::time = 168 [s]; + snapshot missionSystemAtS1Sep :> apollo11MissionSystem { + attribute velocity :> ISQ::speed = 2400 [m/s]; + attribute altitude :> ISQ::length = 67 ['km']; + part :>> launchVehicle { + perform LaunchSystem::provideStage2Thrust :>> provideStage2Thrust; + } + } + } + snapshot atSIISeparation { + doc /* Separation Event: The S-II second stage separates. */ + attribute missionTime :> ISQ::time = 540 [s]; + snapshot missionSystemAtS2Sep :> apollo11MissionSystem { + attribute velocity :> ISQ::speed = 6800 [m/s]; + attribute altitude :> ISQ::length = 185 ['km']; + part :>> launchVehicle { + perform LaunchSystem::provideOrbitInsertionThrust :>> provideOrbitInsertionThrust; + } + } + } + } + + then timeslice translunarInjection { + doc /* This timeslice covers the burn to leave Earth orbit. */ + assert constraint { isDuring(apollo11Phases.tli) } + snapshot atTLI { + doc /* State Activation: TransLunarInjectionPhase begins with the S-IVB burn. */ + attribute missionTime :> ISQ::time = 10036 [s]; + snapshot missionSystemAtTLI :> apollo11MissionSystem { + part :>> launchVehicle { + part :>> stage3 { + attribute engineStatus: String = "Burning"; + } + perform LaunchSystem::provideTranslunarInjectionThrust :>> provideTranslunarInjectionThrust; + perform LaunchSystem::controlTranslunarInjectionBurn :>> controlTranslunarInjectionBurn; + } + } + } + snapshot atTLIComplete { + doc /* The TLI burn is complete, placing the vehicle on a translunar trajectory. */ + attribute missionTime :> ISQ::time = 10384 [s]; + snapshot missionSystemAtTLIEnd :> apollo11MissionSystem { + attribute status: String = "Translunar trajectory established"; + attribute velocity :> ISQ::speed = 10840 [m/s]; + } + } + } + + then timeslice transpositionAndDocking { + doc /* This timeslice covers the CSM/LM docking and extraction maneuver. */ + assert constraint { isDuring(apollo11Phases.tli) } + snapshot atCSMSeparation { + doc /* Separation Event: The CSM separates from the S-IVB/SLA. */ + attribute missionTime :> ISQ::time = 11400 [s]; + snapshot missionSystemAtCSMSep :> apollo11MissionSystem { + part :>> spacecraft { + part :>> csm { + attribute relativeVelocity :> ISQ::speed = 0.5 [m/s]; + attribute status: String = "Separated and maneuvering"; + } + perform Spacecraft::provideAttitudeControlThrust :>> provideAttitudeControlThrust; + } + part :>> crew { + perform Crew::executeTranspositionManeuver :>> executeTranspositionManeuver; + } + } + } + snapshot atCSLMDocking { + doc /* The CSM has turned around and is docking with the LM. */ + attribute missionTime :> ISQ::time = 12000 [s]; + snapshot missionSystemAtDocking :> apollo11MissionSystem { + part :>> spacecraft { + part :>> csm { + part :>> commandModule { + attribute dockingProbeStatus: String = "Capture latches engaged"; + } + } + attribute status: String = "Soft docked"; + perform Spacecraft::mechanicallyLatchModules :>> mechanicallyLatchModules; + } + part :>> crew { + perform Crew::connectSpacecraft :>> connectSpacecraft; + } + } + } + snapshot atExtractionComplete { + doc /* The docked CSM and LM have been extracted from the S-IVB stage. */ + attribute missionTime :> ISQ::time = 14400 [s]; + snapshot missionSystemAtExtraction :> apollo11MissionSystem { + part :>> spacecraft { + attribute status: String = "Docked stack extracted"; + } + } + } + } + + then timeslice translunarCoast { + doc /* This timeslice represents the coast to the Moon. */ + assert constraint { isDuring(apollo11Phases.tlc) } + snapshot atTLCStart { + doc /* State Activation: TransLunarCoastPhase begins. */ + attribute missionTime :> ISQ::time = 14401 [s]; + snapshot missionSystemAtTLC :> apollo11MissionSystem { + part :>> spacecraft { + attribute status: String = "Passive thermal control (barbecue roll) initiated"; + perform Spacecraft::provideAttitudeControlThrust :>> provideAttitudeControlThrust; + } + part :>> crew { + perform Crew::monitorOnboardSystems :>> monitorOnboardSystems; + } + } + } + } + + then timeslice lunarOrbitInsertion { + doc /* This timeslice covers the maneuver to enter lunar orbit. */ + assert constraint { isDuring(apollo11Phases.loi) } + snapshot atLOI { + doc /* State Activation: LunarOrbitInsertionPhase begins with the LOI burn. */ + attribute missionTime :> ISQ::time = 273110 [s]; + snapshot missionSystemAtLOI :> apollo11MissionSystem { + part :>> spacecraft { + part :>> csm { + part :>> serviceModule { + attribute engineStatus: String = "Burning (SPS)"; + attribute fuelRemaining :> ISQ::mass = 18400 [kg]; + } + } + perform Spacecraft::provideLunarOrbitInsertionThrust :>> provideLunarOrbitInsertionThrust; + perform Spacecraft::controlLunarOrbitInsertionBurn :>> controlLunarOrbitInsertionBurn; + } + } + } + snapshot atLOIComplete { + doc /* The LOI burn is complete and the spacecraft is in a stable orbit. */ + attribute missionTime :> ISQ::time = 273470 [s]; + snapshot missionSystemAtLOIEnd :> apollo11MissionSystem { + attribute status: String = "In stable elliptical lunar orbit"; + attribute orbitalParameters: String = "113km x 314km"; + } + } + } + + then timeslice descentPreparation { + doc /* This timeslice covers checking out and undocking the LM. */ + assert constraint { isDuring(apollo11Phases.lunarOpsDescentPrep) } + snapshot atDescentPrep { + doc /* State Activation: LunarOrbitOperationsDescentPreparationPhase begins. */ + attribute missionTime :> ISQ::time = 352800 [s]; + snapshot missionSystemAtDescentPrep :> apollo11MissionSystem { + part :>> spacecraft { + part :>> lm { + attribute powerStatus: String = "Activated on internal batteries"; + } + } + part :>> crew { + perform Crew::performOrbitalSystemCheckouts :>> performOrbitalSystemCheckouts; + perform Crew::prepareLanderForSeparation :>> prepareLanderForSeparation; + } + } + } + snapshot atLMUndocking { + doc /* Separation Event: The LM undocks from the CSM. */ + attribute missionTime :> ISQ::time = 353100 [s]; + snapshot missionSystemAtUndocking :> apollo11MissionSystem { + part :>> spacecraft { + perform Spacecraft::separateLanderFromOrbiter :>> separateLanderFromOrbiter; + } + } + } + } + + then timeslice poweredDescent { + doc /* This timeslice covers the powered descent to the lunar surface. */ + assert constraint { isDuring(apollo11Phases.poweredDescent) } + snapshot atPDI { + doc /* State Activation: PoweredDescentPhase begins with Powered Descent Initiation. */ + attribute missionTime :> ISQ::time = 360205 [s]; + snapshot missionSystemAtPDI :> apollo11MissionSystem { + part :>> spacecraft { + part :>> lm { + part :>> lunarModuleDescentStage { + attribute engineStatus: String = "Burning"; + attribute throttleLevel :> ratio = 90['%']; + } + } + perform Spacecraft::executeDescentBurn :>> executeDescentBurn; + } + } + } + snapshot atLanding { + doc /* The Lunar Module 'Eagle' touches down in the Sea of Tranquility. */ + attribute missionTime :> ISQ::time = 360940 [s]; + snapshot missionSystemAtLanding :> apollo11MissionSystem { + part :>> spacecraft { + part :>> lm { + part :>> lunarModuleDescentStage { + attribute engineStatus: String = "Shutdown"; + attribute propellantRemaining :> ISQ::mass = 45 [kg]; + } + } + } + part :>> crew { + perform Crew::manuallyPilotLander :>> manuallyPilotLander; + perform Crew::performPostLandingCheck :>> performPostLandingCheck; + } + } + } + + attribute :>> softLandingAchieved = true; + } + + then timeslice lunarSurfaceOps { + doc /* This timeslice covers the activities on the lunar surface. */ + assert constraint { isDuring(apollo11Phases.lunarSurfaceOps) } + snapshot atEVAStart { + doc /* State Activation: LunarSurfaceOperationsPhase begins with the first EVA. */ + attribute missionTime :> ISQ::time = 384300 [s]; + snapshot missionSystemAtEVAStart :> apollo11MissionSystem { + part :>> spaceSuits[0] { + attribute oxygenRemaining :> ISQ::duration = 6.5 ['h']; + attribute status: String = "Nominal"; + perform EVASystem::provideIndividualLifesupport :>> provideIndividualLifesupport; + } + part :>> crew { + part :>> commander { + perform Crew::conductSurfaceExploration :>> conductSurfaceExploration; + perform Crew::gatherLunarSamples :>> gatherLunarSamples; + perform Crew::deploySurfaceExperiments :>> deploySurfaceExperiments; + } + } + } + } + + attribute :>> instrumentsDeployed = true; + + snapshot atEVAEnd { + doc /* The EVA is complete and the crew are back inside the LM. */ + attribute missionTime :> ISQ::time = 393300 [s]; + snapshot missionSystemAtEVAEnd :> apollo11MissionSystem { + part :>> spacecraft { + part :>> lm { + attribute samplesStowed: Boolean = true; + attribute cabinPressure :> ISQ::pressure = 34 ['kPa']; + } + } + part :>> crew { + perform Crew::completeExtravehicularActivity :>> completeExtravehicularActivity; + } + } + } + } + + then timeslice ascentAndRendezvous { + doc /* This timeslice covers returning to lunar orbit and docking with the CSM. */ + assert constraint { isDuring(apollo11Phases.lunarAscentRendezvous) } + snapshot atLunarLiftoff { + doc /* State Activation: LunarAscentRendezvousPhase begins with liftoff from the Moon. */ + attribute missionTime :> ISQ::time = 447721 [s]; + snapshot missionSystemAtLunarLiftoff :> apollo11MissionSystem { + part :>> spacecraft { + perform Spacecraft::executeAscentBurn :>> executeAscentBurn; + } + } + } + snapshot atLunarDocking { + doc /* The LM Ascent Stage has completed rendezvous and docks with the CSM. */ + attribute missionTime :> ISQ::time = 460200 [s]; + snapshot missionSystemAtDocking :> apollo11MissionSystem { + attribute status: String = "Docked in lunar orbit, preparing for crew transfer"; + part :>> crew { + perform Crew::connectSpacecraft :>> connectSpacecraft; + perform Crew::transferCrewAndMaterials :>> transferCrewAndMaterials; + } + } + } + } + + then timeslice transearthInjection { + doc /* This timeslice covers the burn to leave lunar orbit. */ + assert constraint { isDuring(apollo11Phases.tei) } + snapshot atTEI { + doc /* State Activation: TransEarthInjectionPhase begins with the TEI burn. */ + attribute missionTime :> ISQ::time = 478500 [s]; + snapshot missionSystemAtTEI :> apollo11MissionSystem { + part :>> spacecraft { + perform Spacecraft::executeTransearthBurn :>> executeTransearthBurn; + } + } + } + } + + then timeslice transearthCoast { + doc /* This timeslice represents the coast back to Earth. */ + assert constraint { isDuring(apollo11Phases.tec) } + snapshot atTECStart { + doc /* State Activation: TransEarthCoastPhase begins. */ + attribute missionTime :> ISQ::time = 478651 [s]; + snapshot missionSystemAtTEC :> apollo11MissionSystem { + part :>> spacecraft { + attribute status: String = "Passive thermal control (barbecue roll) initiated"; + } + } + } + } + + then timeslice reentryAndLanding { + doc /* This timeslice covers the atmospheric entry and splashdown. */ + assert constraint { isDuring(apollo11Phases.reentryLanding) } + snapshot atCMSMSeparation { + doc /* Separation Event: The Command Module separates from the Service Module. */ + attribute missionTime :> ISQ::time = 688200 [s]; + snapshot missionSystemAtCMSMSep :> apollo11MissionSystem { + part :>> spacecraft { + perform Spacecraft::separateReturnCapsule :>> separateReturnCapsule; + } + } + } + snapshot atReentry { + doc /* State Activation: ReentryLandingPhase begins as the CM hits the atmosphere. */ + attribute missionTime :> ISQ::time = 689100 [s]; + snapshot missionSystemAtReentry :> apollo11MissionSystem { + part :>> spacecraft { + part :>> csm { + part :>> commandModule { + attribute heatshieldTemp :> ISQ::thermodynamicTemperature = 2760 ['K']; + attribute gForce :> ISQ::acceleration = 6.5 [gn]; + } + } + perform Spacecraft::guideAtmosphericEntry :>> guideAtmosphericEntry; + } + } + } + snapshot atSplashdown { + doc /* The Command Module 'Columbia' splashes down in the Pacific Ocean. */ + attribute missionTime :> ISQ::time = 690395 [s]; + snapshot missionSystemAtSplashdown :> apollo11MissionSystem { + part :>> spacecraft { + perform Spacecraft::deployDecelerators :>> deployDecelerators; + perform Spacecraft::performSplashdown :>> performSplashdown; + } + } + } + } + + then timeslice recoveryAndQuarantine { + doc /* This timeslice covers the recovery of the crew. */ + assert constraint { isDuring(apollo11Phases.recoveryQuarantine) } + snapshot atRecovery { + doc /* State Activation: RecoveryQuarantinePhase begins with crew retrieval. */ + attribute missionTime :> ISQ::time = 693000 [s]; + snapshot groundSystemAtRecovery :> context : Apollo11MissionContext { + part :>> recoveryForces { + perform GroundSupportSystem::retrieveVehicleAndCrew :>> retrieveVehicleAndCrew; + perform GroundSupportSystem::executeQuarantine :>> executeQuarantine; + } + } + } + snapshot atRecoveryComplete { + doc /* The Command Module is hoisted aboard the recovery ship. */ + attribute missionTime :> ISQ::time = 694800 [s]; + snapshot missionSystemAtRecEnd :> apollo11MissionSystem { + part :>> spacecraft { + part :>> csm { + part :>> commandModule { + attribute status: String = "Secured on deck of USS Hornet"; + } + } + } + } + } + + attribute :>> crewReturnedSafely = true; + attribute :>> requiredSamplesReturned = true; + } + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/AstronautsPackage.sysml b/language/src/test/resources/Apollo_11/AstronautsPackage.sysml new file mode 100644 index 00000000..6b853855 --- /dev/null +++ b/language/src/test/resources/Apollo_11/AstronautsPackage.sysml @@ -0,0 +1,167 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package AstronautsPackage { + + private import CoSMAPackage::*; + private import ScalarValues::*; + private import Time::*; + + individual part def 'Gus Grissom' :> Astronaut { + doc /* Virgil "Gus" Grissom was one of the original Mercury Seven astronauts. He was the second American in space and the first person to fly in space twice. He was the commander of the ill-fated Apollo 1 mission and tragically died in the launch pad fire. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1926-04-03"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("1967-01-27"); + } + individual part def 'Ed White' :> Astronaut { + doc /* Edward H. White II was the first American to perform a spacewalk, during the Gemini 4 mission. As Senior Pilot for the Apollo 1 mission, he died in the launch pad fire alongside his crewmates. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1930-11-14"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("1967-01-27"); + } + individual part def 'Roger B. Chaffee' :> Astronaut { + doc /* A rookie astronaut selected for the first crewed low Earth orbital test of the Apollo spacecraft. He served as the Pilot for Apollo 1 and tragically died in the launch pad fire with his crew. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1935-02-15"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("1967-01-27"); + } + individual part def 'Wally Schirra' :> Astronaut { + doc /* Walter "Wally" Schirra was the only astronaut to fly in all three of America's first human spaceflight programs: Mercury, Gemini, and Apollo. He commanded Apollo 7, the first crewed flight of the Apollo program. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1923-03-12"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2007-05-03"); + } + individual part def 'Walt Cunningham' :> Astronaut { + doc /* Walter Cunningham was a physicist and the Lunar Module Pilot on Apollo 7. This mission was a critical 11-day Earth-orbital test of the Apollo Command/Service Module, proving its space-worthiness. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1932-03-16"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2023-01-03"); + } + individual part def 'Donn Eisele' :> Astronaut { + doc /* Donn F. Eisele was the Command Module Pilot on Apollo 7, the first crewed flight of the Apollo spacecraft, which successfully tested the vehicle in Earth orbit. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1930-06-23"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("1987-12-02"); + } + individual part def 'Frank Borman' :> Astronaut { + doc /* Frank Borman was the Commander of the Apollo 8 mission, the first crewed flight to orbit the Moon. This historic 1968 mission was a crucial step towards the lunar landing. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1928-03-14"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2023-11-07"); + } + individual part def 'James Lovell' :> Astronaut { + doc /* James "Jim" Lovell is one of only three men to have flown to the Moon twice. He flew on Apollo 8, the first mission to orbit the Moon, and was the Commander of the ill-fated Apollo 13 mission, which he and his crew safely returned to Earth after a major in-flight emergency. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1928-03-25"); + } + individual part def 'William Anders' :> Astronaut { + doc /* William "Bill" Anders was the Lunar Module Pilot on Apollo 8. He is famous for taking the iconic "Earthrise" photograph, showing the Earth rising above the lunar horizon. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1933-10-17"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2024-06-07"); + } + individual part def 'James McDivitt' :> Astronaut { + doc /* James McDivitt was the Commander of Gemini 4 and Apollo 9 (first flight of the Lunar Module). */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1929-06-10"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2022-10-13"); + } + individual part def 'David Scott' :> Astronaut { + doc /* David Scott flew on Gemini 8 and Apollo 9, and was the Commander of Apollo 15. As the seventh person to walk on the Moon, he was the first to drive the Lunar Roving Vehicle on the lunar surface. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1932-06-06"); + } + individual part def 'Russell Schweickart' :> Astronaut { + doc /* Russell "Rusty" Schweickart was the Lunar Module Pilot on Apollo 9. He performed the first extravehicular activity (EVA) of the Apollo program, testing the new spacesuit's life support system. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1935-10-25"); + } + individual part def 'Thomas Stafford' :> Astronaut { + doc /* Thomas Stafford was the Commander of Apollo 10, the final "dress rehearsal" mission that flew to the Moon and tested the Lunar Module in lunar orbit, descending to within 9 miles of the surface. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1930-09-17"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2024-03-18"); + } + individual part def 'John Young' :> Astronaut { + doc /* John Young had a long and distinguished career, flying in the Gemini, Apollo, and Space Shuttle programs. He was the Command Module Pilot on Apollo 10 and the Commander of Apollo 16, becoming the ninth person to walk on the Moon. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1930-09-24"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2018-01-05"); + } + individual part def 'Eugene Cernan' :> Astronaut { + doc /* Eugene "Gene" Cernan was one of three men to fly to the Moon twice, on Apollo 10 and Apollo 17. As Commander of Apollo 17, he was the last person to walk on the Moon. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1934-03-14"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2017-01-16"); + } + individual part def 'Neil Armstrong' :> Astronaut { + doc /* Neil Armstrong was the Commander of Apollo 11. A veteran of the Gemini program and a skilled test pilot, he became the first human to walk on the lunar surface on July 20, 1969. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1930-08-05"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2012-08-25"); + } + individual part def 'Michael Collins' :> Astronaut { + doc /* Michael Collins was the Command Module Pilot for Apollo 11. He remained in lunar orbit aboard the Command Module "Columbia" while his crewmates explored the surface, a critical role for their safe return. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1930-10-31"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2021-04-28"); + } + individual part def 'Buzz Aldrin' :> Astronaut { + doc /* Edwin "Buzz" Aldrin was the Lunar Module Pilot for Apollo 11. He joined Neil Armstrong on the lunar surface, becoming the second human to walk on the Moon. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1930-01-20"); + } + individual part def 'Pete Conrad' :> Astronaut { + doc /* Charles "Pete" Conrad Jr. was the Commander of Apollo 12, the second lunar landing mission. He was the third person to walk on the Moon. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1930-06-02"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("1999-07-08"); + } + individual part def 'Richard Gordon' :> Astronaut { + doc /* Richard "Dick" Gordon Jr. was the Command Module Pilot for Apollo 12, orbiting the Moon while his crewmates landed in the Ocean of Storms. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1929-10-05"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2017-11-06"); + } + individual part def 'Alan Bean' :> Astronaut { + doc /* Alan Bean was the Lunar Module Pilot for Apollo 12, becoming the fourth person to walk on the Moon. After retiring from NASA, he became a renowned artist, painting scenes from the Apollo missions. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1932-03-15"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2018-05-26"); + } + individual part def 'Jack Swigert' :> Astronaut { + doc /* John "Jack" Swigert Jr. was the Command Module Pilot for the dramatic Apollo 13 mission. He was a late replacement for Ken Mattingly and played a key role in the crew's safe return. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1931-08-30"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("1982-12-27"); + } + individual part def 'Fred Haise' :> Astronaut { + doc /* Fred Haise was the Lunar Module Pilot for Apollo 13. He was scheduled to be the sixth person to walk on the Moon before an in-flight emergency forced the mission to abort its landing. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1933-11-14"); + } + individual part def 'Alan Shepard' :> Astronaut { + doc /* Alan Shepard was one of the original Mercury Seven and the first American in space. After overcoming an inner-ear disorder, he commanded Apollo 14, becoming the fifth person to walk on the Moon, where he famously hit two golf balls. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1923-11-18"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("1998-07-21"); + } + individual part def 'Stuart Roosa' :> Astronaut { + doc /* Stuart Roosa was the Command Module Pilot for Apollo 14. He carried hundreds of tree seeds into lunar orbit as part of a joint project with the U.S. Forest Service. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1933-08-16"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("1994-12-12"); + } + individual part def 'Edgar Mitchell' :> Astronaut { + doc /* Edgar Mitchell was the Lunar Module Pilot for Apollo 14 and the sixth person to walk on the Moon, exploring the Fra Mauro formation. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1930-09-17"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2016-02-04"); + } + individual part def 'Alfred Worden' :> Astronaut { + doc /* Alfred Worden was the Command Module Pilot for Apollo 15. During the return journey from the Moon, he performed the first-ever deep-space extravehicular activity (EVA). */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1932-02-07"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2020-03-18"); + } + individual part def 'James Irwin' :> Astronaut { + doc /* James Irwin was the Lunar Module Pilot for Apollo 15 and the eighth person to walk on the Moon. He was one of the first to explore the lunar mountains and drive the Lunar Roving Vehicle. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1930-03-17"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("1991-08-08"); + } + individual part def 'Ken Mattingly' :> Astronaut { + doc /* Thomas Kenneth "Ken" Mattingly II was famously removed from the Apollo 13 crew due to exposure to measles but later served as the Command Module Pilot for Apollo 16, orbiting the Moon during the mission. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1936-03-17"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("2023-10-31"); + } + individual part def 'Charles Duke' :> Astronaut { + doc /* Charles Duke served as the CAPCOM for Apollo 11, and his voice was heard by millions during the landing. He later flew as the Lunar Module Pilot for Apollo 16, becoming the tenth person to walk on the Moon. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1935-10-03"); + } + individual part def 'Ronald Evans' :> Astronaut { + doc /* Ronald Evans was the Command Module Pilot for Apollo 17. During the return flight from the Moon, he performed an EVA to retrieve film cassettes from the Service Module, which was the last deep-space EVA of the Apollo program. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1933-11-10"); + attribute dateOfDeath: Iso8601DateTime = new Iso8601DateTime("1990-04-07"); + } + individual part def 'Harrison Schmitt' :> Astronaut { + doc /* Harrison "Jack" Schmitt was the Lunar Module Pilot for Apollo 17. As a professional geologist, he was the only scientist to walk on the Moon and the twelfth person to do so. */ + attribute dateOfBirth: Iso8601DateTime = new Iso8601DateTime("1935-07-03"); + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/CalculationsPackage.sysml b/language/src/test/resources/Apollo_11/CalculationsPackage.sysml new file mode 100644 index 00000000..bbeecd18 --- /dev/null +++ b/language/src/test/resources/Apollo_11/CalculationsPackage.sysml @@ -0,0 +1,149 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package CalculationsPackage { + + private import ISQ::*; + private import ScalarValues::*; + private import CoSMAPackage::*; + private import ScalarFunctions::*; + private import CoSMAQuantitiesAndUnitsPackage::*; + private import TechnicalComponentsPackage::*; + private import NumericalFunctions::*; + private import CollectionFunctions::*; + private import ControlFunctions::*; + private import NumericalFunctions::*; + private import Parts::*; + + calc def rollupPowerGeneration { + in system: System; + return :> ISQ::power = system.subparts->select { + in sys : Part; + sys istype PowerProvider + } + ->collect { + in sys : PowerProvider; + sys.powerGenerated + } + ->sum(); + } + + calc def rollupPowerConsumption { + in system: System; + return :> ISQ::power = system.subparts->select { + in sys : Part; + sys istype PowerConsumer + } + ->collect { + in sys : PowerConsumer; + sys.powerLoad + } + ->sum(); + } + + + calc def calculateTliDeltaV { + doc /* Calculates the required Delta-V for a Hohmann-like Translunar Injection. */ + in mu_Earth :> ISQ::force; + in r_leo :> ISQ::length; + in r_apoapsis :> ISQ::length; + return deltaV :> ISQ::speed = (mu_Earth * (2/r_leo - 2/(r_leo + r_apoapsis)))^(1/2) - (mu_Earth / r_leo)^(1/2); + } + + calc def calculateLoiDeltaV { + doc /* Calculates the required braking Delta-V for Lunar Orbit Insertion from a hyperbolic approach. */ + in v_inf :> ISQ::speed; + in mu_Moon :> ISQ::force; + in r_periapsis :> ISQ::length; + return deltaV :> ISQ::speed = (v_inf^2 + 2*mu_Moon/r_periapsis)^(1/2) - (mu_Moon/r_periapsis)^(1/2); + } + + calc def sumCosts { + doc /* Sums the major cost categories to find the total program cost. */ + in r_d :> currency; + in mfg :> currency; + in ops :> currency; + in personnel :> currency; + return total :> currency = r_d + mfg + ops + personnel; + } + + calc def calculateReliability { + doc /* Calculates the reliability of a component over time using the exponential failure distribution. */ + in failureRate :> ISQ::frequency; + in missionTime :> ISQ::duration; + return reliability : RatioValue = eulerNumber^(-(failureRate * missionTime)); + } + + calc def evaluateMissionSuccess { + doc /* Evaluates the overall mission success based on the achievement of primary objectives. */ + in crewSafe : Boolean; + in landed : Boolean; + in samplesReturned : Boolean; + in instrumentsDeployed : Boolean; + return isSuccess : Boolean = crewSafe and landed and samplesReturned and instrumentsDeployed; + } + + calc def calculateMassBudgetStep { + doc /* Calculates the remaining mass of a vehicle after a mission event. */ + in initialMass :> ISQ::mass; + in propellantUsed :> ISQ::mass; + in jettisonedMass :> ISQ::mass; + return finalMass :> ISQ::mass = initialMass - propellantUsed - jettisonedMass; + } + + calc def calculatePowerMargin { + doc /* Calculates the difference between available power and the sum of all electrical loads. */ + in sourcePower :> ISQ::power; + in totalLoadPower :> ISQ::power; + return powerMargin :> ISQ::power = sourcePower - totalLoadPower; + } + + calc def calculateDeltaV { + doc /* Calculates the maximum change in velocity a stage can provide using the Tsiolkovsky Rocket Equation. */ + in isp :> specificImpulse; + in g0 :> ISQ::acceleration; + in m0 :> ISQ::mass; + in mf :> ISQ::mass; + return deltaV :> ISQ::speed = isp * g0 * ln(m0 / mf); + } + + calc def calculateLaunchStageDeltaV { + doc /* Calculates the delta-v provided by a launch stage (like S-IC or S-II) carrying an upper stack. */ + in stage: RocketStage; + in payloadStack: HardwareComponent[*]; + + payloadMass = sumGrossMass(payloadStack); + initialMass = stage.dryMass + stage.propellantMass + payloadMass; + finalMass = stage.dryMass + payloadMass; + isp = stage.engines.specificImpulseVacuum; + + return deltaV :> ISQ::speed = calculateDeltaV(isp, initialMass, finalMass); + } + + calc def calculateSpacecraftBurnDeltaV { + doc /* Calculates the delta-v provided by a self-propelled spacecraft (CSM or LM stages). */ + in spacecraft: PropelledSpacecraft; + + initialMass = spacecraft.dryMass + spacecraft.propellantMass; + finalMass = spacecraft.dryMass; + isp = spacecraft.specificImpulse; + + return deltaV :> ISQ::speed = calculateDeltaV(isp, initialMass, finalMass); + } + + calc def sumGrossMass { + doc /* A utility to sum the gross (fully fueled) mass of a set of components. */ + in components: HardwareComponent[*]; + return totalMass :> ISQ::mass = sum(components.totalMass); + } + + calc def sumDryMass { + doc /* A utility to sum the dry mass of a set of components. */ + in components: FuelledComponent[*]; + return totalMass :> ISQ::mass = sum(components.dryMass); + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/CapabilitiesPackage.sysml b/language/src/test/resources/Apollo_11/CapabilitiesPackage.sysml new file mode 100644 index 00000000..21b7e7dc --- /dev/null +++ b/language/src/test/resources/Apollo_11/CapabilitiesPackage.sysml @@ -0,0 +1,156 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package CapabilitiesPackage { + + private import CoSMAPackage::*; + private import StakeholderNeedsPackage::*; + private import ModelingMetadata::*; + + part def ProgrammaticAndPublicAffairsManagement :> Capability { + doc /* The ability to manage budgets, schedules, stakeholder communications, and public relations to maintain political and public support for a large-scale, high-cost program. */ + #refinement dependency ProgrammaticAndPublicAffairsManagement to 'SHN-N003'; + #refinement dependency ProgrammaticAndPublicAffairsManagement to 'SHN-N017'; + #refinement dependency ProgrammaticAndPublicAffairsManagement to 'SHN-N018'; + #refinement dependency ProgrammaticAndPublicAffairsManagement to 'SHN-N020'; + } + + part def HeavyLiftLaunch :> Capability { + doc /* The capability to propel extremely heavy payloads from Earth's surface into various orbital and interplanetary trajectories. */ + #refinement dependency HeavyLiftLaunch to 'SHN-N001'; + #refinement dependency HeavyLiftLaunch to 'SHN-N019'; + #refinement dependency HeavyLiftLaunch to 'SHN-N022'; + } + + part def MultiStagePropulsion :> Capability { + doc /* The ability to efficiently shed mass during ascent through the sequential operation of multiple rocket stages, optimizing for different phases of flight. */ + #refinement dependency MultiStagePropulsion to 'SHN-N001'; + } + + part def PrecisionOrbitalMechanics :> Capability { + doc /* The capability to accurately calculate, execute, and refine trajectories and orbital maneuvers in complex gravitational fields (Earth-Moon system). This includes achieving and maintaining stable orbits, as well as performing precise rendezvous and docking operations in space. */ + #refinement dependency PrecisionOrbitalMechanics to 'SHN-N001'; + #refinement dependency PrecisionOrbitalMechanics to 'SHN-N022'; + } + + part def AtmosphericReentryAndLanding :> Capability { + doc /* The ability to guide a spacecraft safely through Earth's atmosphere, dissipate extreme heat, control descent, and achieve a soft water landing. */ + #refinement dependency AtmosphericReentryAndLanding to 'SHN-N002'; + #refinement dependency AtmosphericReentryAndLanding to 'SHN-N007'; + } + + part def DeepSpaceHabitationAndLifeSupport :> Capability { + doc /* Providing sustained environments for humans in the vacuum of space, managing air quality, temperature, humidity, water, and waste for extended durations. */ + #refinement dependency DeepSpaceHabitationAndLifeSupport to 'SHN-N002'; + #refinement dependency DeepSpaceHabitationAndLifeSupport to 'SHN-N007'; + #refinement dependency DeepSpaceHabitationAndLifeSupport to 'SHN-N011'; + } + + part def AutonomousAndAssistedNavigationGuidanceAndControl :> Capability { + doc /* Systems capable of determining position and velocity, calculating optimal paths, and executing maneuvers, both independently and with ground assistance. */ + #refinement dependency AutonomousAndAssistedNavigationGuidanceAndControl to 'SHN-N022'; + } + + part def InSpacePropulsion :> Capability { + doc /* The ability to provide thrust for major orbital changes and trans-planetary injections using highly reliable and powerful engines. */ + #refinement dependency InSpacePropulsion to 'SHN-N001'; + } + + part def PowerGenerationAndDistribution :> Capability { + doc /* Reliable systems to generate and distribute electrical power to all spacecraft systems throughout the mission. */ + #refinement dependency PowerGenerationAndDistribution to 'SHN-N001'; + } + + part def LunarSurfaceLandingAndAscent :> Capability { + doc /* The specialized capability to de-orbit, perform a powered descent to a planetary surface, and then launch from that surface back into orbit. */ + #refinement dependency LunarSurfaceLandingAndAscent to 'SHN-N004'; + #refinement dependency LunarSurfaceLandingAndAscent to 'SHN-N016'; + #refinement dependency LunarSurfaceLandingAndAscent to 'SHN-N019'; + } + + part def GlobalTrackingAndCommunication :> Capability { + doc /* Maintaining continuous contact and data exchange with spacecraft across vast distances using a worldwide network of ground stations. */ + #refinement dependency GlobalTrackingAndCommunication to 'SHN-N014'; + } + + part def RealtimeMissionControl :> Capability { + doc /* The ability to monitor thousands of operational parameters, analyze data, and make critical, time-sensitive decisions to guide and support the mission. */ + #refinement dependency RealtimeMissionControl to 'SHN-N012'; + #refinement dependency RealtimeMissionControl to 'SHN-N014'; + #refinement dependency RealtimeMissionControl to 'SHN-N015'; + } + + part def ContingencyPlanningAndRapidResponse :> Capability { + doc /* Developing and implementing procedures to address unforeseen anomalies or failures swiftly and effectively. */ + #refinement dependency ContingencyPlanningAndRapidResponse to 'SHN-N002'; + #refinement dependency ContingencyPlanningAndRapidResponse to 'SHN-N007'; + } + + part def CrewTrainingAndSimulation :> Capability { + doc /* Rigorous programs to prepare astronauts for all mission aspects, including emergency procedures, through realistic simulations and drills. */ + #refinement dependency CrewTrainingAndSimulation to 'SHN-N008'; + #refinement dependency CrewTrainingAndSimulation to 'SHN-N010'; + #refinement dependency CrewTrainingAndSimulation to 'SHN-N015'; + } + + part def HumanPerformanceUnderExtremeStress :> Capability { + doc /* The ability of individuals and teams to maintain focus, make sound judgments, and execute complex tasks during high-stakes situations with immense pressure. */ + #refinement dependency HumanPerformanceUnderExtremeStress to 'SHN-N009'; + } + + part def ComplexSoftwareDevelopment :> Capability { + doc /* Creating and verifying intricate software for real-time control, navigation, and system management in highly constrained environments. */ + #refinement dependency ComplexSoftwareDevelopment to 'SHN-N001'; + } + + part def ComplexLogisticsAndIntegration :> Capability { + doc /* The capacity to manage the design, manufacturing, assembly, and testing of highly complex, interdependent systems on an unprecedented scale. */ + #refinement dependency ComplexLogisticsAndIntegration to 'SHN-N001'; + } + + part def LaunchOperationsManagement :> Capability { + doc /* The specialized ability to meticulously prepare, fuel, and execute the launch of large-scale rockets with precision and safety. */ + #refinement dependency LaunchOperationsManagement to 'SHN-N001'; + } + + part def AdaptabilityAndProblemSolving :> Capability { + doc /* The inherent human capacity to adjust to unexpected challenges and devise creative solutions in real-time. */ + #refinement dependency AdaptabilityAndProblemSolving to 'SHN-N012'; + } + + part def ExtravehicularActivitySupport :> Capability { + doc /* Providing specialized protective suits and equipment that allow humans to operate and perform tasks safely and effectively in the vacuum and harsh environments of space and planetary surfaces. */ + #refinement dependency ExtravehicularActivitySupport to 'SHN-N011'; + } + + part def LunarMobility :> Capability { + doc /* The ability for astronauts to move and work efficiently in lunar gravity. */ + #refinement dependency LunarMobility to 'SHN-N004'; + } + + part def ScientificDataAcquisitionAndSampleReturn :> Capability { + doc /* The capability to deploy scientific instruments, collect geological samples from an extraterrestrial body, and return them safely for Earth-based analysis. */ + #refinement dependency ScientificDataAcquisitionAndSampleReturn to 'SHN-N005'; + #refinement dependency ScientificDataAcquisitionAndSampleReturn to 'SHN-N021'; + } + + part def PlanetaryProtection :> Capability { + doc /* Implementing stringent protocols to prevent the biological contamination of Earth from returned extraterrestrial samples and to minimize contamination of the extraterrestrial body. */ + #refinement dependency PlanetaryProtection to 'SHN-N006'; + } + + part def RobustCommunicationAndTelemetry :> Capability { + doc /* Establishing and maintaining reliable data and voice links over vast distances, including transmitting live video. */ + #refinement dependency RobustCommunicationAndTelemetry to 'SHN-N013'; + } + + part def ToolDevelopment :> Capability { + doc /* Creating specialized tools for lunar surface tasks (e.g., sample collection, instrument deployment). */ + #refinement dependency ToolDevelopment to 'SHN-N008'; + } + +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/CoSMAPackage.sysml b/language/src/test/resources/Apollo_11/CoSMAPackage.sysml new file mode 100644 index 00000000..33de8f6f --- /dev/null +++ b/language/src/test/resources/Apollo_11/CoSMAPackage.sysml @@ -0,0 +1,126 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +library package CoSMAPackage { + + private import NumericalFunctions::*; + private import States::*; + private import ISQ::*; + private import SI::*; + private import MeasurementReferences::*; + private import Quantities::*; + private import Base::DataValue; + private import Metaobjects::*; + private import CoSMAQuantitiesAndUnitsPackage::*; + + part def MassedComponent { + part subcomponents : MassedComponent [*] default null; + attribute mass :> ISQ::mass; + attribute totalMass :> ISQ::mass = mass + sum(subcomponents.totalMass); + } + + abstract action def Operation; + + abstract action def Function { + action subfunctions[*] : Function :>> subactions; + } + + abstract part def SystemOfInterest; + abstract part def LogicalComponent; + + abstract part def TechnicalComponent { + attribute failureRate :> ISQ::frequency; + } + + abstract part def SoftwareComponent :> TechnicalComponent; + abstract part def HardwareComponent :> TechnicalComponent, MassedComponent; + + abstract part def PowerProvider :> HardwareComponent { + attribute powerGenerated :> ISQ::power default 0 [W]; + } + + abstract part def PowerConsumer :> HardwareComponent { + attribute powerLoad :> ISQ::power; + } + + part def Program { + part missions[1..*] : Mission; + } + + state def Phase :> StateAction; + + part def Capability; + + part def Astronaut :> Person; + + abstract part def MannedSpaceMission :> Mission { + part crew[1..*] : Astronaut; + } + + abstract part def Mission { + requirement goals[1..*] : Goal; + part system : System; + part context : Context; + exhibit state phases : StateAction; + part requiredCapabilites[0..*]; + abstract connection capabilityToGoals[*] : CapabilityToGoalDerivation; + attribute plannedDuration :> ISQ::duration; + + attribute researchAndDevelopmentCost :> currency; + attribute manufacturingCost :> currency; + attribute operationsCost :> currency; + attribute personnelCost :> currency; + } + + abstract connection def CapabilityToGoalDerivation { + ref part capability[1] : Capability :> participant; + ref requirement goals[1..*] : Goal :> participant; + } + + requirement def Goal; + + item def Concern; + + enum def StakeholderInfluenceKind { + enum direct; + enum indirect; + } + + enum def StakeholderInfluenceLevel { + enum high; + enum medium; + enum low; + } + + part def Person; + + requirement def StakeholderNeed; + + part def Stakeholder { + attribute influenceLevel: StakeholderInfluenceLevel; + attribute influenceKind: StakeholderInfluenceKind; + item concerns[*]: Concern; + requirement needs[*]: StakeholderNeed; + } + + part def Context :> System { + part externalSystems[*] : System; + } + + part def System :> MassedComponent { + + } + + part def SystemOfSystems :> System { + part constituentSystems[*] : ConstituentSystem; + } + + part def ConstituentSystem :> System { + + } + +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/CoSMAQuantitiesAndUnitsPackage.sysml b/language/src/test/resources/Apollo_11/CoSMAQuantitiesAndUnitsPackage.sysml new file mode 100644 index 00000000..0aaada93 --- /dev/null +++ b/language/src/test/resources/Apollo_11/CoSMAQuantitiesAndUnitsPackage.sysml @@ -0,0 +1,80 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +library package CoSMAQuantitiesAndUnitsPackage { + + private import NumericalFunctions::*; + private import ISQ::*; + private import SI::*; + private import MeasurementReferences::*; + private import Quantities::*; + private import Base::DataValue; + + attribute def RatioValue :> MeasurementReferences::DimensionOneValue { + doc /* Quantity of dimension one value that represents a ratio */ + attribute :>> num: ScalarValues::Real; + attribute :>> mRef: RatioUnit; + } + + attribute ratio : RatioValue nonunique :> Quantities::scalarQuantities; + attribute def RatioUnit :> MeasurementReferences::DimensionOneUnit; + + attribute <'%'> 'per cent' : RatioUnit { + attribute :>> unitConversion { + attribute :>> conversionFactor = RationalFunctions::rat(1, 100); + } + } + + attribute <'m³⋅s⁻²'> 'metre to the power 3 second to the power minus 2' : SimpleUnit; + + attribute kilonewton : ForceUnit { :>> unitConversion: ConversionByPrefix { :>> prefix = kilo; :>> referenceUnit = N; } } + attribute kilopascal : PressureUnit { :>> unitConversion: ConversionByPrefix { :>> prefix = kilo; :>> referenceUnit = Pa; } } + attribute meganewton : ForceUnit { :>> unitConversion: ConversionByPrefix { :>> prefix = mega; :>> referenceUnit = N; } } + attribute standardgravity : AccelerationUnit {:>> unitConversion: ConversionByConvention { :>> referenceUnit = 'm⋅s⁻²'; :>> conversionFactor = 9.80665; :>> isExact = false; }} + attribute framespersecond : FrequencyUnit; + attribute kilobyte : StorageCapacityUnit { :>> unitConversion: ConversionByPrefix { :>> prefix = kilo; :>> referenceUnit = B; } } + attribute year : TimeUnit {:>> unitConversion: ConversionByConvention { :>> referenceUnit = 's'; :>> conversionFactor = 31536000; :>> isExact = false; }} + + attribute def CurrencyUnit :> SimpleUnit { + private attribute currencyPF: QuantityPowerFactor[1] { :>> quantity = Currency; :>> exponent = 1; } + attribute :>> quantityDimension { :>> quantityPowerFactors = currencyPF; } + } + + attribute def CurrencyValue :> ScalarQuantityValue { + doc + /* + * application domain: generic + * name: Currency + * measurement unit(s): $ + * tensor order: 0 + */ + attribute :>> num: Real; + attribute :>> mRef: CurrencyUnit[1]; + } + + attribute Currency: CurrencyValue[1]; + attribute currency: CurrencyValue[*] nonunique :> scalarQuantities; + attribute <'$'> dollar : CurrencyUnit; + attribute <'€'> euro : CurrencyUnit; + + attribute def SpecificImpulseValue :> ScalarQuantityValue { + doc + /* + * application domain: rocket engineering + * name: Specific Impulse + * measurement unit(s): s + * tensor order: 0 + */ + attribute :>> num: Real; + attribute :>> mRef: DurationUnit[1]; + } + + attribute SpecificImpulse: SpecificImpulseValue[1]; + attribute specificImpulse: SpecificImpulseValue[*] nonunique :> scalarQuantities; + + calc naturalLogarithm { in x: DataValue[1]; in y: DataValue[1]; return : DataValue[1]; } +} diff --git a/language/src/test/resources/Apollo_11/CoSMAViewsPackage.sysml b/language/src/test/resources/Apollo_11/CoSMAViewsPackage.sysml new file mode 100644 index 00000000..c8bf83ad --- /dev/null +++ b/language/src/test/resources/Apollo_11/CoSMAViewsPackage.sysml @@ -0,0 +1,14 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +library package CoSMAViewsPackage { + + view RequirementsTableView { + //expose Requirements::MissionRequirementsPackage::*; + //filter hastype SysML::Systems::RequirementDefinition; + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/ContextPackage.sysml b/language/src/test/resources/Apollo_11/ContextPackage.sysml new file mode 100644 index 00000000..ad35123a --- /dev/null +++ b/language/src/test/resources/Apollo_11/ContextPackage.sysml @@ -0,0 +1,85 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package ContextPackage { + + private import SI::*; + private import ISQ::*; + private import ScalarValues::*; + private import CoSMAPackage::*; + private import CoSMAQuantitiesAndUnitsPackage::*; + private import USCustomaryUnits::*; + private import LogicalComponentsPackage::*; + + part def EarthEnvironment { + doc /* The starting and ending physical environment for the mission. */ + attribute surfaceGravity :> ISQ::acceleration = 1 [gn]; + attribute standardAtmosphericPressure :> ISQ::pressure = 101325 [pascal]; + attribute rotationalVelocity :> ISQ::speed = 465 [m/s]; // At the equator + attribute reentryInterfaceAltitude :> ISQ::length = 122 ['km']; + } + + part def CislunarSpaceEnvironment { + doc /* The physical environment between Earth and the Moon. */ + attribute ambientPressure :> ISQ::pressure = 3.2E-14 [pascal]; // Approximate pressure of interplanetary space + attribute solarIrradiance :> ISQ::irradiance = 1361 [W/m^2]; + attribute backgroundTemperature :> ISQ::thermodynamicTemperature = 2.7 [K]; + } + + part def LunarEnvironment { + doc /* The destination physical environment. */ + attribute surfaceGravity :> ISQ::acceleration = 1.62 ['m⋅s⁻²']; + attribute surfacePressure :> ISQ::pressure = 3E-10 [pascal]; // Near-perfect vacuum + attribute maxDayTemperature :> ISQ::thermodynamicTemperature = 400 [K]; // Approx. 127 °C + attribute minNightTemperature :> ISQ::thermodynamicTemperature = 100 [K]; // Approx. -173 °C + } + + part def LaunchSite :> System, GroundSupportSystem { + doc /* The specific ground facility from which the mission originates. */ + attribute name: String = "John F. Kennedy Space Center"; + attribute location: String = "Merritt Island, Florida, USA"; + attribute geographicCoordinates: String = "28.57° N, 80.65° W"; + + part vehicleAssemblyBuilding : VehicleAssemblyBuilding; + part launchControlCenter : LaunchControlCenter; + part crawlerTransporter : CrawlerTransporter; + } + + part def VehicleAssemblyBuilding :> System, GroundSupportSystem { + doc /* The massive facility used to stack the space vehicle. */ + } + + part def LaunchControlCenter :> System, GroundSupportSystem { + doc /* The facility for controlling the pre-launch and launch sequences. */ + } + + part def CrawlerTransporter :> System, GroundSupportSystem { + doc /* The mobile platform used to move the rocket from the VAB to the launch pad. */ + } + + part def MissionControl :> System, GroundSupportSystem { + doc /* The Earth-based command, control, and analysis center for post-launch operations. */ + attribute location: String = "Houston, Texas"; + } + + part def RecoveryForces :> System, GroundSupportSystem { + doc /* The assets tasked with retrieving the crew and capsule after splashdown. */ + } + + part def MannedSpaceFlightNetwork :> System, DataTransmissionNetwork { + doc /* The Manned Space Flight Network (abbreviated MSFN, pronounced "misfin") was a set of tracking stations built to support the American Mercury, Gemini, Apollo, and Skylab space programs. */ + } + + part def Apollo11MissionContext :> Context { + part vehicleAssemblyBuilding : VehicleAssemblyBuilding :> externalSystems; + part launchControlCenter : LaunchControlCenter :> externalSystems; + part crawlerTransporter : CrawlerTransporter :> externalSystems; + part missionControl : MissionControl :> externalSystems; + part recoveryForces : RecoveryForces :> externalSystems; + part mannedSpaceFlightNetwork : MannedSpaceFlightNetwork :> externalSystems; + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/FunctionSpecificationPackage.sysml b/language/src/test/resources/Apollo_11/FunctionSpecificationPackage.sysml new file mode 100644 index 00000000..d07eb455 --- /dev/null +++ b/language/src/test/resources/Apollo_11/FunctionSpecificationPackage.sysml @@ -0,0 +1,243 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package FunctionSpecificationPackage { + + private import FunctionalRequirementsPackage::*; + private import FunctionsPackage::*; + + requirement performLunarMissionSpecification { + doc /* Apollo 11 Function requirements group */ + subject performLunarMission : PerformLunarMission; + + requirement 'flr-R001' : PropellantLoadingRequirement; + requirement 'flr-R002' : ConsumableConditioningRequirement; + requirement 'flr-R003' : CrewIngressRequirement; + requirement 'flr-R004' : CabinPressurizationRequirement; + requirement 'flr-R005' : CountdownSequencingRequirement; + requirement 'flr-R006' : CountdownAbortRequirement; + requirement 'flr-R007' : Stage1ThrustInitiationRequirement; + requirement 'flr-R008' : Stage1ThrustMagnitudeRequirement; + requirement 'flr-R009' : Stage2ThrustInitiationRequirement; + requirement 'flr-R010' : Stage2PropulsionRequirement; + requirement 'flr-R011' : OrbitInsertionThrustInitiationRequirement; + requirement 'flr-R012' : OrbitInsertionThrustTerminationRequirement; + requirement 'flr-R013' : AscentGuidanceRequirement; + requirement 'flr-R014' : AscentStagingCommandRequirement; + requirement 'flr-R015' : CrewAscentMonitoringRequirement; + requirement 'flr-R016' : CrewAscentAbortRequirement; + requirement 'flr-R017' : GroundTelemetryAnalysisRequirement; + requirement 'flr-R018' : GroundPerformanceVerificationRequirement; + requirement 'flr-R019' : TliThrustInitiationRequirement; + requirement 'flr-R020' : TliThrustControlRequirement; + requirement 'flr-R021' : ModuleSeparationRequirement; + requirement 'flr-R022' : ModuleRepositioningRequirement; + requirement 'flr-R023' : ModuleConnectionRequirement; + requirement 'flr-R024' : InSpacePropulsionRequirement; + requirement 'flr-R025' : AttitudeControlRequirement; + requirement 'flr-R026' : NavigationalDataAcquisitionRequirement; + requirement 'flr-R027' : TrajectoryCalculationRequirement; + requirement 'flr-R028' : CourseCorrectionCalculationRequirement; + requirement 'flr-R029' : CourseCorrectionExecutionRequirement; + requirement 'flr-R030' : CrewSystemMonitoringRequirement; + requirement 'flr-R031' : GroundSystemMonitoringRequirement; + requirement 'flr-R032' : SpacecraftDataTransmissionRequirement; + requirement 'flr-R033' : SpacecraftDataReceptionRequirement; + requirement 'flr-R034' : GroundTrackingRequirement; + requirement 'flr-R035' : GroundCommunicationRelayRequirement; + requirement 'flr-R036' : CrewActivitySchedulingRequirement; + requirement 'flr-R037' : CrewRestProvisionRequirement; + requirement 'flr-R038' : LoiThrustRequirement; + requirement 'flr-R039' : LoiGuidanceRequirement; + requirement 'flr-R040' : LanderSystemVerificationRequirement; + requirement 'flr-R041' : LanderInterfaceVerificationRequirement; + requirement 'flr-R042' : LanderCrewTransferRequirement; + requirement 'flr-R043' : LanderConfigurationRequirement; + requirement 'flr-R044' : ModuleDisengagementRequirement; + requirement 'flr-R045' : ModuleSeparationManeuverRequirement; + requirement 'flr-R046' : DescentPropulsionRequirement; + requirement 'flr-R047' : DescentDataDisplayRequirement; + requirement 'flr-R048' : DescentDataProcessingRequirement; + requirement 'flr-R049' : ManualAttitudeControlRequirement; + requirement 'flr-R050' : ManualPositionControlRequirement; + requirement 'flr-R051' : PostLandingSafingRequirement; + requirement 'flr-R052' : PostLandingVerificationRequirement; + requirement 'flr-R053' : EgressPreparationRequirement; + requirement 'flr-R054' : CabinDepressurizationRequirement; + requirement 'flr-R055' : SurfaceMobilityRequirement; + requirement 'flr-R056' : SymbolicDeploymentRequirement; + requirement 'flr-R057' : SampleCollectionRequirement; + requirement 'flr-R058' : SampleStorageRequirement; + requirement 'flr-R059' : InstrumentDeploymentRequirement; + requirement 'flr-R060' : VisualTransmissionRequirement; + requirement 'flr-R061' : EvaIngressRequirement; + requirement 'flr-R062' : CabinRepressurizationRequirement; + requirement 'flr-R063' : SurfaceHabitationRequirement; + requirement 'flr-R064' : SurfaceTimelineManagementRequirement; + requirement 'flr-R065' : AscentThrustInitiationRequirement; + requirement 'flr-R066' : AscentPropulsionRequirement; + requirement 'flr-R067' : RendezvousCalculationRequirement; + requirement 'flr-R068' : RendezvousExecutionRequirement; + requirement 'flr-R069' : DockingApproachRequirement; + requirement 'flr-R070' : DockingLatchingRequirement; + requirement 'flr-R071' : IntervehicularCrewTransferRequirement; + requirement 'flr-R072' : IntervehicularSampleTransferRequirement; + requirement 'flr-R073' : AscentStageSeparationRequirement; + requirement 'flr-R074' : AscentStageDisposalRequirement; + requirement 'flr-R075' : TeiPropulsionRequirement; + requirement 'flr-R076' : ReentryConfigurationRequirement; + requirement 'flr-R077' : ServiceModuleJettisonRequirement; + requirement 'flr-R078' : CleanSeparationRequirement; + requirement 'flr-R079' : ReentryGuidanceRequirement; + requirement 'flr-R080' : HeatDissipationRequirement; + requirement 'flr-R081' : DeceleratorDeploymentRequirement; + requirement 'flr-R082' : FinalVelocityRequirement; + requirement 'flr-R083' : WaterLandingRequirement; + requirement 'flr-R084' : PostLandingSystemsRequirement; + requirement 'flr-R085' : CrewRecoveryRequirement; + requirement 'flr-R086' : VesselTransferRequirement; + requirement 'flr-R087' : QuarantineImplementationRequirement; + requirement 'flr-R088' : QuarantineHabitationRequirement; + requirement 'flr-R089' : SamplePreservationRequirement; + requirement 'flr-R090' : SampleTransportRequirement; + requirement 'flr-R091' : TGNCNavigationAccuracy; + requirement 'flr-R092' : ManualPilotingLogic; + requirement 'flr-R093' : SystemInterfaceCompatibility; + requirement 'flr-R094' : TrainingSimulatorHours; + requirement 'flr-R095' : CourseCorrectionCapability; + requirement 'flr-R096' : SpacecraftOrientationControl; + requirement 'flr-R097' : DescentDataAcquisition; + requirement 'flr-R098' : LaunchVehicleAscentThrust; + requirement 'flr-R099' : DescentRateModulation; + requirement 'flr-R100' : ThermalProtectionLogic; + requirement 'flr-R101' : TouchdownEnergyDissipation; + requirement 'flr-R102' : AtmosphericScrubbingFunction; + requirement 'flr-R103' : TelemetryStreamIntegrity; + requirement 'flr-R104' : EMUPressureMaintenance; + requirement 'flr-R105' : SoftwareMissionProficiency; + requirement 'flr-R106' : SpaceEnvironmentResilience; + requirement 'flr-R107' : VisualDataCapture; + requirement 'flr-R108' : WasteContainmentFunction; + requirement 'flr-R109' : CrossVehicleAudioLink; + requirement 'flr-R110' : ComponentFaultTolerance; + requirement 'flr-R111' : HumanMedicalSelfSufficiency; + requirement 'flr-R112' : DataRedundancyArchiving; + + satisfy 'flr-R001' by performLunarMission.outbound.prep.load; + satisfy 'flr-R002' by performLunarMission.outbound.prep.load; + satisfy 'flr-R003' by performLunarMission.outbound.prep.board; + satisfy 'flr-R004' by performLunarMission.outbound.prep.board; + satisfy 'flr-R005' by performLunarMission.outbound.launch.countdown; + satisfy 'flr-R006' by performLunarMission.outbound.launch.countdown; + satisfy 'flr-R007' by performLunarMission.outbound.launch.provideThrust1; + satisfy 'flr-R008' by performLunarMission.outbound.launch.provideThrust1; + satisfy 'flr-R009' by performLunarMission.outbound.launch.provideThrust2; + satisfy 'flr-R010' by performLunarMission.outbound.launch.provideThrust2; + satisfy 'flr-R011' by performLunarMission.outbound.launch.provideThrust3; + satisfy 'flr-R012' by performLunarMission.outbound.launch.provideThrust3; + satisfy 'flr-R013' by performLunarMission.outbound.launch.guide; + satisfy 'flr-R014' by performLunarMission.outbound.launch.guide; + satisfy 'flr-R015' by performLunarMission.outbound.launch.observe; + satisfy 'flr-R016' by performLunarMission.outbound.launch.observe; + satisfy 'flr-R017' by performLunarMission.outbound.launch.analyze; + satisfy 'flr-R018' by performLunarMission.outbound.launch.analyze; + satisfy 'flr-R019' by performLunarMission.outbound.tli.burn; + satisfy 'flr-R020' by performLunarMission.outbound.tli.control; + satisfy 'flr-R021' by performLunarMission.outbound.tli.executeTransposition; + satisfy 'flr-R022' by performLunarMission.outbound.tli.executeTransposition; + satisfy 'flr-R023' by performLunarMission.outbound.tli.reconfigure; + satisfy 'flr-R024' by performLunarMission.outbound.loi.burn; + satisfy 'flr-R025' by performLunarMission.outbound.tli.provideAttitudeControlAndThrust; + satisfy 'flr-R026' by performLunarMission.outbound.coast.trackAndRelay; + satisfy 'flr-R027' by performLunarMission.outbound.coast.calculate; + satisfy 'flr-R028' by performLunarMission.outbound.coast.calculate; + satisfy 'flr-R029' by performLunarMission.outbound.coast.correct; + satisfy 'flr-R030' by performLunarMission.outbound.coast.monitorOnboard; + satisfy 'flr-R031' by performLunarMission.outbound.coast.monitorGround; + satisfy 'flr-R032' by performLunarMission.outbound.coast.comms; + satisfy 'flr-R033' by performLunarMission.outbound.coast.comms; + satisfy 'flr-R034' by performLunarMission.outbound.coast.trackAndRelay; + satisfy 'flr-R035' by performLunarMission.outbound.coast.trackAndRelay; + satisfy 'flr-R036' by performLunarMission.outbound.coast.rest; + satisfy 'flr-R037' by performLunarMission.outbound.coast.rest; + satisfy 'flr-R038' by performLunarMission.outbound.loi.burn; + satisfy 'flr-R039' by performLunarMission.outbound.loi.control; + satisfy 'flr-R040' by performLunarMission.lunarOps.prepLanding.checkout; + satisfy 'flr-R041' by performLunarMission.lunarOps.prepLanding.checkout; + satisfy 'flr-R042' by performLunarMission.lunarOps.prepLanding.prep; + satisfy 'flr-R043' by performLunarMission.lunarOps.prepLanding.prep; + satisfy 'flr-R044' by performLunarMission.lunarOps.prepLanding.undock; + satisfy 'flr-R045' by performLunarMission.lunarOps.prepLanding.undock; + satisfy 'flr-R046' by performLunarMission.lunarOps.land.burn; + satisfy 'flr-R047' by performLunarMission.lunarOps.land.monitor; + satisfy 'flr-R048' by performLunarMission.lunarOps.land.monitor; + satisfy 'flr-R049' by performLunarMission.lunarOps.land.pilot; + satisfy 'flr-R050' by performLunarMission.lunarOps.land.pilot; + satisfy 'flr-R051' by performLunarMission.lunarOps.explore.postLand; + satisfy 'flr-R052' by performLunarMission.lunarOps.explore.postLand; + satisfy 'flr-R053' by performLunarMission.lunarOps.explore.prepEva; + satisfy 'flr-R054' by performLunarMission.lunarOps.explore.prepEva; + satisfy 'flr-R055' by performLunarMission.lunarOps.explore.eva; + satisfy 'flr-R056' by performLunarMission.lunarOps.explore.eva; + satisfy 'flr-R057' by performLunarMission.lunarOps.explore.collect; + satisfy 'flr-R058' by performLunarMission.lunarOps.explore.collect; + satisfy 'flr-R059' by performLunarMission.lunarOps.explore.deploy; + satisfy 'flr-R060' by performLunarMission.lunarOps.explore.deploy; + satisfy 'flr-R061' by performLunarMission.lunarOps.explore.conclude; + satisfy 'flr-R062' by performLunarMission.lunarOps.explore.conclude; + satisfy 'flr-R063' by performLunarMission.lunarOps.explore.rest; + satisfy 'flr-R064' by performLunarMission.lunarOps.explore.rest; + satisfy 'flr-R065' by performLunarMission.lunarOps.ascendAndDock.ascend; + satisfy 'flr-R066' by performLunarMission.lunarOps.ascendAndDock.ascend; + satisfy 'flr-R067' by performLunarMission.lunarOps.ascendAndDock.calculate; + satisfy 'flr-R068' by performLunarMission.lunarOps.ascendAndDock.rendezvous; + satisfy 'flr-R069' by performLunarMission.lunarOps.ascendAndDock.dock; + satisfy 'flr-R070' by performLunarMission.lunarOps.ascendAndDock.dock; + satisfy 'flr-R071' by performLunarMission.lunarOps.ascendAndDock.transfer; + satisfy 'flr-R072' by performLunarMission.lunarOps.ascendAndDock.transfer; + satisfy 'flr-R073' by performLunarMission.lunarOps.ascendAndDock.jettison; + satisfy 'flr-R074' by performLunarMission.lunarOps.ascendAndDock.jettison; + satisfy 'flr-R075' by performLunarMission.returnJourney.tei.burn; + satisfy 'flr-R076' by performLunarMission.returnJourney.coast.prep; + satisfy 'flr-R077' by performLunarMission.returnJourney.land.separate; + satisfy 'flr-R078' by performLunarMission.returnJourney.land.separate; + satisfy 'flr-R079' by performLunarMission.returnJourney.land.guide; + satisfy 'flr-R080' by performLunarMission.returnJourney.land.guide; + satisfy 'flr-R081' by performLunarMission.returnJourney.land.deploy; + satisfy 'flr-R082' by performLunarMission.returnJourney.land.deploy; + satisfy 'flr-R083' by performLunarMission.returnJourney.land.splashdown; + satisfy 'flr-R084' by performLunarMission.returnJourney.land.splashdown; + satisfy 'flr-R085' by performLunarMission.returnJourney.recover.retrieve; + satisfy 'flr-R086' by performLunarMission.returnJourney.recover.retrieve; + satisfy 'flr-R087' by performLunarMission.returnJourney.recover.quarantine; + satisfy 'flr-R088' by performLunarMission.returnJourney.recover.quarantine; + satisfy 'flr-R089' by performLunarMission.returnJourney.recover.secure; + satisfy 'flr-R090' by performLunarMission.returnJourney.recover.secure; + satisfy 'flr-R091' by performLunarMission.outbound.coast.trackAndRelay; + satisfy 'flr-R092' by performLunarMission.lunarOps.land.pilot; + satisfy 'flr-R093' by performLunarMission.outbound.prep.load; + satisfy 'flr-R094' by performLunarMission.outbound.prep.board; + satisfy 'flr-R095' by performLunarMission.outbound.coast.correct; + satisfy 'flr-R096' by performLunarMission.outbound.tli.provideAttitudeControlAndThrust; + satisfy 'flr-R097' by performLunarMission.lunarOps.land.monitor; + satisfy 'flr-R098' by performLunarMission.outbound.launch.provideThrust1; + satisfy 'flr-R099' by performLunarMission.lunarOps.land.burn; + satisfy 'flr-R100' by performLunarMission.returnJourney.land.guide; + satisfy 'flr-R101' by performLunarMission.lunarOps.land.burn; + satisfy 'flr-R102' by performLunarMission.outbound.coast.monitorOnboard; + satisfy 'flr-R103' by performLunarMission.outbound.coast.comms; + satisfy 'flr-R104' by performLunarMission.lunarOps.explore.eva; + satisfy 'flr-R105' by performLunarMission.outbound.launch.guide; + satisfy 'flr-R106' by performLunarMission.outbound.coast.monitorOnboard; + satisfy 'flr-R107' by performLunarMission.lunarOps.explore.deploy; + satisfy 'flr-R108' by performLunarMission.outbound.coast.monitorOnboard; + satisfy 'flr-R109' by performLunarMission.lunarOps.explore.eva; + satisfy 'flr-R110' by performLunarMission.outbound.loi.burn; + satisfy 'flr-R111' by performLunarMission.outbound.coast.rest; + satisfy 'flr-R112' by performLunarMission.returnJourney.recover.retrieve; + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/FunctionalRequirementsPackage.sysml b/language/src/test/resources/Apollo_11/FunctionalRequirementsPackage.sysml new file mode 100644 index 00000000..aeb27040 --- /dev/null +++ b/language/src/test/resources/Apollo_11/FunctionalRequirementsPackage.sysml @@ -0,0 +1,945 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package FunctionalRequirementsPackage { + + private import SI::*; + private import ISQ::*; + private import ScalarValues::*; + private import CoSMAQuantitiesAndUnitsPackage::*; + private import USCustomaryUnits::*; + private import ModelingMetadata::*; + private import CoSMAPackage::*; + private import MissionRequirementsPackage::*; + + requirement def <'FLR-R001'> PropellantLoadingRequirement { + doc /* The system shall enable the loading of all required propellants and consumables into the vehicle's storage systems. */ + @Rationale { + text = "All propulsive stages and life support systems must be fully supplied to perform their functions for the mission's duration."; + } + #refinement dependency 'FLR-R001' to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R002'> ConsumableConditioningRequirement { + doc /* The system shall maintain all loaded propellants and consumables at their required temperature and pressure prior to launch. */ + @Rationale { + text = "Cryogenic propellants and other consumables must be kept in a stable state to ensure vehicle integrity and readiness for engine start."; + } + #refinement dependency 'FLR-R002' to MissionRequirementsPackage::'HLR-R005'; + } + + requirement def <'FLR-R003'> CrewIngressRequirement { + doc /* The system shall provide a safe method for the flight crew to enter and be secured within the crew cabin. */ + @Rationale { + text = "The crew must be safely positioned and secured within the vehicle to withstand the forces of launch."; + } + #refinement dependency CrewIngressRequirement to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R004'> CabinPressurizationRequirement { + doc /* The system shall verify the pressure integrity of the crew cabin after crew ingress. */ + @Rationale { + text = "A sealed cabin is fundamental for providing a habitable, life-sustaining environment for the crew."; + } + #refinement dependency CabinPressurizationRequirement to MissionRequirementsPackage::'HLR-R005'; + } + + requirement def <'FLR-R005'> CountdownSequencingRequirement { + doc /* The system shall execute a synchronized sequence of pre-launch checks and configurations. */ + @Rationale { + text = "A precisely timed sequence is necessary to ensure thousands of vehicle and ground systems are correctly configured for launch."; + } + #refinement dependency 'FLR-R005' to MissionRequirementsPackage::'HLR-R068'; + } + + requirement def <'FLR-R006'> CountdownAbortRequirement { + doc /* The system shall be capable of holding or aborting the countdown if any critical system parameter violates pre-defined limits. */ + @Rationale { + text = "This capability is a critical safety function to prevent launching a vehicle that is not in a nominal state."; + } + #refinement dependency CountdownAbortRequirement to MissionRequirementsPackage::'HLR-R046'; + } + + requirement def <'FLR-R007'> Stage1ThrustInitiationRequirement { + doc /* The system shall initiate first stage main propulsion upon receiving a valid, authenticated launch command. */ + @Rationale { + text = "Reliable and timely initiation of ascent thrust is critical for leaving the launch pad and beginning the flight profile as planned."; + } + #refinement dependency 'FLR-R007' to MissionRequirementsPackage::'HLR-R062'; + } + + requirement def <'FLR-R008'> Stage1ThrustMagnitudeRequirement { + doc /* The system shall generate a propulsive force from the first stage that results in a positive vertical acceleration at liftoff. */ + @Rationale { + text = "A thrust-to-weight ratio greater than one is the fundamental condition required to overcome gravity and lift the vehicle off the launch pad."; + } + #refinement dependency 'FLR-R008' to MissionRequirementsPackage::'HLR-R062'; + } + + requirement def <'FLR-R009'> Stage2ThrustInitiationRequirement { + doc /* The system shall initiate second stage propulsion following the clean separation of the first stage. */ + @Rationale { + text = "Continuous acceleration is required to achieve the velocity needed to reach the upper atmosphere."; + } + #refinement dependency 'FLR-R009' to MissionRequirementsPackage::'HLR-R062'; + } + + requirement def <'FLR-R010'> Stage2PropulsionRequirement { + doc /* The system shall provide continuous thrust from the second stage to propel the vehicle through the upper atmosphere. */ + @Rationale { + text = "The second stage is optimized to provide efficient thrust in near-vacuum conditions."; + } + #refinement dependency 'FLR-R010' to MissionRequirementsPackage::'HLR-R062'; + } + + requirement def <'FLR-R011'> OrbitInsertionThrustInitiationRequirement { + doc /* The system shall initiate third stage propulsion to provide the final thrust needed to achieve a stable Earth orbit. */ + @Rationale { + text = "A final, precise propulsive burn is required to circularize the orbit and prevent the vehicle from falling back to Earth."; + } + #refinement dependency 'FLR-R011' to MissionRequirementsPackage::'HLR-R003'; + } + + requirement def <'FLR-R012'> OrbitInsertionThrustTerminationRequirement { + doc /* The system shall terminate third stage thrust upon receiving a cutoff command. */ + @Rationale { + text = "Precise thrust termination is critical for achieving the correct orbital parameters."; + } + #refinement dependency OrbitInsertionThrustTerminationRequirement to MissionRequirementsPackage::'HLR-R003'; + } + + requirement def <'FLR-R013'> AscentGuidanceRequirement { + doc /* The system shall autonomously control the vehicle's trajectory during ascent according to a pre-programmed flight plan. */ + @Rationale { + text = "Automated guidance is necessary to manage the complex, high-speed ascent profile with precision."; + } + #refinement dependency AscentGuidanceRequirement to MissionRequirementsPackage::'HLR-R003'; + } + + requirement def <'FLR-R014'> AscentStagingCommandRequirement { + doc /* The system shall issue commands to separate expended stages at pre-determined points in the ascent profile. */ + @Rationale { + text = "Jettisoning mass is essential for maximizing the efficiency of the upper stages."; + } + #refinement dependency 'FLR-R014' to MissionRequirementsPackage::'HLR-R003'; + } + + requirement def <'FLR-R015'> CrewAscentMonitoringRequirement { + doc /* The system shall display critical vehicle parameters to the flight crew during ascent. */ + @Rationale { + text = "The crew must have situational awareness to monitor vehicle health and make manual control or abort decisions."; + } + #refinement dependency CrewAscentMonitoringRequirement to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R016'> CrewAscentAbortRequirement { + doc /* The system shall provide an interface for the crew to manually initiate a launch abort sequence. */ + @Rationale { + text = "Manual abort is a key safety feature that provides the crew with ultimate control in a contingency."; + } + #refinement dependency CrewAscentAbortRequirement to MissionRequirementsPackage::'HLR-R046'; + } + + requirement def <'FLR-R017'> GroundTelemetryAnalysisRequirement { + doc /* The system shall receive, process, and display real-time telemetry from the launch vehicle to ground personnel. */ + @Rationale { + text = "Ground teams must have accurate, real-time data to monitor vehicle health and provide support."; + } + #refinement dependency 'FLR-R017' to MissionRequirementsPackage::'HLR-R048'; + } + + requirement def <'FLR-R018'> GroundPerformanceVerificationRequirement { + doc /* The system shall compare vehicle performance against pre-defined limits and provide go/no-go recommendations. */ + @Rationale { + text = "This function provides an independent verification of vehicle performance, enhancing mission safety."; + } + #refinement dependency GroundPerformanceVerificationRequirement to MissionRequirementsPackage::'HLR-R048'; + } + + requirement def <'FLR-R019'> TliThrustInitiationRequirement { + doc /* The system shall provide a propulsive force to cause the vehicle to escape Earth's orbit. */ + @Rationale { + text = "A major propulsive maneuver is required to increase velocity from orbital to escape speed."; + } + #refinement dependency 'FLR-R019' to MissionRequirementsPackage::'HLR-R003'; + } + + requirement def <'FLR-R020'> TliThrustControlRequirement { + doc /* The system shall guide the translunar injection burn to achieve the required trajectory accuracy. */ + @Rationale { + text = "The accuracy of this burn is critical to ensure the spacecraft arrives at the correct position and time near the Moon."; + } + #refinement dependency TliThrustControlRequirement to MissionRequirementsPackage::'HLR-R003'; + } + + requirement def <'FLR-R021'> ModuleSeparationRequirement { + doc /* The system shall enable the primary spacecraft to separate from its launch vehicle adapter. */ + @Rationale { + text = "Separation is required before the spacecraft can be reconfigured for the journey to the Moon."; + } + #refinement dependency 'FLR-R021' to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R022'> ModuleRepositioningRequirement { + doc /* The system shall enable the controlled repositioning of the primary spacecraft after separation. */ + @Rationale { + text = "The spacecraft must be turned around to face the stowed lunar module for docking."; + } + #refinement dependency 'FLR-R022' to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R023'> ModuleConnectionRequirement { + doc /* The system shall enable the physical connection and sealing of two separate spacecraft modules in space. */ + @Rationale { + text = "A rigid, pressurized connection is required to allow for crew transfer and to form the complete translunar vehicle."; + } + #refinement dependency 'FLR-R023' to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R024'> InSpacePropulsionRequirement { + doc /* The system shall provide a propulsive force for major in-space trajectory changes. */ + @Rationale { + text = "A restartable, high-thrust engine is required for critical maneuvers like lunar orbit insertion and transearth injection."; + } + #refinement dependency 'FLR-R024' to MissionRequirementsPackage::'HLR-R061'; + } + + requirement def <'FLR-R025'> AttitudeControlRequirement { + doc /* The system shall provide low-thrust propulsive forces to control the orientation of the spacecraft. */ + @Rationale { + text = "Precise attitude control is required for thermal regulation, communications antenna pointing, and alignment for main engine burns."; + } + #refinement dependency 'FLR-R025' to MissionRequirementsPackage::'HLR-R061'; + } + + requirement def <'FLR-R026'> NavigationalDataAcquisitionRequirement { + doc /* The system shall enable the acquisition of celestial navigation data. */ + @Rationale { + text = "Regular position fixes are necessary to maintain an accurate understanding of the vehicle's trajectory."; + } + #refinement dependency NavigationalDataAcquisitionRequirement to MissionRequirementsPackage::'HLR-R011'; + } + + requirement def <'FLR-R027'> TrajectoryCalculationRequirement { + doc /* The system shall calculate the vehicle's current trajectory based on navigational data. */ + @Rationale { + text = "The current trajectory must be known in order to calculate necessary course corrections."; + } + #refinement dependency TrajectoryCalculationRequirement to MissionRequirementsPackage::'HLR-R011'; + } + + requirement def <'FLR-R028'> CourseCorrectionCalculationRequirement { + doc /* The system shall calculate the required propulsive maneuver to correct any deviations from the planned trajectory. */ + @Rationale { + text = "This function is essential for ensuring an accurate arrival at the Moon and minimizing fuel usage."; + } + #refinement dependency 'FLR-R028' to MissionRequirementsPackage::'HLR-R011'; + } + + requirement def <'FLR-R029'> CourseCorrectionExecutionRequirement { + doc /* The system shall execute a calculated course correction maneuver. */ + @Rationale { + text = "The ability to act on calculated corrections is required to maintain the proper flight path."; + } + #refinement dependency 'FLR-R029' to MissionRequirementsPackage::'HLR-R011'; + } + + requirement def <'FLR-R030'> CrewSystemMonitoringRequirement { + doc /* The system shall display the status of all critical subsystems to the crew. */ + @Rationale { + text = "Continuous situational awareness of system health is required for the crew to manage the mission and respond to anomalies."; + } + #refinement dependency CrewSystemMonitoringRequirement to MissionRequirementsPackage::'HLR-R030'; + } + + requirement def <'FLR-R031'> GroundSystemMonitoringRequirement { + doc /* The system shall transmit the status of all critical subsystems to the ground. */ + @Rationale { + text = "Ground controllers provide a vital support and analysis function that depends on receiving continuous, accurate telemetry."; + } + #refinement dependency 'FLR-R031' to MissionRequirementsPackage::'HLR-R004'; + } + + requirement def <'FLR-R032'> SpacecraftDataTransmissionRequirement { + doc /* The system shall transmit voice, telemetry, and video data to the ground network. */ + @Rationale { + text = "Data transmission is required to support ground control functions and meet public engagement objectives."; + } + #refinement dependency SpacecraftDataTransmissionRequirement to MissionRequirementsPackage::'HLR-R004'; + } + + requirement def <'FLR-R033'> SpacecraftDataReceptionRequirement { + doc /* The system shall receive and process commands and voice data from the ground network. */ + @Rationale { + text = "The crew must be able to receive updated plans, information, and commands from Mission Control."; + } + #refinement dependency SpacecraftDataReceptionRequirement to MissionRequirementsPackage::'HLR-R004'; + } + + requirement def <'FLR-R034'> GroundTrackingRequirement { + doc /* The system shall track the spacecraft's position and velocity from Earth. */ + @Rationale { + text = "Continuous tracking is the primary source of navigational data for Mission Control."; + } + #refinement dependency GroundTrackingRequirement to MissionRequirementsPackage::'HLR-R048'; + } + + requirement def <'FLR-R035'> GroundCommunicationRelayRequirement { + doc /* The system shall relay communications between the spacecraft and Mission Control. */ + @Rationale { + text = "A global network is required to maintain a continuous communications link as the Earth rotates."; + } + #refinement dependency GroundCommunicationRelayRequirement to MissionRequirementsPackage::'HLR-R004'; + } + + requirement def <'FLR-R036'> CrewActivitySchedulingRequirement { + doc /* The system shall provide a structured timeline for all crew activities, including work, meals, and sleep. */ + @Rationale { + text = "A managed schedule is essential for ensuring crew members are rested and prepared for critical mission events."; + } + #refinement dependency CrewActivitySchedulingRequirement to MissionRequirementsPackage::'HLR-R028'; + } + + requirement def <'FLR-R037'> CrewRestProvisionRequirement { + doc /* The system shall provide an environment that allows for crew sleep. */ + @Rationale { + text = "Adequate rest is a fundamental requirement for maintaining crew cognitive performance and health."; + } + #refinement dependency CrewRestProvisionRequirement to MissionRequirementsPackage::'HLR-R028'; + } + + requirement def <'FLR-R038'> LoiThrustRequirement { + doc /* The system shall provide a retrograde propulsive force sufficient to reduce the vehicle's velocity for lunar capture. */ + @Rationale { + text = "A major braking maneuver is the only way to transition from a fly-by trajectory to a stable lunar orbit."; + } + #refinement dependency 'FLR-R038' to MissionRequirementsPackage::'HLR-R061'; + } + + requirement def <'FLR-R039'> LoiGuidanceRequirement { + doc /* The system shall guide the lunar orbit insertion burn to achieve the target orbital parameters. */ + @Rationale { + text = "The accuracy of the lunar orbit is critical for all subsequent operations, including rendezvous and landing."; + } + #refinement dependency 'FLR-R039' to MissionRequirementsPackage::'HLR-R011'; + } + + requirement def <'FLR-R040'> LanderSystemVerificationRequirement { + doc /* The system shall enable the crew to activate and verify the health of all Lunar Module systems prior to separation. */ + @Rationale { + text = "The lander's systems must be confirmed to be fully operational before committing to the landing."; + } + #refinement dependency 'FLR-R040' to MissionRequirementsPackage::'HLR-R002'; + } + + requirement def <'FLR-R041'> LanderInterfaceVerificationRequirement { + doc /* The system shall confirm all interfaces between the lander and the main vehicle are ready for separation. */ + @Rationale { + text = "A clean separation requires that all physical and data connections are properly configured."; + } + #refinement dependency 'FLR-R041' to MissionRequirementsPackage::'HLR-R002'; + } + + requirement def <'FLR-R042'> LanderCrewTransferRequirement { + doc /* The system shall allow the crew to transfer from the primary vehicle to the landing vehicle. */ + @Rationale { + text = "The landing crew must be inside the lander before it can be configured for independent flight."; + } + #refinement dependency LanderCrewTransferRequirement to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R043'> LanderConfigurationRequirement { + doc /* The system shall allow the crew to configure the landing vehicle for independent flight. */ + @Rationale { + text = "The lander must be switched from a stowed, dormant state to a fully operational one."; + } + #refinement dependency 'FLR-R043' to MissionRequirementsPackage::'HLR-R049'; + } + + requirement def <'FLR-R044'> ModuleDisengagementRequirement { + doc /* The system shall disengage all docking latches connecting two vehicles. */ + @Rationale { + text = "This is the primary physical action required to allow two docked vehicles to separate."; + } + #refinement dependency 'FLR-R044' to MissionRequirementsPackage::'HLR-R002'; + } + + requirement def <'FLR-R045'> ModuleSeparationManeuverRequirement { + doc /* The system shall provide a controlled, low-velocity maneuver to create distance between two separated vehicles. */ + @Rationale { + text = "A controlled maneuver is required to ensure the two vehicles separate cleanly without re-contact."; + } + #refinement dependency 'FLR-R045' to MissionRequirementsPackage::'HLR-R002'; + } + + requirement def <'FLR-R046'> DescentPropulsionRequirement { + doc /* The system shall provide a continuous, throttleable propulsive force to control the rate of descent to the lunar surface. */ + @Rationale { + text = "A variable thrust is essential for precisely managing the landing profile, from braking out of orbit to a soft touchdown."; + } + #refinement dependency 'FLR-R046' to MissionRequirementsPackage::'HLR-R002'; + } + + requirement def <'FLR-R047'> DescentDataDisplayRequirement { + doc /* The system shall provide real-time altitude and velocity data to the crew and ground controllers. */ + @Rationale { + text = "Accurate, real-time data is critical for both automated guidance and manual piloting during the hazardous landing phase."; + } + #refinement dependency 'FLR-R047' to MissionRequirementsPackage::'HLR-R002'; + } + + requirement def <'FLR-R048'> DescentDataProcessingRequirement { + doc /* The system shall process sensor data to provide accurate navigation information during landing. */ + @Rationale { + text = "Raw sensor data must be processed into actionable information for the guidance system and crew."; + } + #refinement dependency 'FLR-R048' to MissionRequirementsPackage::'HLR-R002'; + } + + requirement def <'FLR-R049'> ManualAttitudeControlRequirement { + doc /* The system shall allow the crew to take manual control of the lander's attitude. */ + @Rationale { + text = "Manual control is a critical function for making fine adjustments to the landing site."; + } + #refinement dependency 'FLR-R049' to MissionRequirementsPackage::'HLR-R047'; + } + + requirement def <'FLR-R050'> ManualPositionControlRequirement { + doc /* The system shall enable horizontal repositioning to avoid hazards. */ + @Rationale { + text = "The ability to fly over unexpected hazards like craters or boulder fields is essential for landing safety."; + } + #refinement dependency 'FLR-R050' to MissionRequirementsPackage::'HLR-R047'; + } + + requirement def <'FLR-R051'> PostLandingSafingRequirement { + doc /* The system shall allow the crew to place all lander systems into a safe, quiescent state after touchdown. */ + @Rationale { + text = "Securing the vehicle's systems, especially propulsion, is the first priority after a successful landing."; + } + #refinement dependency PostLandingSafingRequirement to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R052'> PostLandingVerificationRequirement { + doc /* The system shall allow the crew to verify that the vehicle is in a stable state and ready for surface operations. */ + @Rationale { + text = "The health of the vehicle must be confirmed before committing to an extravehicular activity."; + } + #refinement dependency PostLandingVerificationRequirement to MissionRequirementsPackage::'HLR-R049'; + } + + requirement def <'FLR-R053'> EgressPreparationRequirement { + doc /* The system shall allow the crew to don and check out their spacesuits. */ + @Rationale { + text = "Spacesuit integrity must be confirmed before the crew is exposed to vacuum."; + } + #refinement dependency 'FLR-R053' to MissionRequirementsPackage::'HLR-R033'; + } + + requirement def <'FLR-R054'> CabinDepressurizationRequirement { + doc /* The system shall be capable of depressurizing the lander cabin to the external vacuum environment. */ + @Rationale { + text = "Depressurization is a prerequisite for opening the hatch to the lunar surface."; + } + #refinement dependency CabinDepressurizationRequirement to MissionRequirementsPackage::'HLR-R033'; + } + + requirement def <'FLR-R055'> SurfaceMobilityRequirement { + doc /* The system shall enable astronauts to traverse the lunar surface. */ + @Rationale { + text = "Mobility is fundamental to exploring the area around the lander and performing scientific tasks."; + } + #refinement dependency SurfaceMobilityRequirement to MissionRequirementsPackage::'HLR-R036'; + } + + requirement def <'FLR-R056'> SymbolicDeploymentRequirement { + doc /* The system shall enable the crew to deploy a national symbol on the lunar surface. */ + @Rationale { + text = "Fulfilling this key political and public objective of the mission was a primary requirement."; + } + #refinement dependency SymbolicDeploymentRequirement to MissionRequirementsPackage::'HLR-R009'; + } + + requirement def <'FLR-R057'> SampleCollectionRequirement { + doc /* The system shall enable the collection of lunar material. */ + @Rationale { + text = "The primary scientific objective of the mission was to return physical samples from the Moon."; + } + #refinement dependency SampleCollectionRequirement to MissionRequirementsPackage::'HLR-R006'; + } + + requirement def <'FLR-R058'> SampleStorageRequirement { + doc /* The system shall provide storage for collected samples that prevents terrestrial contamination. */ + @Rationale { + text = "The scientific value of the samples depends on them remaining in a pristine, uncontaminated state."; + } + #refinement dependency SampleStorageRequirement to MissionRequirementsPackage::'HLR-R038'; + } + + requirement def <'FLR-R059'> InstrumentDeploymentRequirement { + doc /* The system shall enable the crew to deploy scientific experiment packages on the lunar surface. */ + @Rationale { + text = "Leaving behind long-term experiments was a key scientific goal to gather data after the crew departed."; + } + #refinement dependency InstrumentDeploymentRequirement to MissionRequirementsPackage::'HLR-R007'; + } + + requirement def <'FLR-R060'> VisualTransmissionRequirement { + doc /* The system shall enable the deployment of a visual transmission system. */ + @Rationale { + text = "Transmitting live images from the Moon was a critical public engagement and historical documentation requirement."; + } + #refinement dependency 'FLR-R060' to MissionRequirementsPackage::'HLR-R063'; + } + + requirement def <'FLR-R061'> EvaIngressRequirement { + doc /* The system shall allow the crew to re-enter the lander cabin with all collected samples and equipment. */ + @Rationale { + text = "A safe return to the pressurized cabin is required to conclude the surface exploration."; + } + #refinement dependency EvaIngressRequirement to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R062'> CabinRepressurizationRequirement { + doc /* The system shall allow the crew to re-pressurize the lander cabin. */ + @Rationale { + text = "A breathable atmosphere must be restored before the crew can doff their spacesuits."; + } + #refinement dependency CabinRepressurizationRequirement to MissionRequirementsPackage::'HLR-R005'; + } + + requirement def <'FLR-R063'> SurfaceHabitationRequirement { + doc /* The system shall provide a habitable environment for the crew to sleep and eat on the lunar surface. */ + @Rationale { + text = "Crew rest is essential for performance and safety, especially before the critical ascent phase."; + } + #refinement dependency SurfaceHabitationRequirement to MissionRequirementsPackage::'HLR-R028'; + } + + requirement def <'FLR-R064'> SurfaceTimelineManagementRequirement { + doc /* The system shall manage the timeline to ensure readiness for ascent within the required orbital mechanics window. */ + @Rationale { + text = "The ascent must be timed precisely to allow for a successful rendezvous with the orbiting primary vehicle."; + } + #refinement dependency SurfaceTimelineManagementRequirement to MissionRequirementsPackage::'HLR-R049'; + } + + requirement def <'FLR-R065'> AscentThrustInitiationRequirement { + doc /* The system shall initiate the ascent engine using the descent stage as a launch platform. */ + @Rationale { + text = "A successful ignition is the single most critical event for getting the crew off the Moon."; + } + #refinement dependency 'FLR-R065' to MissionRequirementsPackage::'HLR-R049'; + } + + requirement def <'FLR-R066'> AscentPropulsionRequirement { + doc /* The system shall provide a continuous, non-throttleable propulsive force to achieve lunar orbit. */ + @Rationale { + text = "A fixed, highly reliable thrust profile was designed to place the ascent stage into a predictable orbit."; + } + #refinement dependency 'FLR-R066' to MissionRequirementsPackage::'HLR-R049'; + } + + requirement def <'FLR-R067'> RendezvousCalculationRequirement { + doc /* The system shall process tracking data to compute the required maneuvers for rendezvous. */ + @Rationale { + text = "Precise calculations are required to ensure the complex orbital mechanics of the rendezvous are successful."; + } + #refinement dependency 'FLR-R067' to MissionRequirementsPackage::'HLR-R011'; + } + + requirement def <'FLR-R068'> RendezvousExecutionRequirement { + doc /* The system shall execute a series of precise burns to match the orbit of and approach the target vehicle. */ + @Rationale { + text = "The execution of the rendezvous plan is what brings the two vehicles into close proximity for docking."; + } + #refinement dependency 'FLR-R068' to MissionRequirementsPackage::'HLR-R011'; + } + + requirement def <'FLR-R069'> DockingApproachRequirement { + doc /* The system shall allow the crew to pilot the final approach to the target vehicle. */ + @Rationale { + text = "Manual control during the terminal phase of docking provides the fine control necessary for a safe connection."; + } + #refinement dependency 'FLR-R069' to MissionRequirementsPackage::'HLR-R011'; + } + + requirement def <'FLR-R070'> DockingLatchingRequirement { + doc /* The system shall achieve a successful capture and rigid latching of the two vehicles. */ + @Rationale { + text = "A secure, rigid connection is essential for the safe transfer of crew and materials."; + } + #refinement dependency 'FLR-R070' to MissionRequirementsPackage::'HLR-R053'; + } + + requirement def <'FLR-R071'> IntervehicularCrewTransferRequirement { + doc /* The system shall allow the crew to move between two docked vehicles. */ + @Rationale { + text = "This is the primary function enabled by docking and is required to get the landing crew back into the return vehicle."; + } + #refinement dependency IntervehicularCrewTransferRequirement to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R072'> IntervehicularSampleTransferRequirement { + doc /* The system shall allow the crew to transfer all collected lunar samples to the return vehicle. */ + @Rationale { + text = "The scientific goals of the mission are not met until the samples are safely stowed for the journey home."; + } + #refinement dependency IntervehicularSampleTransferRequirement to MissionRequirementsPackage::'HLR-R006'; + } + + requirement def <'FLR-R073'> AscentStageSeparationRequirement { + doc /* The system shall allow the crew to seal the hatches and disengage the docking latches. */ + @Rationale { + text = "The ascent stage must be separated from the primary vehicle before the journey back to Earth."; + } + #refinement dependency 'FLR-R073' to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R074'> AscentStageDisposalRequirement { + doc /* The system shall provide a controlled separation from the ascent stage. */ + @Rationale { + text = "The no-longer-needed ascent stage must be disposed of in a safe manner that does not interfere with the primary vehicle."; + } + #refinement dependency 'FLR-R074' to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R075'> TeiPropulsionRequirement { + doc /* The system shall provide a propulsive force to cause the vehicle to escape lunar orbit and enter a trans-Earth trajectory. */ + @Rationale { + text = "This major propulsive maneuver is the critical event required to start the journey home."; + } + #refinement dependency 'FLR-R075' to MissionRequirementsPackage::'HLR-R061'; + } + + requirement def <'FLR-R076'> ReentryConfigurationRequirement { + doc /* The system shall allow the crew to perform final system checks and configure the vehicle for atmospheric entry. */ + @Rationale { + text = "The vehicle must be in a specific configuration to survive the stresses of reentry."; + } + #refinement dependency ReentryConfigurationRequirement to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R077'> ServiceModuleJettisonRequirement { + doc /* The system shall execute a pyrotechnic separation of the primary crew vehicle from its main support module. */ + @Rationale { + text = "The main support module is not designed for reentry and must be discarded."; + } + #refinement dependency 'FLR-R077' to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R078'> CleanSeparationRequirement { + doc /* The system shall ensure the two separated modules do not re-contact. */ + @Rationale { + text = "Re-contact after separation could damage the primary crew vehicle and jeopardize the safety of reentry."; + } + #refinement dependency 'FLR-R078' to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R079'> ReentryGuidanceRequirement { + doc /* The system shall use the vehicle's shape and orientation to control its trajectory through the atmosphere. */ + @Rationale { + text = "Guidance is required to manage extreme heating and to steer the vehicle toward the target landing zone."; + } + #refinement dependency 'FLR-R079' to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R080'> HeatDissipationRequirement { + doc /* The system shall protect the crew and vehicle structure from the extreme heat of atmospheric entry. */ + @Rationale { + text = "Without a method to dissipate thermal energy, the vehicle would be destroyed during reentry."; + } + #refinement dependency 'FLR-R080' to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R081'> DeceleratorDeploymentRequirement { + doc /* The system shall deploy a sequence of aerodynamic decelerators at pre-defined altitudes. */ + @Rationale { + text = "Parachutes are required to slow the vehicle from supersonic speeds to a safe landing velocity."; + } + #refinement dependency 'FLR-R081' to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R082'> FinalVelocityRequirement { + doc /* The system shall slow the vehicle to a safe landing velocity. */ + @Rationale { + text = "The final velocity must be low enough to ensure the integrity of the vehicle and the safety of the crew upon impact."; + } + #refinement dependency FinalVelocityRequirement to MissionRequirementsPackage::'HLR-R002'; + } + + requirement def <'FLR-R083'> WaterLandingRequirement { + doc /* The system shall execute the final water landing. */ + @Rationale { + text = "The mission was designed for a water landing in a pre-determined location."; + } + #refinement dependency WaterLandingRequirement to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R084'> PostLandingSystemsRequirement { + doc /* The system shall automatically deploy flotation devices and beacons after landing. */ + @Rationale { + text = "These systems are required to keep the vehicle upright and to aid recovery forces in locating it."; + } + #refinement dependency PostLandingSystemsRequirement to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R085'> CrewRecoveryRequirement { + doc /* The system shall allow recovery forces to locate, secure, and retrieve the crew and crew vehicle from the ocean. */ + @Rationale { + text = "The final phase of ensuring crew safety is their successful recovery from the landing site."; + } + #refinement dependency CrewRecoveryRequirement to MissionRequirementsPackage::'HLR-R001'; + } + + requirement def <'FLR-R086'> VesselTransferRequirement { + doc /* The system shall transport the crew and crew vehicle to the primary recovery ship. */ + @Rationale { + text = "The crew and vehicle must be brought into a controlled environment for post-mission procedures."; + } + #refinement dependency VesselTransferRequirement to MissionRequirementsPackage::'HLR-R010'; + } + + requirement def <'FLR-R087'> QuarantineImplementationRequirement { + doc /* The system shall implement Level V biological quarantine procedures for the crew upon recovery. */ + @Rationale { + text = "This was a critical planetary protection requirement to prevent potential contamination of Earth's biosphere."; + } + #refinement dependency QuarantineImplementationRequirement to MissionRequirementsPackage::'HLR-R010'; + } + + requirement def <'FLR-R088'> QuarantineHabitationRequirement { + doc /* The system shall place the crew into a specialized quarantine facility for a 21-day period. */ + @Rationale { + text = "The duration and facility were specified to ensure any potential extraterrestrial organisms could be detected."; + } + #refinement dependency QuarantineHabitationRequirement to MissionRequirementsPackage::'HLR-R010'; + } + + requirement def <'FLR-R089'> SamplePreservationRequirement { + doc /* The system shall place the returned lunar samples into secure, contamination-free containers. */ + @Rationale { + text = "The scientific value of the samples depends on them being handled and stored correctly."; + } + #refinement dependency SamplePreservationRequirement to MissionRequirementsPackage::'HLR-R038'; + } + + requirement def <'FLR-R090'> SampleTransportRequirement { + doc /* The system shall transport the samples to a designated receiving laboratory for analysis. */ + @Rationale { + text = "The ultimate goal of sample collection is their analysis by the scientific community."; + } + #refinement dependency SampleTransportRequirement to MissionRequirementsPackage::'HLR-R006'; + } + + requirement def <'FLR-R091'> TGNCNavigationAccuracy { + doc /* The Apollo 11 Mission's navigation system shall determine spacecraft position with an accuracy of +/- 5 kilometers + during Trans-Lunar Coast, at least once every 6 hours. */ + @Rationale { + text = "Accurate and frequent navigation updates are essential for maintaining the correct trajectory to the Moon, ensuring efficiency and safety during the long Trans-Lunar Coast phase."; + } + + #refinement dependency 'HLR-R011' to CapabilitiesPackage::AutonomousAndAssistedNavigationGuidanceAndControl; + } + + requirement def <'FLR-R092'> ManualPilotingLogic { + doc /* The Apollo 11 Mission's control system shall enable manual piloting of the lunar lander to allow for + horizontal repositioning of +/- 200 meters within the landing ellipse to avoid hazards. */ + @Rationale { + text = "Manual piloting capability is essential for avoiding unexpected surface hazards (e.g., boulders, craters) at the chosen landing site, directly enhancing mission safety and probability of successful landing."; + } + + #refinement dependency 'FLR-R092' to CapabilitiesPackage::HumanPerformanceUnderExtremeStress; + #refinement dependency 'FLR-R092' to CapabilitiesPackage::AdaptabilityAndProblemSolving; + } + + + requirement def <'FLR-R093'> SystemInterfaceCompatibility { + doc /* All major system interfaces of the Apollo 11 Mission (e.g., spacecraft stacking, docking mechanisms) + shall demonstrate 100% compatibility through full-scale integrated fit checks and electrical interface tests + prior to final assembly. */ + @Rationale { + text = "Perfect interface compatibility is critical to prevent physical or electrical malfunctions between joined spacecraft components, ensuring safe and functional assembly and operation."; + } + + #refinement dependency 'FLR-R093' to CapabilitiesPackage::ComplexLogisticsAndIntegration; + } + + requirement def <'FLR-R094'> TrainingSimulatorHours { + doc /* All flight crew members for the Apollo 11 Mission shall complete a minimum of 200 hours + of specialized lunar lander simulator training prior to launch. */ + @Rationale { + text = "Extensive simulator training is crucial to ensure astronauts are highly proficient and prepared for complex and critical operations like lunar landing, enhancing safety and success."; + } + + #refinement dependency 'FLR-R094' to CapabilitiesPackage::CrewTrainingAndSimulation; + } + + requirement def <'FLR-R095'> CourseCorrectionCapability { + doc /* The guidance system shall calculate and execute trajectory adjustments + to maintain the designated mission corridor. */ + @Rationale { + text = "The mission needs the ability to correct course deviations; the technical accuracy is delegated to technical requirements."; + } + #refinement dependency CourseCorrectionCapability to MissionRequirementsPackage::'HLR-R011'; + } + + requirement def <'FLR-R096'> SpacecraftOrientationControl { + doc /* The system shall autonomously maintain the commanded orientation + for thermal regulation and communications. */ + @Rationale { + text = "Logical function of attitude control. Specific stability metrics belong in the technical level."; + } + #refinement dependency SpacecraftOrientationControl to MissionRequirementsPackage::'HLR-R061'; + } + + requirement def <'FLR-R097'> DescentDataAcquisition { + doc /* The landing system shall acquire real-time altitude and velocity telemetry + during the powered descent phase. */ + @Rationale { + text = "Functional bridge for sensor logic. Specific radar precision metrics are moved to the technical level."; + } + #refinement dependency DescentDataAcquisition to MissionRequirementsPackage::'HLR-R002'; + } + + requirement def <'FLR-R098'> LaunchVehicleAscentThrust { + doc /* The launch system shall provide sufficient total impulse to overcome + Earth's gravity and achieve orbit insertion. */ + @Rationale { + text = "Functional logic for ascent. The specific force magnitude value belongs in the technical layer."; + } + #refinement dependency LaunchVehicleAscentThrust to MissionRequirementsPackage::'HLR-R062'; + } + + requirement def <'FLR-R099'> DescentRateModulation { + doc /* The lander shall provide the capability to vary engine thrust to control + the rate of descent to the lunar surface. */ + @Rationale { + text = "Functional behavior for landing. Throttling percentages are defined in the technical level."; + } + #refinement dependency DescentRateModulation to MissionRequirementsPackage::'HLR-R002'; + } + + requirement def <'FLR-R100'> ThermalProtectionLogic { + doc /* The entry vehicle shall dissipate aerodynamic heat to protect + internal volumes during atmospheric return. */ + @Rationale { + text = "Functional logic of the heat shield. Internal temperature rise limits belong at the technical level."; + } + #refinement dependency ThermalProtectionLogic to MissionRequirementsPackage::'HLR-R062'; + } + + requirement def <'FLR-R101'> TouchdownEnergyDissipation { + doc /* The landing gear system shall mechanically attenuate landing forces + to prevent structural damage to the spacecraft. */ + @Rationale { + text = "Functional description of energy absorption. Velocity metrics are moved to the technical level."; + } + #refinement dependency TouchdownEnergyDissipation to MissionRequirementsPackage::'HLR-R002'; + } + + requirement def <'FLR-R102'> AtmosphericScrubbingFunction { + doc /* The life support system shall remove metabolic byproducts and + particles from the cabin air. */ + @Rationale { + text = "Functional behavior for the ECS. Specific filter efficiencies and levels belong in technical requirements."; + } + #refinement dependency AtmosphericScrubbingFunction to MissionRequirementsPackage::'HLR-R005'; + } + + requirement def <'FLR-R103'> TelemetryStreamIntegrity { + doc /* The communication system shall ensure the fidelity of transmitted + data between the spacecraft and ground segment. */ + @Rationale { + text = "Functional description of data link quality. Integrity metrics belong in technical specifications."; + } + #refinement dependency TelemetryStreamIntegrity to MissionRequirementsPackage::'HLR-R063'; + } + + requirement def <'FLR-R104'> EMUPressureMaintenance { + doc /* The Extravehicular Mobility Unit shall provide a constant pressurized + volume for the astronaut in a vacuum environment. */ + @Rationale { + text = "Functional requirement for suit logic. The specific pressure setpoint belongs in the technical level."; + } + #refinement dependency EMUPressureMaintenance to MissionRequirementsPackage::'HLR-R064'; + } + + requirement def <'FLR-R105'> SoftwareMissionProficiency { + doc /* The flight software shall be verified to perform all guidance + and control functions without mission-critical errors. */ + @Rationale { + text = "Functional goal for software quality. The verification defect rate belongs in the technical level."; + } + #refinement dependency SoftwareMissionProficiency to MissionRequirementsPackage::'HLR-R065'; + } + + requirement def <'FLR-R106'> SpaceEnvironmentResilience { + doc /* Spacecraft materials shall maintain their structural and functional + properties under vacuum and thermal cycling. */ + @Rationale { + text = "Functional resilience goal. Exposure constraints belong in the technical layer."; + } + #refinement dependency SpaceEnvironmentResilience to MissionRequirementsPackage::'HLR-R062'; + } + + + + requirement def <'FLR-R107'> VisualDataCapture { + doc /* The system shall capture high-resolution still and motion imagery of + lunar operations. */ + @Rationale { + text = "Required to meet scientific and public documentation goals."; + } + #refinement dependency 'FLR-R107' to MissionRequirementsPackage::'HLR-R008'; + } + + requirement def <'FLR-R108'> WasteContainmentFunction { + doc /* The life support system shall provide localized collection and + sealed storage for all metabolic waste. */ + @Rationale { + text = "Essential for maintaining cabin hygiene and crew health."; + } + #refinement dependency 'FLR-R108' to MissionRequirementsPackage::'HLR-R026'; + } + + requirement def <'FLR-R109'> CrossVehicleAudioLink { + doc /* The communication system shall establish a dedicated VHF audio link + between the LM and CSM during lunar operations. */ + @Rationale { + text = "Required for coordination during critical mission phases."; + } + #refinement dependency 'FLR-R109' to MissionRequirementsPackage::'HLR-R032'; + } + + requirement def <'FLR-R110'> ComponentFaultTolerance { + doc /* Critical systems shall maintain nominal output levels despite + the loss of any single primary component. */ + @Rationale { + text = "Implements the redundancy philosophy required for safety."; + } + #refinement dependency 'FLR-R110' to MissionRequirementsPackage::'HLR-R045'; + } + + requirement def <'FLR-R111'> HumanMedicalSelfSufficiency { + doc /* The system shall provide medical kits and diagnostic guides + enabling the crew to treat minor injuries. */ + @Rationale { + text = "Necessary due to the extreme delay in Earth-based assistance."; + } + #refinement dependency 'FLR-R111' to MissionRequirementsPackage::'HLR-R052'; + } + + requirement def <'FLR-R112'> DataRedundancyArchiving { + doc /* The ground segment shall mirror all incoming telemetry to + multiple geographic locations for permanent archival. */ + @Rationale { + text = "Ensures mission data remains available for future generations."; + } + #refinement dependency 'FLR-R112' to MissionRequirementsPackage::'HLR-R060'; + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/FunctionsPackage.sysml b/language/src/test/resources/Apollo_11/FunctionsPackage.sysml new file mode 100644 index 00000000..48974b9a --- /dev/null +++ b/language/src/test/resources/Apollo_11/FunctionsPackage.sysml @@ -0,0 +1,528 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package FunctionsPackage { + + private import MissionPhasesPackage::*; + private import MissionRequirementsPackage::*; + private import ScalarValues::*; + private import ModelingMetadata::*; + private import CoSMAPackage::*; + + item def VehicleStatus { doc /* Represents the complete state of a vehicle system, including configuration, resources, and trajectory. */ } + item def CrewStatus { doc /* Represents the state of the crew, including health and readiness. */ } + item def MissionPlan { doc /* Contains the overall objectives and parameters for the mission. */ } + item def LunarSamples { doc /* Represents the collected geological materials from the Moon. */ } + item def ScientificData { doc /* Represents data gathered from deployed scientific instruments. */ } + item def MissionReport { doc /* A comprehensive report detailing the outcomes of the mission. */ } + + // =================================================================== + // Level 4: Leaf-Level Function Definitions + // NOTE: These functions refine the abstract Operations from the MissionPhasesPackage. + // =================================================================== + + action def PerformPropellantLoading :> Function { + in currentStatus: VehicleStatus; + out loadedStatus: VehicleStatus; + doc /* Fills and conditions all necessary propellants and consumables for the mission. */ + #refinement dependency PerformPropellantLoading to OperationsPackage::LoadConsumablesAndPropellants; + } + + action def PerformCrewIngress :> Function { + out isCrewAboard: Boolean; + doc /* Transfers the flight crew into the vehicle and secures them for launch. */ + #refinement dependency PerformCrewIngress to OperationsPackage::TransferCrewToVehicle; + } + + action def ExecuteTerminalCountdown :> Function { + out goForLaunch: Boolean; + doc /* Executes the final automated and manual checks leading to launch. */ + #refinement dependency ExecuteTerminalCountdown to OperationsPackage::PerformPreLaunchCountdown; + } + action def ProvideStage1Thrust :> Function { + in launchReadyStatus: VehicleStatus; + out stage1BurnoutStatus: VehicleStatus; + doc /* Provides primary thrust from liftoff through the first two and a half minutes of flight. */ + #refinement dependency ProvideStage1Thrust to OperationsPackage::ExecuteLaunchSequence; + } + action def ProvideStage2Thrust :> Function { + in stage1BurnoutStatus: VehicleStatus; + out stage2BurnoutStatus: VehicleStatus; + doc /* Provides thrust after first stage separation to propel the vehicle to the edge of space. */ + #refinement dependency ProvideStage2Thrust to OperationsPackage::ExecuteLaunchSequence; + } + action def ProvideOrbitInsertionThrust :> Function { + in stage2BurnoutStatus: VehicleStatus; + out orbitalStatus: VehicleStatus; + doc /* Provides the final thrust needed to achieve a stable Earth orbit. */ + #refinement dependency ProvideOrbitInsertionThrust to OperationsPackage::ExecuteLaunchSequence; + } + action def GuideAscentTrajectory :> Function { + in ascentStatus: VehicleStatus; + out guidedStatus: VehicleStatus; + doc /* Autonomously executes the pre-programmed flight plan, controlling engine gimbaling and staging events. */ + #refinement dependency GuideAscentTrajectory to OperationsPackage::MonitorAscentTrajectory; + } + action def ObserveAscentDataFromCockpit :> Function { + in ascentStatus: VehicleStatus; + doc /* Allows the crew to monitor spacecraft displays and provides manual inputs or abort commands if necessary. */ + #refinement dependency ObserveAscentDataFromCockpit to OperationsPackage::MonitorAscentTrajectory; + } + action def AnalyzeLaunchTelemetryFromGround :> Function { + in ascentStatus: VehicleStatus; + doc /* Receives and analyzes telemetry on the ground to provide go/no-go decisions to the crew. */ + #refinement dependency AnalyzeLaunchTelemetryFromGround to OperationsPackage::MonitorAscentTrajectory; + } + + action def ProvideTranslunarInjectionThrust :> Function { + in currentStatus: VehicleStatus; + out postBurnStatus: VehicleStatus; + doc /* Re-ignites the engine to propel the spacecraft out of Earth orbit and toward the Moon. */ + #refinement dependency ProvideTranslunarInjectionThrust to OperationsPackage::ExecuteTLIBurn; + } + action def ControlTranslunarInjectionBurn :> Function { + in currentStatus: VehicleStatus; + doc /* Guides the TLI burn to ensure accuracy. */ + #refinement dependency ControlTranslunarInjectionBurn to OperationsPackage::ExecuteTLIBurn; + } + action def ExecuteTranspositionManeuver :> Function { + in currentStatus: VehicleStatus; + out maneuveringStatus: VehicleStatus; + doc /* Pilots the Command/Service Module after separation from the S-IVB stage. */ + #refinement dependency ExecuteTranspositionManeuver to OperationsPackage::PerformTranspositionDockingExtraction; + } + action def ProvideAttitudeControlThrust :> Function { + in currentStatus: VehicleStatus; + out newAttitudeStatus: VehicleStatus; + doc /* Fires Reaction Control System thrusters to orient the spacecraft. */ + #refinement dependency ProvideAttitudeControlThrust to OperationsPackage::PerformTranspositionDockingExtraction; + } + action def MechanicallyLatchModules :> Function { + in currentStatus: VehicleStatus; + out dockedStatus: VehicleStatus; + doc /* Engages the docking probe and latches to form a rigid connection between two modules. */ + #refinement dependency MechanicallyLatchModules to OperationsPackage::PerformTranspositionDockingExtraction; + } + action def CalculateCourseCorrection :> Function { + in currentStatus: VehicleStatus; + out burnPlan: VehicleStatus; // Using VehicleStatus to represent the plan + doc /* Processes navigational data to determine the required vector for a mid-course correction burn. */ + #refinement dependency CalculateCourseCorrection to OperationsPackage::ConductMidCourseCorrections; + } + action def ExecuteCourseCorrectionBurn :> Function { + in burnPlan: VehicleStatus; + out correctedStatus: VehicleStatus; + doc /* Fires the main engine or RCS thrusters to execute the planned trajectory adjustment. */ + #refinement dependency ExecuteCourseCorrectionBurn to OperationsPackage::ConductMidCourseCorrections; + } + + action def MonitorOnboardSystems :> Function { + in currentStatus: VehicleStatus; + doc /* Allows the crew to observe and manage spacecraft systems from inside the cabin. */ + #refinement dependency MonitorOnboardSystems to OperationsPackage::MonitorSpacecraftSystems; + } + action def MonitorDownlinkedTelemetry :> Function { + in currentStatus: VehicleStatus; + doc /* Allows ground controllers to observe spacecraft systems via telemetry. */ + #refinement dependency MonitorDownlinkedTelemetry to OperationsPackage::MonitorSpacecraftSystems; + } + action def TransmitAndReceiveSpacecraftSignals :> Function { + in currentStatus: VehicleStatus; + doc /* Manages the vehicle's antennas and radios to send and receive data. */ + #refinement dependency TransmitAndReceiveSpacecraftSignals to OperationsPackage::CommunicateWithMissionControl; + } + + action def TrackAndRelayGroundSignals :> Function { + doc /* Manages the global network of ground stations to maintain a continuous link with the spacecraft. */ + #refinement dependency TrackAndRelayGroundSignals to OperationsPackage::CommunicateWithMissionControl; + } + action def ManageCrewSchedules :> Function { + in currentStatus: CrewStatus; + out restedStatus: CrewStatus; + doc /* Manages the schedule for crew work, sleep, and meals. */ + #refinement dependency ManageCrewSchedules to OperationsPackage::ManageCrewRestPeriods; + } + action def ProvideLunarOrbitInsertionThrust :> Function { + in currentStatus: VehicleStatus; + out postBurnStatus: VehicleStatus; + doc /* Fires the main engine to slow the spacecraft for lunar capture. */ + #refinement dependency ProvideLunarOrbitInsertionThrust to OperationsPackage::ExecuteLOIBurn; + } + + action def ControlLunarOrbitInsertionBurn :> Function { + in currentStatus: VehicleStatus; + out finalStatus: VehicleStatus; + doc /* Guides the LOI burn to achieve the target orbit. */ + #refinement dependency ControlLunarOrbitInsertionBurn to OperationsPackage::ExecuteLOIBurn; + } + + action def PerformOrbitalSystemCheckouts :> Function { + in currentStatus: VehicleStatus; + out checkedVehicle: VehicleStatus; + doc /* Performs system health checks while in lunar orbit. */ + #refinement dependency PerformOrbitalSystemCheckouts to OperationsPackage::ConductLunarOrbitCheckouts; + } + action def PrepareLanderForSeparation :> Function { + in currentStatus: VehicleStatus; + out preppedVehicle: VehicleStatus; + doc /* Activates and configures the Lunar Module for independent flight. */ + #refinement dependency PrepareLanderForSeparation to OperationsPackage::PrepareLMforUndocking; + } + action def SeparateLanderFromOrbiter :> Function { + in currentStatus: VehicleStatus; + out lander: VehicleStatus; + out orbiter: VehicleStatus; + doc /* Physically separates the two spacecraft. */ + #refinement dependency SeparateLanderFromOrbiter to OperationsPackage::PerformLMUndocking; + } + action def ExecuteDescentBurn :> Function { + in currentStatus: VehicleStatus; + out descentStatus: VehicleStatus; + doc /* Manages the main engine burn for powered descent. */ + #refinement dependency ExecuteDescentBurn to OperationsPackage::ExecutePoweredDescentBurn; + } + action def MonitorDescent :> Function { + in currentStatus: VehicleStatus; + out monitoredStatus: VehicleStatus; + doc /* Tracks altitude and velocity telemetry during landing. */ + #refinement dependency MonitorDescent to OperationsPackage::MonitorDescentTelemetry; + } + action def ManuallyPilotLander :> Function { + in currentStatus: VehicleStatus; + out pilotedStatus: VehicleStatus; + doc /* Allows for manual control of the lander to avoid hazards. */ + #refinement dependency ManuallyPilotLander to OperationsPackage::PerformManualPiloting; + } + action def PerformPostLandingCheck :> Function { + in currentStatus: VehicleStatus; + doc /* Verifies the state of the vehicle after landing on the Moon. */ + #refinement dependency PerformPostLandingCheck to OperationsPackage::ConductLMPostLandingChecks; + } + action def PrepareForExtravehicularActivity :> Function { + in currentStatus: VehicleStatus; + doc /* Prepares the cabin and suits for surface exploration. */ + #refinement dependency PrepareForExtravehicularActivity to OperationsPackage::PrepareForEVA; + } + action def ProvideIndividualLifesupport :> Function { + doc /* Provide life support for crew member on the lunar surface outside the lander. */ + #refinement dependency ProvideIndividualLifesupport to OperationsPackage::PerformLunarEVA; + } + + action def ConductSurfaceExploration :> Function { + in currentStatus: VehicleStatus; + doc /* The act of the crew operating on the lunar surface. */ + #refinement dependency ConductSurfaceExploration to OperationsPackage::PerformLunarEVA; + } + action def GatherLunarSamples :> Function { + out samples: LunarSamples; + doc /* Collects and stores geological samples. */ + #refinement dependency GatherLunarSamples to OperationsPackage::CollectLunarSamples; + } + action def DeploySurfaceExperiments :> Function { + out scienceData: ScientificData; + doc /* Sets up scientific instrument packages on the lunar surface. */ + #refinement dependency DeploySurfaceExperiments to OperationsPackage::DeployScientificInstruments; + } + + action def CompleteExtravehicularActivity :> Function { + in currentStatus: VehicleStatus; + doc /* Concludes the surface exploration and has the crew re-enter the vehicle. */ + #refinement dependency CompleteExtravehicularActivity to OperationsPackage::ConcludeEVA; + } + + action def ConductSurfaceRestPeriod :> Function { + doc /* Manages the crew rest period while on the lunar surface. */ + #refinement dependency ConductSurfaceRestPeriod to OperationsPackage::ManageLunarSurfaceRestPeriod; + } + + action def ExecuteAscentBurn :> Function { + in currentStatus: VehicleStatus; + out ascentVehicle: VehicleStatus; + doc /* Fires the ascent engine to lift off from the Moon. */ + #refinement dependency ExecuteAscentBurn to OperationsPackage::ExecuteLunarAscentBurn; + } + + action def CalculateRendezvousManeuvers :> Function { + in currentStatus: VehicleStatus; + out rendezvousPlan: VehicleStatus; + doc /* Processes tracking data to compute the required burns for rendezvous. */ + #refinement dependency CalculateRendezvousManeuvers to OperationsPackage::PerformRendezvousManeuvers; + } + action def ExecuteRendezvousBurns :> Function { + in rendezvousPlan: VehicleStatus; + out proximalVehicle: VehicleStatus; + doc /* Fires RCS thrusters to execute the rendezvous plan and approach the target vehicle. */ + #refinement dependency ExecuteRendezvousBurns to OperationsPackage::PerformRendezvousManeuvers; + } + + action def ConnectSpacecraft :> Function { + in currentStatus: VehicleStatus; + out dockedVehicle: VehicleStatus; + doc /* Performs the physical docking of the two vehicles. */ + #refinement dependency ConnectSpacecraft to OperationsPackage::ConductLMCSMDocking; + } + action def TransferCrewAndMaterials :> Function { + in currentStatus: VehicleStatus; + in samples: LunarSamples; + out postTransferVehicle: VehicleStatus; + doc /* Moves the crew and collected samples from the ascent stage to the main vehicle. */ + #refinement dependency TransferCrewAndMaterials to OperationsPackage::TransferCrewAndSamples; + } + action def DiscardAscentStage :> Function { + in currentStatus: VehicleStatus; + out finalVehicle: VehicleStatus; + doc /* Jettisons the Lunar Module ascent stage. */ + #refinement dependency DiscardAscentStage to OperationsPackage::JettisonLM; + } + action def ExecuteTransearthBurn :> Function { + in currentStatus: VehicleStatus; + out finalStatus: VehicleStatus; + doc /* Performs the major propulsive maneuver to leave lunar orbit for Earth. */ + #refinement dependency ExecuteTransearthBurn to OperationsPackage::ExecuteTEIBurn; + } + action def PrepareVehicleForReentry :> Function { + in currentStatus: VehicleStatus; + out finalStatus: VehicleStatus; + doc /* Configures the main vehicle for atmospheric entry. */ + #refinement dependency PrepareVehicleForReentry to OperationsPackage::PrepareCMforReentry; + } + action def SeparateReturnCapsule :> Function { + in currentStatus: VehicleStatus; + out capsule: VehicleStatus; + doc /* Jettisons the service module before entering the atmosphere. */ + #refinement dependency SeparateReturnCapsule to OperationsPackage::SeparateModules; + } + action def GuideAtmosphericEntry :> Function { + in currentStatus: VehicleStatus; + out reentryStatus: VehicleStatus; + doc /* Controls the vehicle's trajectory through the atmosphere to manage heat and aim for the landing zone. */ + #refinement dependency GuideAtmosphericEntry to OperationsPackage::GuideReentryTrajectory; + } + action def DeployDecelerators :> Function { + in currentStatus: VehicleStatus; + out descentStatus: VehicleStatus; + doc /* Deploys the parachute system to slow the vehicle for landing. */ + #refinement dependency DeployDecelerators to OperationsPackage::DeployParachutes; + } + action def PerformSplashdown :> Function { + in currentStatus: VehicleStatus; + out finalStatus: VehicleStatus; + doc /* Manages the final water landing. */ + #refinement dependency PerformSplashdown to OperationsPackage::ConductSplashdownOperations; + } + action def RetrieveVehicleAndCrew :> Function { + in currentStatus: VehicleStatus; + out recoveredCrew: CrewStatus; + out recoveredVehicle: VehicleStatus; + doc /* Locates and recovers the crew and capsule from the ocean. */ + #refinement dependency RetrieveVehicleAndCrew to OperationsPackage::RetrieveCrewAndCM; + } + action def ExecuteQuarantine :> Function { + in crew: CrewStatus; + doc /* Implements biological isolation protocols for the crew. */ + #refinement dependency ExecuteQuarantine to OperationsPackage::InitiateQuarantineProcedures; + } + action def SecureReturnedSamples :> Function { + in samples: LunarSamples; + out finalSamples: LunarSamples; + doc /* Secures the collected lunar materials for scientific study. */ + #refinement dependency SecureReturnedSamples to OperationsPackage::SecureLunarSamples; + } + + // =================================================================== + // Level 1-3 Functions (Orchestrating Leaf-Level Functions) + // =================================================================== + + action def PerformLunarMission :> Function { + in plan: MissionPlan; + in vehicleSystem: VehicleStatus; + in flightCrew: CrewStatus; + out finalReport: MissionReport; + doc /* The top-level function to transport a human crew to the lunar surface, enable exploration, and return them safely to Earth. */ + action outbound: ExecuteOutboundJourney; + action lunarOps: ConductLunarOperations; + action returnJourney: ExecuteReturnJourney; + } + + action def ExecuteOutboundJourney :> Function { + in launchReadySystem: VehicleStatus; + in crew: CrewStatus; + out vehicleInLunarOrbit: VehicleStatus; + doc /* To execute all operations required to travel from a pre-launch state on Earth to achieving a stable orbit around the Moon. */ + action prep: PrepareForLaunch; + action launch: LaunchToOrbit; + action tli: SetTranslunarCourse; + action coast: TraverseToMoon; + action loi: AchieveLunarOrbit; + } + + action def ConductLunarOperations :> Function { + in vehicleInLunarOrbit: VehicleStatus; + out returnReadyVehicle: VehicleStatus; + out samples: LunarSamples; + out science: ScientificData; + doc /* To perform all operations in the lunar environment, including landing, exploration, and returning to the main vehicle in lunar orbit. */ + action prepLanding: PrepareForLanding; + action land: LandOnSurface; + action explore: ExploreLunarSurface; + action ascendAndDock: ReturnToOrbitAndDock; + } + + action def ExecuteReturnJourney :> Function { + in returnReadyVehicle: VehicleStatus; + in samples: LunarSamples; + out recoveredCrew: CrewStatus; + out recoveredSamples: LunarSamples; + doc /* To execute all operations required to leave lunar orbit, travel back to Earth, and safely recover the crew and mission assets. */ + action tei: SetTransearthCourse; + action coast: TraverseToEarth; + action land: ReenterAndLand; + action recover: RecoverCrewAndAssets; + } + + action def PrepareForLaunch :> Function { + in assembledVehicle: VehicleStatus; + in crew: CrewStatus; + out launchReadyVehicle: VehicleStatus; + out readyCrew: CrewStatus; + doc /* Covers final ground preparations. Corresponds to the PrepareForMissionPhase. */ + action load: PerformPropellantLoading; + action board: PerformCrewIngress; + } + + action def LaunchToOrbit :> Function { + in launchReadyVehicle: VehicleStatus; + out vehicleInEarthOrbit: VehicleStatus; + doc /* Applies motive force to overcome gravity and achieve a stable Earth orbit. Corresponds to the LaunchPhase. */ + action countdown: ExecuteTerminalCountdown; + action provideThrust1: ProvideStage1Thrust; + action provideThrust2: ProvideStage2Thrust; + action provideThrust3: ProvideOrbitInsertionThrust; + action guide: GuideAscentTrajectory; + action observe: ObserveAscentDataFromCockpit; + action analyze: AnalyzeLaunchTelemetryFromGround; + } + + action def SetTranslunarCourse :> Function { + in vehicleInEarthOrbit: VehicleStatus; + out vehicleOnTranslunarTrajectory: VehicleStatus; + doc /* Executes a propulsive maneuver to leave Earth orbit and reconfigure the vehicle. Corresponds to the TransLunarInjectionPhase. */ + action executeTransposition: ExecuteTranspositionManeuver; + action provideAttitudeControlAndThrust: ProvideAttitudeControlThrust; + action reconfigure: MechanicallyLatchModules; + action burn: ProvideTranslunarInjectionThrust; + action control: ControlTranslunarInjectionBurn; + } + + action def TraverseToMoon :> Function { + in vehicleOnTranslunarTrajectory: VehicleStatus; + out vehicleInLunarSphere: VehicleStatus; + doc /* Navigates the vehicle across cislunar space. Corresponds to the TransLunarCoastPhase. */ + action calculate: CalculateCourseCorrection; + action correct: ExecuteCourseCorrectionBurn; + action monitorOnboard: MonitorOnboardSystems; + action monitorGround: MonitorDownlinkedTelemetry; + action comms: TransmitAndReceiveSpacecraftSignals; + action trackAndRelay: TrackAndRelayGroundSignals; + action rest: ManageCrewSchedules; + } + + action def AchieveLunarOrbit :> Function { + in vehicleInLunarSphere: VehicleStatus; + out vehicleInStableLunarOrbit: VehicleStatus; + doc /* Executes a propulsive maneuver for gravitational capture by the Moon. Corresponds to the LunarOrbitInsertionPhase. */ + action burn: ProvideLunarOrbitInsertionThrust; + action control : ControlLunarOrbitInsertionBurn; + } + + action def PrepareForLanding :> Function { + in combinedVehicle: VehicleStatus; + out separatedLander: VehicleStatus; + out separatedOrbiter: VehicleStatus; + doc /* Prepares and separates the landing vehicle from the main vehicle. Corresponds to the LunarOrbitOperationsDescentPreparationPhase. */ + action checkout: PerformOrbitalSystemCheckouts; + action prep: PrepareLanderForSeparation; + action undock: SeparateLanderFromOrbiter; + } + + action def LandOnSurface :> Function { + in landingVehicle: VehicleStatus; + out vehicleOnSurface: VehicleStatus; + doc /* Executes a controlled, powered descent from lunar orbit to the surface. Corresponds to the PoweredDescentPhase. */ + action burn: ExecuteDescentBurn; + action monitor: MonitorDescent; + action pilot: ManuallyPilotLander; + } + + action def ExploreLunarSurface :> Function { + in vehicleOnSurface: VehicleStatus; + out collectedSamples: LunarSamples; + out deployedScience: ScientificData; + doc /* Conducts all planned extravehicular activities on the Moon. Corresponds to the LunarSurfaceOperationsPhase. */ + action postLand: PerformPostLandingCheck; + action prepEva: PrepareForExtravehicularActivity; + action provideIndividualLifesupport: ProvideIndividualLifesupport; + action eva: ConductSurfaceExploration; + action collect: GatherLunarSamples; + action deploy: DeploySurfaceExperiments; + action conclude: CompleteExtravehicularActivity; + action rest: ConductSurfaceRestPeriod; + } + + action def ReturnToOrbitAndDock :> Function { + in ascentVehicleOnSurface: VehicleStatus; + in mainVehicleInOrbit: VehicleStatus; + in samplesToTransfer: LunarSamples; + out mainVehicleWithCrew: VehicleStatus; + doc /* Leaves the lunar surface, achieves orbit, and physically connects with the primary vehicle. Corresponds to the LunarAscentRendezvousPhase. */ + action ascend: ExecuteAscentBurn; + action calculate : CalculateRendezvousManeuvers; + action rendezvous: ExecuteRendezvousBurns; + action dock: ConnectSpacecraft; + action transfer: TransferCrewAndMaterials; + action jettison: DiscardAscentStage; + } + + action def SetTransearthCourse :> Function { + in mainVehicleInLunarOrbit: VehicleStatus; + out vehicleOnTransearthTrajectory: VehicleStatus; + doc /* Executes a propulsive maneuver to leave lunar orbit and begin the journey to Earth. Corresponds to the TransEarthInjectionPhase. */ + action burn: ExecuteTransearthBurn; + } + + action def TraverseToEarth :> Function { + in vehicleOnTransearthTrajectory: VehicleStatus; + out reentryReadyVehicle: VehicleStatus; + doc /* Navigates the vehicle to Earth and prepares for reentry. Corresponds to the TransEarthCoastPhase. */ + action monitorSystems: MonitorOnboardSystems; + action monitorTelemetry : MonitorDownlinkedTelemetry; + action transmitAndReceive: TransmitAndReceiveSpacecraftSignals; + action trackAndRelay: TrackAndRelayGroundSignals; + action prep: PrepareVehicleForReentry; + } + + action def ReenterAndLand :> Function { + in reentryReadyVehicle: VehicleStatus; + out landedVehicle: VehicleStatus; + doc /* Manages atmospheric entry and executes a safe landing. Corresponds to the ReentryLandingPhase. */ + action separate: SeparateReturnCapsule; + action guide: GuideAtmosphericEntry; + action deploy: DeployDecelerators; + action splashdown: PerformSplashdown; + } + + action def RecoverCrewAndAssets :> Function { + in landedVehicle: VehicleStatus; + in samplesOnboard: LunarSamples; + out securedCrew: CrewStatus; + out securedSamples: LunarSamples; + doc /* Retrieves the crew and vehicle and initiates post-mission protocols. Corresponds to the RecoveryQuarantinePhase. */ + action retrieve: RetrieveVehicleAndCrew; + action quarantine: ExecuteQuarantine; + action secure: SecureReturnedSamples; + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/LogicalComponentsPackage.sysml b/language/src/test/resources/Apollo_11/LogicalComponentsPackage.sysml new file mode 100644 index 00000000..49074803 --- /dev/null +++ b/language/src/test/resources/Apollo_11/LogicalComponentsPackage.sysml @@ -0,0 +1,89 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package LogicalComponentsPackage { + + private import CoSMAPackage::*; + private import FunctionsPackage::*; + + part def LaunchSystem :> LogicalComponent { + doc /* This system's sole purpose is to propel the payload from Earth's surface onto a precise path to the Moon. It is responsible for all functions related to ascent and injection into a translunar trajectory. */ + perform action provideStage1Thrust : ProvideStage1Thrust; + perform action provideStage2Thrust : ProvideStage2Thrust; + perform action provideOrbitInsertionThrust : ProvideOrbitInsertionThrust; + perform action guideAscentTrajectory : GuideAscentTrajectory; + perform action provideTranslunarInjectionThrust : ProvideTranslunarInjectionThrust; + perform action controlTranslunarInjectionBurn : ControlTranslunarInjectionBurn; + } + + part def Spacecraft :> LogicalComponent { + /* This system comprises the vehicles that travel to, operate at, and return from the Moon. It handles all functions related to in-space travel, life support, landing, and returning through Earth's atmosphere. */ + perform action provideAttitudeControlThrust : ProvideAttitudeControlThrust; + perform action mechanicallyLatchModules : MechanicallyLatchModules; + perform action calculateCourseCorrection : CalculateCourseCorrection; + perform action executeCourseCorrectionBurn : ExecuteCourseCorrectionBurn; + perform action transmitAndReceiveSpacecraftSignals : TransmitAndReceiveSpacecraftSignals; + perform action provideLunarOrbitInsertionThrust : ProvideLunarOrbitInsertionThrust; + perform action controlLunarOrbitInsertionBurn : ControlLunarOrbitInsertionBurn; + perform action separateLanderFromOrbiter : SeparateLanderFromOrbiter; + perform action executeDescentBurn : ExecuteDescentBurn; + perform action executeAscentBurn : ExecuteAscentBurn; + perform action calculateRendezvousManeuvers : CalculateRendezvousManeuvers; + perform action executeRendezvousBurns : ExecuteRendezvousBurns; + perform action discardAscentStage : DiscardAscentStage; + perform action executeTransearthBurn : ExecuteTransearthBurn; + perform action separateReturnCapsule : SeparateReturnCapsule; + perform action guideAtmosphericEntry : GuideAtmosphericEntry; + perform action deployDecelerators : DeployDecelerators; + perform action performSplashdown : PerformSplashdown; + } + + part def GroundSupportSystem :> LogicalComponent { + doc /* This system is the Earth-based infrastructure and personnel that manage, control, and support the mission from start to finish. */ + perform action performPropellantLoading : PerformPropellantLoading; + perform action performCrewIngress : PerformCrewIngress; + perform action retrieveVehicleAndCrew : RetrieveVehicleAndCrew; + perform action executeQuarantine : ExecuteQuarantine; + perform action secureReturnedSamples : SecureReturnedSamples; + + perform action executeTerminalCountdown : ExecuteTerminalCountdown; + perform action analyzeLaunchTelemetryFromGround : AnalyzeLaunchTelemetryFromGround; + perform action monitorDownlinkedTelemetry : MonitorDownlinkedTelemetry; + perform action monitorDescent : MonitorDescent; + } + + part def DataTransmissionNetwork { + doc /* The system to relay and transmit data between the SoS elements. */ + perform action trackAndRelayGroundSignals : TrackAndRelayGroundSignals; + } + + part def EVASystem :> LogicalComponent { + doc /* This system consists of the personal equipment required for an astronaut to live and work in the vacuum of space on the lunar surface. */ + perform action provideIndividualLifesupport: ProvideIndividualLifesupport; + } + + part def Crew :> LogicalComponent { + doc /* This system represents the human operators who pilot the spacecraft, conduct experiments, and make real-time decisions. */ + perform action observeAscentDataFromCockpit : ObserveAscentDataFromCockpit; + perform action executeTranspositionManeuver : ExecuteTranspositionManeuver; + perform action monitorOnboardSystems : MonitorOnboardSystems; + perform action manageCrewSchedules : ManageCrewSchedules; + perform action performOrbitalSystemCheckouts : PerformOrbitalSystemCheckouts; + perform action prepareLanderForSeparation : PrepareLanderForSeparation; + perform action manuallyPilotLander : ManuallyPilotLander; + perform action performPostLandingCheck : PerformPostLandingCheck; + perform action prepareForExtravehicularActivity : PrepareForExtravehicularActivity; + perform action conductSurfaceExploration : ConductSurfaceExploration; + perform action gatherLunarSamples : GatherLunarSamples; + perform action deploySurfaceExperiments : DeploySurfaceExperiments; + perform action completeExtravehicularActivity : CompleteExtravehicularActivity; + perform action conductSurfaceRestPeriod : ConductSurfaceRestPeriod; + perform action connectSpacecraft : ConnectSpacecraft; + perform action transferCrewAndMaterials : TransferCrewAndMaterials; + perform action prepareVehicleForReentry : PrepareVehicleForReentry; + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/MissionPackage.sysml b/language/src/test/resources/Apollo_11/MissionPackage.sysml new file mode 100644 index 00000000..23f3a82c --- /dev/null +++ b/language/src/test/resources/Apollo_11/MissionPackage.sysml @@ -0,0 +1,323 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package MissionPackage { + + private import CoSMAPackage::*; + private import MissionPhasesPackage::*; + private import CapabilitiesPackage::*; + private import SystemPackage::*; + private import AstronautsPackage::*; + private import FunctionsPackage::*; + private import ContextPackage::*; + private import CoSMAQuantitiesAndUnitsPackage::*; + private import SI::*; + private import ISQ::*; + + part def Apollo11Mission :> MannedSpaceMission { + doc /* Apollo 11 was a spaceflight conducted from July 16 to 24, 1969, by the United States and launched by NASA. */ + + comment source /* https://www.nasa.gov/history/apollo-11-mission-overview/ */ + + part apollo11MissionSystem : Apollo11MissionSystem :> system; + part apollo11MissionContext : Apollo11MissionContext :> context; + part crew[1..*] : Astronaut, LogicalComponentsPackage::Crew :>> crew; + + perform action performLunarMission : PerformLunarMission; + + individual part commander : 'Neil Armstrong' :> crew; + individual part commandModulePilot : 'Michael Collins' :> crew; + individual part lunarModulePilot : 'Buzz Aldrin' :> crew; + + attribute :>> plannedDuration = 195.3 [h]; + doc /* Known mission duration: 8 days, 3 hours, 18 minutes. */ + + comment cost /* All costs are estimations and more a best guess */ + attribute :>> researchAndDevelopmentCost = 5E9 ['$']; + attribute :>> manufacturingCost = 3E9 ['$']; + attribute :>> operationsCost = 1E9 ['$']; + attribute :>> personnelCost = 2E9 ['$']; + + requirement goToMoon : Goal { + doc /* Perform a crewed lunar landing and return to Earth. */ + } :> goals; + requirement flag : Goal { + doc /* Put a USA flag on the moon. */ + } :> goals; + requirement samples : Goal { + doc /* Gather samples of lunar-surface materials and bring them back to Earth. */ + } :> goals; + requirement pictures : Goal { + doc /* Extensively photograph the lunar terrain, the deployed scientific equipment, the LM spacecraft, and each other, both with still and motion picture cameras. */ + } :> goals; + requirement deploy : Goal { + doc /* Deployment of a television camera to transmit signals to Earth; and deployment of a solar wind composition experiment, seismic experiment package and a Laser Ranging Retroreflector. */ + } :> goals; + + exhibit state apollo11Phases { + + // Declare the states used in this specific state machine + state initial : Initial; + state preparation : PrepareForMissionPhase; + state launch : LaunchPhase; + state tli : TransLunarInjectionPhase; + state tlc : TransLunarCoastPhase; + state loi : LunarOrbitInsertionPhase; + state lunarOpsDescentPrep : LunarOrbitOperationsDescentPreparationPhase; + state poweredDescent : PoweredDescentPhase; + state lunarSurfaceOps : LunarSurfaceOperationsPhase; + state lunarAscentRendezvous : LunarAscentRendezvousPhase; + state tei : TransEarthInjectionPhase; + state tec : TransEarthCoastPhase; + state reentryLanding : ReentryLandingPhase; + state recoveryQuarantine : RecoveryQuarantinePhase; + state final : MissionComplete; + + transition first initial then preparation; + + transition first preparation accept PreparationPhaseCompletedNotification then launch { + doc /* if "all preparations concluded successfully" + */ + } + + + transition first launch accept LaunchPhaseCompletedNotification then tli { + doc /* if "Successful insertion into stable Earth parking orbit" and "All spacecraft systems verified 'nominal' or 'go' for TLI" and + "Astronauts report systems nominal and ready for TLI" and + "Ground stations confirm accurate tracking and TLI burn parameters" + */ + } + + transition first tli accept TransLunarInjectionPhaseCompletedNotification then tlc { + doc /* if "Successful S-IVB TLI burn" and + "Mission Control confirms free-return trajectory to Moon" and + "Successful CSM separation, transposition, docking, and LM extraction" and + "S-IVB stage successfully targeted for disposal" + */ + } + + transition first tlc accept TransLunarCoastPhaseCompletedNotification then loi { + doc /* if "Spacecraft reaches precise LOI burn point" and + "All CSM systems (SPS engine) verified 'green' and ready for LOI" and + "Final navigation updates confirm precise trajectory and burn parameters" and + "Astronauts completed pre-LOI checklists" + */ + } + + transition first loi accept LunarOrbitInsertionPhaseCompletedNotification then lunarOpsDescentPrep { + doc /* if "Successful LOI burn, achieving stable lunar orbit" and + "Mission Control confirms planned lunar orbit" and + "Post-LOI checks confirm no anomalies" + */ + } + + transition first lunarOpsDescentPrep accept LunarOrbitOperationsDescentPreparationPhaseCompletedNotification then poweredDescent { + doc /* if "Astronauts transferred into LM and systems activated" and + "LM successfully undocked from CSM (visual integrity confirmed)" and + "Landing site deemed acceptable by crew and Mission Control" and + "Final navigation updates confirm precise descent trajectory and targeting" and + "Mission Control gives final 'GO' for Powered Descent" + */ + } + + transition first poweredDescent accept PoweredDescentPhaseCompletedNotification then lunarSurfaceOps { + doc /* if "LM descent stage makes soft landing ('The Eagle has landed!')" and + "LM integrity confirmed (upright, stable, systems nominal)" and + "Astronauts safe, healthy, and ready for surface operations" and + "Adequate consumables remain for abort or planned ascent" and + "Crew provides initial observations of landing site" + */ + } + + transition first lunarSurfaceOps accept LunarSurfaceOperationsPhaseCompletedNotification then lunarAscentRendezvous { + doc /* if "All planned EVA activities successfully completed" and + "Both astronauts safely re-entered LM" and + "LM cabin successfully repressurized" and + "All LM ascent stage systems confirmed ready for launch" and + "Sufficient power and propellant for ascent and rendezvous" and + "Lunar orbital mechanics align for rendezvous" + */ + } + + transition first lunarAscentRendezvous accept LunarAscentRendezvousPhaseCompletedNotification then tei { + doc /* if "LM ascent stage successfully launched and achieved stable lunar orbit" and + "LM ascent stage successfully rendezvoused and docked with CSM" and + "Armstrong, Aldrin, and lunar samples transferred back into CSM" and + "LM ascent stage successfully undocked and jettisoned" and + "CSM (with all three astronauts) confirmed ready for TEI burn" + */ + } + + transition first tei accept TransEarthInjectionPhaseCompletedNotification then tec { + doc /* if "Successful TEI burn, achieving trans-Earth trajectory" and + "Mission Control confirms proper return path to Earth" and + "SPS engine is permanently shut down" + */ + } + + transition first tec accept TransEarthCoastPhaseCompletedNotification then reentryLanding { + doc /* if "CM positioned correctly for atmospheric re-entry (separated from SM)" and + "Final navigation updates confirm precise re-entry trajectory and landing zone" and + "All Command Module re-entry systems verified 'go'" and + "Recovery forces in position and landing zone clear" + */ + } + + transition first reentryLanding accept ReentryLandingPhaseCompletedNotification then recoveryQuarantine { + doc /* if "CM splashes down safely in targeted recovery area" and + "Astronauts report safe and healthy in capsule" and + "CM flotation systems active and stable" and + "Recovery forces have visually acquired CM" + */ + } + + transition first recoveryQuarantine accept RecoveryQuarantinePhaseCompletedNotification then final { + doc /* if "Astronauts extracted to MQF, CM retrieved" and + "Lunar samples secured and transferred to MQF" and + "Preliminary health checks of astronauts nominal" and + "21-day quarantine period officially begins" + */ + } + + } :>> phases; + + part programmaticAndPublicAffairsManagement:ProgrammaticAndPublicAffairsManagement :> requiredCapabilites; + part heavyLiftLaunch:HeavyLiftLaunch :> requiredCapabilites; + part multiStagePropulsion:MultiStagePropulsion :> requiredCapabilites; + part precisionOrbitalMechanics:PrecisionOrbitalMechanics :> requiredCapabilites; + part atmosphericReentryAndLanding:AtmosphericReentryAndLanding :> requiredCapabilites; + part deepSpaceHabitationAndLifeSupport:DeepSpaceHabitationAndLifeSupport :> requiredCapabilites; + part autonomousAndAssistedNavigationGuidanceAndControl:AutonomousAndAssistedNavigationGuidanceAndControl :> requiredCapabilites; + part inSpacePropulsion:InSpacePropulsion :> requiredCapabilites; + part powerGenerationAndDistribution:PowerGenerationAndDistribution :> requiredCapabilites; + part lunarSurfaceLandingAndAscent:LunarSurfaceLandingAndAscent :> requiredCapabilites; + part globalTrackingAndCommunication:GlobalTrackingAndCommunication :> requiredCapabilites; + part realtimeMissionControl:RealtimeMissionControl :> requiredCapabilites; + part contingencyPlanningAndRapidResponse:ContingencyPlanningAndRapidResponse :> requiredCapabilites; + part crewTrainingAndSimulation:CrewTrainingAndSimulation :> requiredCapabilites; + part humanPerformanceUnderExtremeStress:HumanPerformanceUnderExtremeStress :> requiredCapabilites; + part complexSoftwareDevelopment:ComplexSoftwareDevelopment :> requiredCapabilites; + part complexLogisticsAndIntegration:ComplexLogisticsAndIntegration :> requiredCapabilites; + part launchOperationsManagement:LaunchOperationsManagement :> requiredCapabilites; + part adaptabilityAndProblemSolving:AdaptabilityAndProblemSolving :> requiredCapabilites; + part extravehicularActivitySupport:ExtravehicularActivitySupport :> requiredCapabilites; + part lunarMobility:LunarMobility :> requiredCapabilites; + part scientificDataAcquisitionAndSampleReturn:ScientificDataAcquisitionAndSampleReturn :> requiredCapabilites; + part planetaryProtection:PlanetaryProtection :> requiredCapabilites; + part robustCommunicationAndTelemetry:RobustCommunicationAndTelemetry :> requiredCapabilites; + part toolDevelopment:ToolDevelopment :> requiredCapabilites; + + connection : CapabilityToGoalDerivation { + end capa ::> programmaticAndPublicAffairsManagement; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> heavyLiftLaunch; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> multiStagePropulsion; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> precisionOrbitalMechanics; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> atmosphericReentryAndLanding; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> deepSpaceHabitationAndLifeSupport; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> autonomousAndAssistedNavigationGuidanceAndControl; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> inSpacePropulsion; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> powerGenerationAndDistribution; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> lunarSurfaceLandingAndAscent; + end goal1 ::> goToMoon; + end goal2 ::> samples; + end goal3 ::> deploy; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> globalTrackingAndCommunication; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> realtimeMissionControl; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> contingencyPlanningAndRapidResponse; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> crewTrainingAndSimulation; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> humanPerformanceUnderExtremeStress; + end goal1 ::> goToMoon; + end goal2 ::> pictures; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> complexSoftwareDevelopment; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> complexLogisticsAndIntegration; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> launchOperationsManagement; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> adaptabilityAndProblemSolving; + end goal ::> goToMoon; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> extravehicularActivitySupport; + end goal1 ::> flag; + end goal2 ::> samples; + end goal3 ::> pictures; + end goal4 ::> deploy; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> lunarMobility; + end goal ::> flag; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> scientificDataAcquisitionAndSampleReturn; + end goal1 ::> samples; + end goal2 ::> pictures; + end goal3 ::> deploy; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> planetaryProtection; + end goal ::> samples; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> robustCommunicationAndTelemetry; + end goal ::> pictures; + } :> capabilityToGoals; + connection : CapabilityToGoalDerivation { + end capa ::> toolDevelopment; + end goal ::> deploy; + } :> capabilityToGoals; + } +} diff --git a/language/src/test/resources/Apollo_11/MissionPhasesPackage.sysml b/language/src/test/resources/Apollo_11/MissionPhasesPackage.sysml new file mode 100644 index 00000000..d2c100c4 --- /dev/null +++ b/language/src/test/resources/Apollo_11/MissionPhasesPackage.sysml @@ -0,0 +1,154 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package MissionPhasesPackage { + + private import CoSMAPackage::*; + private import OperationsPackage::*; + + // --- Item Definitions (Representing Completion Notifications/Triggers) --- + item def PreparationPhaseCompletedNotification; + item def LaunchPhaseCompletedNotification; + item def TransLunarInjectionPhaseCompletedNotification; + item def TransLunarCoastPhaseCompletedNotification; + item def LunarOrbitInsertionPhaseCompletedNotification; + item def LunarOrbitOperationsDescentPreparationPhaseCompletedNotification; + item def PoweredDescentPhaseCompletedNotification; + item def LunarSurfaceOperationsPhaseCompletedNotification; + item def LunarAscentRendezvousPhaseCompletedNotification; + item def TransEarthInjectionPhaseCompletedNotification; + item def TransEarthCoastPhaseCompletedNotification; + item def ReentryLandingPhaseCompletedNotification; + item def RecoveryQuarantinePhaseCompletedNotification; + + // States + state def PrepareForMissionPhase :> Phase { + do action prepareForMissionPhaseOperations { + first start; + then action loadConsumablesAndPropellants : LoadConsumablesAndPropellants; + then action transferCrewToVehicle : TransferCrewToVehicle; + then done; + } + } + + state def LaunchPhase :> Phase { + do action launchPhaseOperations { + first start; + then action performPreLaunchCountdown : PerformPreLaunchCountdown; + then action executeLaunchSequence : ExecuteLaunchSequence; + then action monitorAscentTrajectory : MonitorAscentTrajectory; + then done; + } + } + state def TransLunarInjectionPhase :> Phase { + do action tliPhaseOperations { + first start; + then action executeTLIBurn : ExecuteTLIBurn; + then action performTranspositionDockingExtraction : PerformTranspositionDockingExtraction; + then done; + } + } + state def TransLunarCoastPhase :> Phase { + do action tlcPhaseOperations { + first start; + then action conductMidCourseCorrections : ConductMidCourseCorrections; + then action monitorSpacecraftSystems : MonitorSpacecraftSystems; + then action communicateWithMissionControl : CommunicateWithMissionControl; + then action manageCrewRestPeriods : ManageCrewRestPeriods; + then done; + } + } + state def LunarOrbitInsertionPhase :> Phase { + do action loiPhaseOperations { + first start; + then action executeLOIBurn : ExecuteLOIBurn; + then done; + } + } + state def LunarOrbitOperationsDescentPreparationPhase :> Phase { + do action lunarOpsDescentPrepOperations { + first start; + then action conductLunarOrbitCheckouts : ConductLunarOrbitCheckouts; + then action prepareLMforUndocking : PrepareLMforUndocking; + then action performLMUndocking : PerformLMUndocking; + then done; + } + } + state def PoweredDescentPhase :> Phase { + do action poweredDescentOperations { + first start; + then action executePoweredDescentBurn : ExecutePoweredDescentBurn; + then action monitorDescentTelemetry : MonitorDescentTelemetry; + then action performManualPiloting : PerformManualPiloting; + then done; + } + } + state def LunarSurfaceOperationsPhase :> Phase { + do action lunarSurfaceOpsOperations { + first start; + then action conductLMPostLandingChecks : ConductLMPostLandingChecks; + then action prepareForEVA : PrepareForEVA; + then action performLunarEVA : PerformLunarEVA; + then action collectLunarSamples : CollectLunarSamples; + then action deployScientificInstruments : DeployScientificInstruments; + then action concludeEVA : ConcludeEVA; + then action manageLunarSurfaceRestPeriod : ManageLunarSurfaceRestPeriod; + then done; + } + } + state def LunarAscentRendezvousPhase :> Phase { + do action lunarAscentRendezvousOperations { + first start; + then action executeLunarAscentBurn : ExecuteLunarAscentBurn; + then action performRendezvousManeuvers : PerformRendezvousManeuvers; + then action conductLMCSMDocking : ConductLMCSMDocking; + then action transferCrewAndSamples : TransferCrewAndSamples; + then action jettisonLM : JettisonLM; + then done; + } + } + state def TransEarthInjectionPhase :> Phase { + do action teiPhaseOperations { + first start; + then action executeTEIBurn : ExecuteTEIBurn; + then done; + } + } + state def TransEarthCoastPhase :> Phase { + do action tecPhaseOperations { + first start; + then action monitorSpacecraftSystems : MonitorSpacecraftSystems; + then action communicateWithMissionControl : CommunicateWithMissionControl; + then action prepareCMforReentry : PrepareCMforReentry; + then done; + } + } + state def ReentryLandingPhase :> Phase { + do action reentryLandingOperations { + first start; + then action separateModules : SeparateModules; + then action guideReentryTrajectory : GuideReentryTrajectory; + then action deployParachutes : DeployParachutes; + then action conductSplashdownOperations : ConductSplashdownOperations; + then done; + } + } + state def RecoveryQuarantinePhase :> Phase { + do action recoveryQuarantineOperations { + first start; + then action retrieveCrewAndCM : RetrieveCrewAndCM; + then action initiateQuarantineProcedures : InitiateQuarantineProcedures; + then action secureLunarSamples : SecureLunarSamples; + then done; + } + } + + // Special states + state def Initial; + state def MissionComplete; + +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/MissionRequirementsPackage.sysml b/language/src/test/resources/Apollo_11/MissionRequirementsPackage.sysml new file mode 100644 index 00000000..ad6a74cb --- /dev/null +++ b/language/src/test/resources/Apollo_11/MissionRequirementsPackage.sysml @@ -0,0 +1,673 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package MissionRequirementsPackage { + + private import SI::*; + private import ISQ::*; + private import ScalarValues::*; + private import CoSMAPackage::*; + private import CoSMAQuantitiesAndUnitsPackage::*; + private import USCustomaryUnits::*; + private import ModelingMetadata::*; + + + requirement def <'HLR-R001'> CrewReturnSafetyRequirement { + doc /* The Apollo 11 Mission shall safely return all three crew members to Earth, + with no life-threatening injuries or long-term health impacts, by July 24, 1969. */ + @Rationale { + text = "This requirement is paramount for fulfilling the core mission objective (Go to Moon) and directly addresses the primary concern of all stakeholders (NASA, Astronauts, Families, Public, U.S. Government) regarding human life safety."; + } + attribute crewInjuryCount: Integer; + attribute maxAcceptableInjuries: Integer = 0; + + require constraint { crewInjuryCount <= maxAcceptableInjuries } + #refinement dependency 'HLR-R001' to CapabilitiesPackage::DeepSpaceHabitationAndLifeSupport; + #refinement dependency 'HLR-R001' to CapabilitiesPackage::AtmosphericReentryAndLanding; + #refinement dependency 'HLR-R001' to CapabilitiesPackage::ContingencyPlanningAndRapidResponse; + } + + requirement def <'HLR-R002'> LunarLanderSoftLandingRequirement { + doc /* The Apollo 11 Mission shall achieve a soft landing of the crewed lunar lander on the lunar surface + within the designated landing zone (Tranquility Base), by July 20, 1969. */ + @Rationale { + text = "A soft and precise lunar landing is fundamental to the 'Go to Moon' goal and ensures the integrity of the lander and safety of the crew for surface operations and subsequent ascent."; + } + + attribute actualVerticalVelocity :> ISQ::speed; + attribute maxVerticalVelocity :> ISQ::speed = 2 [m/s]; + + attribute actualHorizontalVelocity :> ISQ::speed; + attribute maxHorizontalVelocity :> ISQ::speed = 0.5 [m/s]; + + attribute actualLandingZoneDeviation :> ISQ::length; + attribute maxLandingZoneDeviation :> ISQ::length = 1000 [m]; + + require constraint { + (actualVerticalVelocity <= maxVerticalVelocity) and + (actualHorizontalVelocity <= maxHorizontalVelocity) and + (actualLandingZoneDeviation <= maxLandingZoneDeviation) + } + #refinement dependency 'HLR-R002' to CapabilitiesPackage::LunarSurfaceLandingAndAscent; + #refinement dependency 'HLR-R002' to CapabilitiesPackage::PrecisionOrbitalMechanics; + #refinement dependency 'HLR-R002' to CapabilitiesPackage::AutonomousAndAssistedNavigationGuidanceAndControl; + } + + requirement def <'HLR-R003'> TransLunarInjectionAccuracyRequirement { + doc /* The Apollo 11 Mission launch system shall successfully place the spacecraft into a Trans-Lunar Injection (TLI) trajectory + with a delta-V accuracy of +/- 0.5 meters per second and a path leading to lunar orbit insertion within 75 hours from launch, + on July 16, 1969. */ + @Rationale { + text = "Accurate Trans-Lunar Injection is essential for reaching the Moon efficiently and correctly, directly supporting the 'Go to Moon' goal and minimizing the need for costly and time-consuming mid-course corrections."; + } + + attribute actualDeltaVAccuracy :> ISQ::speed; + attribute maxDeltaVAccuracy :> ISQ::speed = 0.5 [m/s]; + + attribute actualTimeToLunarOrbitInsertion :> ISQ::time; + attribute maxTimeToLunarOrbitInsertion :> ISQ::time = 75 [h]; + + require constraint { + (actualDeltaVAccuracy <= maxDeltaVAccuracy) and + (actualTimeToLunarOrbitInsertion <= maxTimeToLunarOrbitInsertion) + } + #refinement dependency 'HLR-R003' to CapabilitiesPackage::HeavyLiftLaunch; + #refinement dependency 'HLR-R003' to CapabilitiesPackage::MultiStagePropulsion; + #refinement dependency 'HLR-R003' to CapabilitiesPackage::PrecisionOrbitalMechanics; + } + + requirement def <'HLR-R004'> CommunicationUptimeRequirement { + doc /* The Apollo 11 Mission's communication system shall maintain continuous voice and telemetry contact with ground control + for >= 95% of the mission duration, with no single blackout exceeding 10 minutes during lunar farside passes, + throughout the 8-day mission. */ + @Rationale { + text = "Reliable communication is vital for real-time mission control, astronaut safety, and public engagement, addressing concerns of Mission Control, NASA, and the public."; + } + + attribute actualCommunicationUptimePercentage: RatioValue; // Represents a percentage (0-100) + attribute minCommunicationUptimePercentage: RatioValue = 95['%']; + + attribute maxSingleBlackoutDuration :> ISQ::time; + attribute allowedSingleBlackoutDuration :> ISQ::time = 10 [min]; + + require constraint { + (actualCommunicationUptimePercentage >= minCommunicationUptimePercentage) and + (maxSingleBlackoutDuration <= allowedSingleBlackoutDuration) + } + #refinement dependency 'HLR-R004' to CapabilitiesPackage::GlobalTrackingAndCommunication; + #refinement dependency 'HLR-R004' to CapabilitiesPackage::RobustCommunicationAndTelemetry; + } + + requirement def <'HLR-R005'> SustainedCabinHabitability { + doc /* The spacecraft system shall maintain an internal environment that supports crew health and cognitive performance for the mission duration. */ + @Rationale { + text = "Human life cannot be sustained in the vacuum of space without an artificial environment. Proper habitability is critical for the crew to perform complex tasks."; + } + #refinement dependency SustainedCabinHabitability to CapabilitiesPackage::DeepSpaceHabitationAndLifeSupport; + } + + requirement def <'HLR-R006'> LunarSampleCollectionQuantityRequirement { + doc /* The Apollo 11 Mission shall collect a minimum of 20 kilograms of documented lunar surface material, + including contingency and bulk samples, and return them to Earth within the Mobile Quarantine Facility, + by July 24, 1969. */ + @Rationale { + text = "This requirement directly fulfills the 'samples' goal, providing crucial scientific data for understanding the Moon's origin and geology, and supports the scientific community's objectives."; + } + + attribute actualSampleMass :> ISQ::mass; + attribute minRequiredSampleMass :> ISQ::mass = 20 [kg]; + attribute contaminationPercentage: RatioValue; + attribute maxContaminationPercentage: RatioValue = 0.1['%']; + + require constraint { + (actualSampleMass >= minRequiredSampleMass) and + (contaminationPercentage <= maxContaminationPercentage) + } + #refinement dependency 'HLR-R006' to CapabilitiesPackage::ScientificDataAcquisitionAndSampleReturn; + #refinement dependency 'HLR-R006' to CapabilitiesPackage::ExtravehicularActivitySupport; + } + + requirement def <'HLR-R007'> ScientificInstrumentDeploymentRequirement { + doc /* The Apollo 11 Mission shall deploy a visual transmission system and at least two scientific experiment packages + on the lunar surface, and these packages shall transmit data to Earth for a minimum of 1 month post-landing. */ + @Rationale { + text = "This requirement is essential for achieving the 'deploy' goal, providing long-term scientific data from the lunar surface and enabling public engagement through visual broadcasts."; + } + + attribute actualDeployedVisualSystems: Integer; + attribute minRequiredVisualSystems: Integer = 1; + + attribute actualDeployedSciencePackages: Integer; + attribute minRequiredSciencePackages: Integer = 2; + + attribute actualDataTransmissionDuration :> ISQ::time; + attribute minDataTransmissionDuration :> ISQ::time = 30 [d]; + + require constraint { + (actualDeployedVisualSystems >= minRequiredVisualSystems) and + (actualDeployedSciencePackages >= minRequiredSciencePackages) and + (actualDataTransmissionDuration >= minDataTransmissionDuration) + } + #refinement dependency 'HLR-R007' to CapabilitiesPackage::ScientificDataAcquisitionAndSampleReturn; + #refinement dependency 'HLR-R007' to CapabilitiesPackage::ExtravehicularActivitySupport; + } + + requirement def <'HLR-R008'> LunarVisualDocumentationRequirement { + doc /* The Apollo 11 Mission shall capture and return to Earth at least 1,000 high-resolution still photographs + and at least 30 minutes of motion picture footage documenting the lunar terrain, deployed equipment, + and crew activities, by July 24, 1969. */ + @Rationale { + text = "This requirement directly supports the 'pictures' goal, providing vital visual data for scientific analysis, historical record, and public inspiration and engagement."; + } + + attribute actualStillPhotosCount: Integer; + attribute minStillPhotosCount: Integer = 1000; + + attribute actualMotionPictureDuration :> ISQ::time; + attribute minMotionPictureDuration :> ISQ::time = 30 [min]; + + require constraint { + (actualStillPhotosCount >= minStillPhotosCount) and + (actualMotionPictureDuration >= minMotionPictureDuration) + } + #refinement dependency 'HLR-R008' to CapabilitiesPackage::ScientificDataAcquisitionAndSampleReturn; + } + + requirement def <'HLR-R009'> NationalSymbolDeploymentRequirement { + doc /* The Apollo 11 Mission shall successfully plant a national symbol on the lunar surface, + ensuring it remains upright and visible for subsequent observation (if possible), + during the initial Extravehicular Activity on July 20, 1969. */ + @Rationale { + text = "This requirement directly fulfills the 'flag' goal, serving as a powerful symbolic demonstration of national achievement and technological prowess, addressing the U.S. Government's and American Public's interests."; + } + + attribute symbolSuccessfullyPlanted: Boolean; + attribute symbolRemainsUpright: Boolean; + attribute symbolVisibility: Boolean; + + require constraint { + symbolSuccessfullyPlanted and symbolRemainsUpright and symbolVisibility + } + #refinement dependency 'HLR-R009' to CapabilitiesPackage::ExtravehicularActivitySupport; + #refinement dependency 'HLR-R009' to CapabilitiesPackage::LunarMobility; + + } + + requirement def <'HLR-R010'> PlanetaryProtectionQuarantineRequirement { + doc /* The Apollo 11 Mission shall implement and adhere to Level V biological quarantine procedures + for the crew and extraterrestrial samples upon return, ensuring no detectable extraterrestrial + biological contamination is released into Earth's biosphere, throughout the 21-day quarantine period. */ + @Rationale { + text = "This requirement is critical for protecting Earth's environment and public health from potential unknown hazards from the Moon, addressing concerns of the U.S. Government and the global public."; + } + + attribute actualQuarantineLevel: Integer; + attribute requiredQuarantineLevel: Integer = 5; + + attribute biologicalContaminationDetected: Boolean; + attribute contaminationThresholdExceeded: Boolean; + + require constraint { + (actualQuarantineLevel == requiredQuarantineLevel) and + not biologicalContaminationDetected and + not contaminationThresholdExceeded + } + #refinement dependency 'HLR-R010' to CapabilitiesPackage::PlanetaryProtection; + } + + requirement def <'HLR-R011'> TrajectoryNavigationPrecision { + doc /* The mission shall maintain the capability to determine spacecraft position with sufficient + accuracy to ensure a safe lunar arrival. */ + @Rationale { + text = "Precise navigation is required to intercept the Moon and enter the correct lunar orbit. Errors in trajectory determination can lead to mission loss."; + } + #refinement dependency TrajectoryNavigationPrecision to CapabilitiesPackage::AutonomousAndAssistedNavigationGuidanceAndControl; + } + + requirement def <'HLR-R026'> WasteManagementEffectiveness { + doc /* The Apollo 11 Mission's waste management system shall effectively collect and store all solid and liquid waste + for the entire mission, preventing contamination of the cabin environment. */ + @Rationale { + text = "Effective waste management is essential for maintaining a hygienic and safe crew cabin environment, preventing health hazards and equipment contamination."; + } + + attribute wasteContaminationDetected: Boolean; + + require constraint { not wasteContaminationDetected } + #refinement dependency 'HLR-R026' to CapabilitiesPackage::DeepSpaceHabitationAndLifeSupport; + } + + requirement def <'HLR-R028'> CrewSleepEnvironmentQuality { + doc /* The Apollo 11 Mission's crew's sleep environment shall allow for at least 6 hours of undisturbed sleep per 24-hour period, + characterized by noise levels below 60 decibels. */ + @Rationale { + text = "Adequate and undisturbed sleep is crucial for maintaining crew physical and mental performance, especially during high-stress and long-duration missions."; + } + + attribute actualUndisturbedSleepDuration :> ISQ::time; + attribute minUndisturbedSleepDuration :> ISQ::time = 6 [h]; + + attribute actualNoiseLevelMax :> ISQ::soundPressureLevel; + attribute maxNoiseLevelReqd :> ISQ::soundPressureLevel = 60 ['dB']; + + require constraint { + (actualUndisturbedSleepDuration >= minUndisturbedSleepDuration) and + (actualNoiseLevelMax <= maxNoiseLevelReqd) + } + #refinement dependency 'HLR-R028' to CapabilitiesPackage::DeepSpaceHabitationAndLifeSupport; + } + + requirement def <'HLR-R030'> CrewAlarmResponseTime { + doc /* The Apollo 11 Mission's crew interface system shall provide visual and auditory alarms for all critical system failures, + with an alarm response time of <= 1 second. */ + @Rationale { + text = "Rapid and clear alarming is essential for the crew to quickly identify and respond to critical system failures, mitigating risks and ensuring safety."; + } + + attribute actualAlarmResponseTime :> ISQ::time; + attribute maxAlarmResponseTime :> ISQ::time = 1 [s]; + + require constraint { actualAlarmResponseTime <= maxAlarmResponseTime } + #refinement dependency 'HLR-R030' to CapabilitiesPackage::DeepSpaceHabitationAndLifeSupport; + } + + requirement def <'HLR-R032'> LunarLanderToOrbiterVoiceComm { + doc /* The Apollo 11 Mission's lunar lander's communication system shall enable voice communication between the crew on the surface + and the crew in lunar orbit, with a signal clarity of 90% (subjective scoring). */ + @Rationale { + text = "Reliable voice communication between the lander and orbiter crews is crucial for coordinating critical operations like rendezvous and docking, ensuring safety and mission success."; + } + + attribute actualSignalClarity: RatioValue; + attribute minSignalClarity: RatioValue = 90['%']; + + require constraint { actualSignalClarity >= minSignalClarity } + #refinement dependency 'HLR-R032' to CapabilitiesPackage::RobustCommunicationAndTelemetry; + } + + requirement def <'HLR-R033'> ExtravehicularMobilityUnitLifeSupportDuration { + doc /* The Apollo 11 Mission's Extravehicular Mobility Unit shall provide life support for a minimum of 4 hours + of continuous Extravehicular Activity in the lunar environment. */ + @Rationale { + text = "Sufficient life support duration for the Extravehicular Mobility Unit is necessary to enable astronauts to perform required tasks on the lunar surface, supporting scientific and symbolic goals."; + } + + attribute actualEMULifeSupportDuration :> ISQ::time; + attribute minEMULifeSupportDuration :> ISQ::time = 4 [h]; + + require constraint { actualEMULifeSupportDuration >= minEMULifeSupportDuration } + #refinement dependency 'HLR-R033' to CapabilitiesPackage::ExtravehicularActivitySupport; + } + + requirement def <'HLR-R035'> ExtravehicularMobilityUnitDexterityForTasks { + doc /* The Apollo 11 Mission's Extravehicular Mobility Unit shall allow for manual dexterity sufficient to operate small tools and manipulate samples + with gloved hands, demonstrating a 90% success rate for task completion during Extravehicular Activity simulations. */ + @Rationale { + text = "Adequate dexterity in the Extravehicular Mobility Unit is essential for astronauts to effectively perform scientific and operational tasks on the lunar surface, directly impacting mission success."; + } + + attribute actualTaskCompletionSuccessRate: RatioValue; + attribute minTaskCompletionSuccessRate: RatioValue = 90['%']; + + require constraint { actualTaskCompletionSuccessRate >= minTaskCompletionSuccessRate } + #refinement dependency 'HLR-R035' to CapabilitiesPackage::ExtravehicularActivitySupport; + #refinement dependency 'HLR-R035' to CapabilitiesPackage::ToolDevelopment; + } + + requirement def <'HLR-R036'> LunarSurfaceMobilityRange { + doc /* The Apollo 11 Mission's lunar surface mobility system shall enable astronauts to traverse distances of up to 50 meters + from the lander during Extravehicular Activity with less than 10% fatigue impact on subsequent tasks. */ + @Rationale { + text = "Ensuring efficient and manageable astronaut mobility on the lunar surface is important for maximizing the scientific return and operational effectiveness of Extravehicular Activities."; + } + + attribute actualTraverseDistanceCapability :> ISQ::length; + attribute minTraverseDistanceCapability :> ISQ::length = 50 [m]; + + attribute actualFatigueImpact: RatioValue; + attribute maxFatigueImpact: RatioValue = 10['%']; + + require constraint { + (actualTraverseDistanceCapability >= minTraverseDistanceCapability) and + (actualFatigueImpact <= maxFatigueImpact) + } + #refinement dependency 'HLR-R036' to CapabilitiesPackage::LunarMobility; + } + + requirement def <'HLR-R037'> ExtravehicularActivityToolSecurity { + doc /* All Extravehicular Activity tools used in the Apollo 11 Mission shall be operable with a minimum of two points of contact (e.g., tethered or hand-held) + to prevent loss in lunar gravity. */ + @Rationale { + text = "Securing tools during Extravehicular Activity is vital to prevent loss in the low lunar gravity environment, ensuring tools are available for all planned tasks and do not become debris."; + } + + attribute toolsMeetContactRequirement: Boolean; + attribute toolsLostDuringEVA: Integer; + attribute maxToolsLost: Integer = 0; + + require constraint { + toolsMeetContactRequirement and + (toolsLostDuringEVA <= maxToolsLost) + } + #refinement dependency 'HLR-R037' to CapabilitiesPackage::ExtravehicularActivitySupport; + } + + requirement def <'HLR-R038'> SamplePristinePreservation { + doc /* Apollo 11 Mission's lunar samples shall be collected and stored in a manner that preserves their pristine lunar environment + and prevents terrestrial contamination, ensuring less than 0.1% terrestrial material contamination by mass. */ + @Rationale { + text = "Maintaining the pristine state of lunar samples is crucial for their scientific value, as contamination would compromise the integrity of geological analysis and understanding of lunar composition."; + } + + attribute actualTerrestrialContamination: RatioValue; + attribute maxTerrestrialContamination: RatioValue = 0.1['%']; + + require constraint { actualTerrestrialContamination <= maxTerrestrialContamination } + #refinement dependency 'HLR-R038' to CapabilitiesPackage::ScientificDataAcquisitionAndSampleReturn; + #refinement dependency 'HLR-R038' to CapabilitiesPackage::PlanetaryProtection; + } + + requirement def <'HLR-R040'> SampleGeologicalContext { + doc /* The Apollo 11 Mission shall obtain geological context for all collected samples through photographic documentation + with clear scale references, ensuring >= 90% of samples are correlated with their collection location. */ + @Rationale { + text = "Providing accurate geological context for samples is vital for interpreting their scientific significance and understanding the Moon's stratigraphy and formation."; + } + + attribute actualSampleCorrelationPercentage: RatioValue; + attribute minSampleCorrelationPercentage: RatioValue = 90['%']; + attribute photosHaveScaleReferences: Boolean; + + require constraint { + (actualSampleCorrelationPercentage >= minSampleCorrelationPercentage) and + photosHaveScaleReferences + } + #refinement dependency 'HLR-R040' to CapabilitiesPackage::ScientificDataAcquisitionAndSampleReturn; + } + + requirement def <'HLR-R045'> CriticalComponentRedundancy { + doc /* The Apollo 11 Mission shall have redundancy (N+1 or greater) for all critical single-point-of-failure components + in propulsion, Guidance, Navigation, and Control, and life support systems, ensuring continued operation after a single failure. */ + @Rationale { + text = "Redundancy for single points of failure is a fundamental safety and reliability measure, allowing the mission to continue even if a critical component fails."; + } + + attribute singleFailureCausesOperationalLoss: Boolean; + + require constraint { not singleFailureCausesOperationalLoss } + #refinement dependency 'HLR-R045' to CapabilitiesPackage::ContingencyPlanningAndRapidResponse; + } + + requirement def <'HLR-R046'> AbortSequenceExecutionTime { + doc /* Apollo 11 Mission Control shall be capable of initiating and executing an abort sequence + from any point during ascent or Trans-Lunar/Earth Coast within 5 minutes of an abort decision. */ + @Rationale { + text = "Rapid abort capability is a critical safety net, allowing the mission to be terminated and the crew safely returned in response to unforeseen catastrophic failures."; + } + + attribute actualAbortExecutionTime :> ISQ::time; + attribute maxAbortExecutionTime :> ISQ::time = 5 [min]; + + require constraint { actualAbortExecutionTime <= maxAbortExecutionTime } + #refinement dependency 'HLR-R046' to CapabilitiesPackage::ContingencyPlanningAndRapidResponse; + #refinement dependency 'HLR-R046' to CapabilitiesPackage::RealtimeMissionControl; + } + + requirement def <'HLR-R047'> ManualOverrideResponseTime { + doc /* The Apollo 11 Mission's crew shall be able to manually override automated flight control systems + for all major maneuvers (e.g., Trans-Lunar Injection, Lunar Orbit Insertion, Powered Descent Initiation) with a response time of <= 1 second. */ + @Rationale { + text = "Manual override capability provides a crucial human element of control and contingency in case automated systems fail or encounter unexpected conditions, directly enhancing safety."; + } + + attribute actualOverrideResponseTime :> ISQ::time; + attribute maxOverrideResponseTime :> ISQ::time = 1 [s]; + + require constraint { actualOverrideResponseTime <= maxOverrideResponseTime } + #refinement dependency 'HLR-R047' to CapabilitiesPackage::HumanPerformanceUnderExtremeStress; + } + + requirement def <'HLR-R048'> GroundSegmentDataUpdateFrequency { + doc /* The Apollo 11 Mission's ground segment shall provide up-to-date trajectory and state vector information + to the flight crew at least every 10 minutes during dynamic flight phases. */ + @Rationale { + text = "Frequent and up-to-date information from ground control is essential for the crew's situational awareness, navigation, and ability to execute maneuvers safely and accurately."; + } + + attribute actualUpdateInterval :> ISQ::time; + attribute maxUpdateInterval :> ISQ::time = 10 [min]; + + require constraint { actualUpdateInterval <= maxUpdateInterval } + #refinement dependency 'HLR-R048' to CapabilitiesPackage::RealtimeMissionControl; + } + + requirement def <'HLR-R049'> LunarLanderAscentReadinessTime { + doc /* The Apollo 11 Mission's lunar lander's ascent stage shall be capable of launching from the lunar surface + within 24 hours of landing, to align with rendezvous opportunities in lunar orbit. */ + @Rationale { + text = "A limited readiness time for ascent ensures the crew can depart the lunar surface within favorable orbital mechanics windows for rendezvous, crucial for their return."; + } + + attribute actualTimeFromLandingToAscentLaunch :> ISQ::time; + attribute maxTimeToAscentLaunch :> ISQ::time = 24 [h]; + + require constraint { actualTimeFromLandingToAscentLaunch <= maxTimeToAscentLaunch } + #refinement dependency 'HLR-R049' to CapabilitiesPackage::LunarSurfaceLandingAndAscent; + } + + requirement def <'HLR-R050'> FlightSoftwareUpdateTime { + doc /* Apollo 11 Mission Control shall be able to reconfigure and uplink flight software updates + to the spacecraft's primary computers within 1 hour in response to critical in-flight anomalies. */ + @Rationale { + text = "The ability to rapidly update flight software in-flight provides a vital corrective capability to address unforeseen bugs or adapt to changing mission conditions."; + } + + attribute actualSoftwareUpdateDuration :> ISQ::time; + attribute maxSoftwareUpdateDuration :> ISQ::time = 1 [h]; + + require constraint { actualSoftwareUpdateDuration <= maxSoftwareUpdateDuration } + #refinement dependency 'HLR-R050' to CapabilitiesPackage::ComplexSoftwareDevelopment; + } + + requirement def <'HLR-R052'> CrewEmergencyMedicalProficiency { + doc /* The Apollo 11 Mission crew shall demonstrate proficiency in emergency medical procedures + to handle common in-flight illnesses or minor injuries without external assistance for up to 72 hours. */ + @Rationale { + text = "Crew self-sufficiency in basic medical emergencies is essential given the vast distances and isolation of lunar missions, where immediate external medical aid is impossible."; + } + + attribute medicalProficiencyScore: Real; + attribute minMedicalProficiencyScore: Real = 90; + + attribute externalAssistanceRequiredBeforeTime :> ISQ::time; + attribute minSelfSufficiencyDuration :> ISQ::time = 72 [h]; + + require constraint { + (medicalProficiencyScore >= minMedicalProficiencyScore) and + (externalAssistanceRequiredBeforeTime >= minSelfSufficiencyDuration) + } + #refinement dependency 'HLR-R052' to CapabilitiesPackage::CrewTrainingAndSimulation; + } + + requirement def <'HLR-R053'> InFlightProcedureErrorRate { + doc /* The Apollo 11 Mission crew shall be capable of performing all critical in-flight procedures (e.g., docking, re-entry preparation) + with an error rate of <= 0.5% under nominal conditions. */ + @Rationale { + text = "A very low error rate for critical procedures is paramount for mission success and crew safety, as failures in these steps could have catastrophic consequences."; + } + + attribute actualProcedureErrorRate: RatioValue; + attribute maxProcedureErrorRate: RatioValue = 0.5['%']; + + require constraint { actualProcedureErrorRate <= maxProcedureErrorRate } + #refinement dependency 'HLR-R053' to CapabilitiesPackage::HumanPerformanceUnderExtremeStress; + } + + requirement def <'HLR-R054'> CrewNutritionAndHydration { + doc /* Apollo 11 Mission astronauts shall be able to consume all provided food and water + throughout the mission without experiencing significant gastrointestinal issues or nutrient deficiencies. */ + @Rationale { + text = "Adequate nutrition and hydration are fundamental for maintaining astronaut health, energy levels, and cognitive function throughout the demanding mission."; + } + + attribute significantGIIssuesExperienced: Boolean; + attribute nutrientDeficienciesObserved: Boolean; + + require constraint { + not significantGIIssuesExperienced and + not nutrientDeficienciesObserved + } + #refinement dependency 'HLR-R054' to CapabilitiesPackage::DeepSpaceHabitationAndLifeSupport; + } + + requirement def <'HLR-R055'> CrewPsychologicalState { + doc /* The Apollo 11 Mission crew shall maintain a positive psychological state as assessed by structured psychological evaluations + throughout the mission. */ + @Rationale { + text = "Crew psychological well-being is vital for effective teamwork, decision-making, and overall mission performance, especially during long periods of isolation and stress."; + } + + attribute actualPsychologicalStateScore: Real; // e.g., on a positive/negative scale (0-100) + attribute minPsychologicalStateScore: Real = 75; + + require constraint { actualPsychologicalStateScore >= minPsychologicalStateScore } + #refinement dependency 'HLR-R055' to CapabilitiesPackage::HumanPerformanceUnderExtremeStress; + } + + requirement def <'HLR-R057'> MicrometeoroidPenetrationRisk { + doc /* The Apollo 11 Mission spacecraft shall be designed to minimize micro-meteoroid penetration risk + to critical habitable volumes to less than 1 event in 1,000 missions. */ + @Rationale { + text = "Minimizing micrometeoroid penetration risk is a key safety requirement to protect the crew and critical systems from space debris impacts that could cause depressurization or damage."; + } + + attribute actualPenetrationProbabilityPerMission: Real; // Represents a probability (0-1) + attribute maxAcceptablePenetrationProbability: Real = 0.001; // 1/1000 + + require constraint { actualPenetrationProbabilityPerMission <= maxAcceptablePenetrationProbability } + #refinement dependency 'HLR-R057' to CapabilitiesPackage::DeepSpaceHabitationAndLifeSupport; + } + + requirement def <'HLR-R059'> LunarElementEnvironmentalResistance { + doc /* All external mission elements left on the lunar surface by the Apollo 11 Mission shall be designed to withstand lunar thermal cycles + (approx. +/- 150°C) and lunar dust exposure for a minimum of 3 months while maintaining structural integrity. */ + @Rationale { + text = "Ensuring the long-term survival of deployed lunar elements in the harsh lunar environment is crucial for extended scientific data collection and mission legacy."; + } + + attribute structuralIntegrityMaintained: Boolean; + attribute minResistanceDuration :> ISQ::time; + require constraint { structuralIntegrityMaintained } // Assuming tested duration meets minResistanceDuration + #refinement dependency 'HLR-R059' to CapabilitiesPackage::ScientificDataAcquisitionAndSampleReturn; + } + + requirement def <'HLR-R060'> PostFlightDataArchiving { + doc /* The Apollo 11 Mission shall ensure post-flight data retention and archiving of all telemetry, voice, video, + and scientific data, maintaining 99.99% data availability for future analysis for a minimum of 50 years. */ + @Rationale { + text = "Long-term data archiving ensures that valuable mission data is preserved for future scientific research, engineering analysis, and historical purposes, benefiting future generations."; + } + + attribute actualDataAvailabilityPercentage: RatioValue; + attribute minDataAvailabilityPercentage: RatioValue = 99.99['%']; + + attribute actualArchivalDuration :> ISQ::time; + attribute minArchivalDuration :> ISQ::time = 50 ['yr']; + + require constraint { + (actualDataAvailabilityPercentage >= minDataAvailabilityPercentage) and + (actualArchivalDuration >= minArchivalDuration) + } + #refinement dependency 'HLR-R060' to CapabilitiesPackage::ComplexLogisticsAndIntegration; + } + + requirement def <'HLR-R061'> PropulsionSystemMissionReliability { + doc /* The mission's major maneuvers shall be executed using highly reliable propulsive systems + to ensure mission success and return. */ + @Rationale { + text = "Failure during critical maneuvers like LOI or TEI would leave the crew stranded. Engine systems must be highly predictable."; + } + #refinement dependency 'HLR-R061' to CapabilitiesPackage::InSpacePropulsion; + } + + requirement def <'HLR-R062'> MechanicalLoadResilience { + doc /* All primary structures shall withstand the flight environment without compromising + mission functionality. */ + @Rationale { + text = "The spacecraft must survive extreme mechanical stresses during launch and reentry to protect internal subsystems."; + } + #refinement dependency 'HLR-R062' to CapabilitiesPackage::HeavyLiftLaunch; + } + + requirement def <'HLR-R063'> LiveVisualBroadcast { + doc /* The mission shall provide a live visual record of lunar surface operations to satisfy + public and scientific return goals. */ + @Rationale { + text = "Real-time coverage is vital for fulfilling national prestige and providing visual context for Mission Control."; + } + #refinement dependency 'HLR-R063' to CapabilitiesPackage::RobustCommunicationAndTelemetry; + } + + requirement def <'HLR-R064'> ExtendedScientificOperation { + doc /* Deployed lunar elements shall remain operational post-landing to provide + long-term data return. */ + @Rationale { + text = "Scientific value is maximized by instruments that continue to collect data long after the crew departs."; + } + #refinement dependency 'HLR-R064' to CapabilitiesPackage::ScientificDataAcquisitionAndSampleReturn; + } + + requirement def <'HLR-R065'> CriticalSystemAvailability { + doc /* All mission-critical systems shall be designed for maximum uptime to prevent + catastrophic mission loss. */ + @Rationale { + text = "High availability is the cornerstone of safety, ensuring that single-point failures do not result in the loss of crew or spacecraft."; + } + #refinement dependency 'HLR-R065' to CapabilitiesPackage::ComplexLogisticsAndIntegration; + } + + requirement def <'HLR-R066'> PublicSupportAndAffairsManagement { + doc /* The Apollo 11 program shall maintain a public affairs office to provide real-time updates and + educational materials to the global public, ensuring a favorable public opinion rating of + at least 60% throughout the mission duration. */ + @Rationale { + text = "Sustained political and public support is necessary to maintain the massive financial commitment required for the program's existence."; + } + #refinement dependency 'HLR-R066' to CapabilitiesPackage::ProgrammaticAndPublicAffairsManagement; + } + + requirement def <'HLR-R067'> ElectricalPowerAvailability { + doc /* The spacecraft electrical power system shall provide a continuous supply of regulated DC power + to all primary bus systems, maintaining a minimum of 25% energy reserve at all times + during the nominal mission profile. */ + @Rationale { + text = "Reliable power distribution is fundamental to the operation of all other spacecraft systems and is a prerequisite for mission success."; + } + #refinement dependency 'HLR-R067' to CapabilitiesPackage::PowerGenerationAndDistribution; + } + + requirement def <'HLR-R068'> LaunchWindowPrecision { + doc /* Launch operations shall execute the final countdown and ignition sequence within a ±2.5-second + launch window to ensure the spacecraft meets the required planetary alignment for the + Trans-Lunar Injection. */ + @Rationale { + text = "Precise management of ground-based launch activities is required to ensure the launch system places the spacecraft into the correct trajectory efficiently."; + } + #refinement dependency 'HLR-R068' to CapabilitiesPackage::LaunchOperationsManagement; + } + + requirement def <'HLR-R069'> OperationalWorkaroundProtocol { + doc /* The mission architecture shall provide the crew and ground controllers with 'workaround' + protocols for all non-critical system anomalies, enabling mission continuation despite + minor hardware or software deviations. */ + @Rationale { + text = "The inherent human capacity to adjust to unexpected challenges is a critical safety function that allows for mission success when automated systems encounter unforeseen conditions."; + } + #refinement dependency 'HLR-R069' to CapabilitiesPackage::AdaptabilityAndProblemSolving; + } + +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/MissionSpecificationPackage.sysml b/language/src/test/resources/Apollo_11/MissionSpecificationPackage.sysml new file mode 100644 index 00000000..dfff2fb6 --- /dev/null +++ b/language/src/test/resources/Apollo_11/MissionSpecificationPackage.sysml @@ -0,0 +1,113 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package MissionSpecificationPackage { + + private import MissionRequirementsPackage::*; + private import MissionPackage::*; + private import OperationsPackage::*; + + requirement apollo11MissionSpecification { + doc /* Apollo 11 Mission requirements group */ + subject apollo11Mission : Apollo11Mission; + + requirement 'hlr-R001' : CrewReturnSafetyRequirement; + requirement 'hlr-R002' : LunarLanderSoftLandingRequirement; + requirement 'hlr-R003' : TransLunarInjectionAccuracyRequirement; + requirement 'hlr-R004' : CommunicationUptimeRequirement; + requirement 'hlr-R006' : LunarSampleCollectionQuantityRequirement; + requirement 'hlr-R007' : ScientificInstrumentDeploymentRequirement; + requirement 'hlr-R008' : LunarVisualDocumentationRequirement; + requirement 'hlr-R009' : NationalSymbolDeploymentRequirement; + requirement 'hlr-R010' : PlanetaryProtectionQuarantineRequirement; + requirement 'hlr-R026' : WasteManagementEffectiveness; + requirement 'hlr-R028' : CrewSleepEnvironmentQuality; + requirement 'hlr-R030' : CrewAlarmResponseTime; + requirement 'hlr-R032' : LunarLanderToOrbiterVoiceComm; + requirement 'hlr-R033' : ExtravehicularMobilityUnitLifeSupportDuration; + requirement 'hlr-R035' : ExtravehicularMobilityUnitDexterityForTasks; + requirement 'hlr-R036' : LunarSurfaceMobilityRange; + requirement 'hlr-R037' : ExtravehicularActivityToolSecurity; + requirement 'hlr-R038' : SamplePristinePreservation; + requirement 'hlr-R040' : SampleGeologicalContext; + requirement 'hlr-R045' : CriticalComponentRedundancy; + requirement 'hlr-R046' : AbortSequenceExecutionTime; + requirement 'hlr-R047' : ManualOverrideResponseTime; + requirement 'hlr-R048' : GroundSegmentDataUpdateFrequency; + requirement 'hlr-R049' : LunarLanderAscentReadinessTime; + requirement 'hlr-R050' : FlightSoftwareUpdateTime; + requirement 'hlr-R052' : CrewEmergencyMedicalProficiency; + requirement 'hlr-R053' : InFlightProcedureErrorRate; + requirement 'hlr-R054' : CrewNutritionAndHydration; + requirement 'hlr-R055' : CrewPsychologicalState; + requirement 'hlr-R057' : MicrometeoroidPenetrationRisk; + requirement 'hlr-R059' : LunarElementEnvironmentalResistance; + requirement 'hlr-R060' : PostFlightDataArchiving; + + requirement 'hlr-R005' : SustainedCabinHabitability; + requirement 'hlr-R011' : TrajectoryNavigationPrecision; + requirement 'hlr-R061' : PropulsionSystemMissionReliability; + requirement 'hlr-R062' : MechanicalLoadResilience; + requirement 'hlr-R063' : LiveVisualBroadcast; + requirement 'hlr-R064' : ExtendedScientificOperation; + requirement 'hlr-R065' : CriticalSystemAvailability; + requirement 'hlr-R066' : PublicSupportAndAffairsManagement; + requirement 'hlr-R067' : ElectricalPowerAvailability; + requirement 'hlr-R068' : LaunchWindowPrecision; + requirement 'hlr-R069' : OperationalWorkaroundProtocol; + + satisfy 'hlr-R001' by apollo11Mission.apollo11Phases.recoveryQuarantine.recoveryQuarantineOperations.retrieveCrewAndCM; + satisfy 'hlr-R002' by apollo11Mission.apollo11Phases.poweredDescent.poweredDescentOperations.executePoweredDescentBurn; + satisfy 'hlr-R003' by apollo11Mission.apollo11Phases.tli.tliPhaseOperations.executeTLIBurn; + satisfy 'hlr-R004' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.communicateWithMissionControl; + satisfy 'hlr-R006' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.collectLunarSamples; + satisfy 'hlr-R007' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.deployScientificInstruments; + satisfy 'hlr-R008' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.performLunarEVA; + satisfy 'hlr-R009' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.performLunarEVA; + satisfy 'hlr-R010' by apollo11Mission.apollo11Phases.recoveryQuarantine.recoveryQuarantineOperations.initiateQuarantineProcedures; + satisfy 'hlr-R026' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.monitorSpacecraftSystems; + satisfy 'hlr-R028' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.manageCrewRestPeriods; + satisfy 'hlr-R030' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.monitorSpacecraftSystems; + satisfy 'hlr-R032' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.performLunarEVA; + satisfy 'hlr-R033' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.performLunarEVA; + satisfy 'hlr-R035' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.performLunarEVA; + satisfy 'hlr-R036' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.performLunarEVA; + satisfy 'hlr-R037' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.performLunarEVA; + satisfy 'hlr-R038' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.collectLunarSamples; + satisfy 'hlr-R040' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.collectLunarSamples; + satisfy 'hlr-R045' by apollo11Mission.apollo11Phases.loi.loiPhaseOperations.executeLOIBurn; + satisfy 'hlr-R046' by apollo11Mission.apollo11Phases.launch.launchPhaseOperations.executeLaunchSequence; + satisfy 'hlr-R047' by apollo11Mission.apollo11Phases.poweredDescent.poweredDescentOperations.performManualPiloting; + satisfy 'hlr-R048' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.communicateWithMissionControl; + satisfy 'hlr-R049' by apollo11Mission.apollo11Phases.lunarAscentRendezvous.lunarAscentRendezvousOperations.executeLunarAscentBurn; + satisfy 'hlr-R050' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.communicateWithMissionControl; + satisfy 'hlr-R052' by apollo11Mission.apollo11Phases.preparation.prepareForMissionPhaseOperations.transferCrewToVehicle; + satisfy 'hlr-R053' by apollo11Mission.apollo11Phases.lunarAscentRendezvous.lunarAscentRendezvousOperations.conductLMCSMDocking; + satisfy 'hlr-R054' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.manageCrewRestPeriods; + satisfy 'hlr-R055' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.manageCrewRestPeriods; + satisfy 'hlr-R057' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.monitorSpacecraftSystems; + satisfy 'hlr-R059' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.deployScientificInstruments; + satisfy 'hlr-R060' by apollo11Mission.apollo11Phases.recoveryQuarantine.recoveryQuarantineOperations; + + satisfy 'hlr-R005' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.monitorSpacecraftSystems; + satisfy 'hlr-R005' by apollo11Mission.apollo11Phases.tec.tecPhaseOperations.monitorSpacecraftSystems; + satisfy 'hlr-R011' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.conductMidCourseCorrections; + satisfy 'hlr-R061' by apollo11Mission.apollo11Phases.loi.loiPhaseOperations.executeLOIBurn; + satisfy 'hlr-R062' by apollo11Mission.apollo11Phases.launch.launchPhaseOperations.executeLaunchSequence; + satisfy 'hlr-R063' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.communicateWithMissionControl; + satisfy 'hlr-R063' by apollo11Mission.apollo11Phases.tec.tecPhaseOperations.communicateWithMissionControl; + satisfy 'hlr-R064' by apollo11Mission.apollo11Phases.lunarSurfaceOps.lunarSurfaceOpsOperations.deployScientificInstruments; + satisfy 'hlr-R065' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.monitorSpacecraftSystems; + satisfy 'hlr-R065' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.monitorSpacecraftSystems; + satisfy 'hlr-R066' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.communicateWithMissionControl; + satisfy 'hlr-R066' by apollo11Mission.apollo11Phases.tec.tecPhaseOperations.communicateWithMissionControl; + satisfy 'hlr-R067' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.monitorSpacecraftSystems; + satisfy 'hlr-R067' by apollo11Mission.apollo11Phases.tlc.tlcPhaseOperations.monitorSpacecraftSystems; + satisfy 'hlr-R068' by apollo11Mission.apollo11Phases.launch.launchPhaseOperations.performPreLaunchCountdown; + satisfy 'hlr-R069' by apollo11Mission.apollo11Phases.poweredDescent.poweredDescentOperations.performManualPiloting; + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/OperationsPackage.sysml b/language/src/test/resources/Apollo_11/OperationsPackage.sysml new file mode 100644 index 00000000..701ec7f7 --- /dev/null +++ b/language/src/test/resources/Apollo_11/OperationsPackage.sysml @@ -0,0 +1,137 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package OperationsPackage { + + private import CoSMAPackage::*; + + action def LoadConsumablesAndPropellants :> Operation { + doc /* The process of fueling the Saturn V rocket and loading all necessary consumables like oxygen and water into the spacecraft. */ + } + action def TransferCrewToVehicle :> Operation { + doc /* The operation where the flight crew moves from the crew quarters to the launch pad and ingresses the Command Module. */ + } + + action def PerformPreLaunchCountdown :> Operation { + doc /* The synchronized sequence of checks and configurations performed in the final hours and minutes leading up to liftoff. */ + } + action def ExecuteLaunchSequence :> Operation { + doc /* The automated and monitored sequence of engine ignitions, vehicle ascent, and staging events that propel the vehicle into orbit. */ + } + action def MonitorAscentTrajectory :> Operation { + doc /* The continuous tracking of the vehicle's speed, altitude, and flight path during ascent to ensure it is following the correct trajectory. */ + } + + action def ExecuteTLIBurn :> Operation { + doc /* The critical engine burn of the S-IVB third stage to propel the spacecraft out of Earth orbit and onto a trajectory to the Moon. */ + } + action def PerformTranspositionDockingExtraction :> Operation { + doc /* The complex maneuver where the CSM separates, turns around, docks with the LM, and extracts it from the S-IVB stage. */ + } + action def ConductMidCourseCorrections :> Operation { + doc /* Small propulsive burns performed during the coast phases to refine the spacecraft's trajectory. */ + } + action def MonitorSpacecraftSystems :> Operation { + doc /* The continuous monitoring of all onboard systems by the crew and Mission Control to ensure vehicle health. */ + } + action def CommunicateWithMissionControl :> Operation { + doc /* The two-way exchange of voice, telemetry, and command data between the spacecraft and ground stations. */ + } + action def ManageCrewRestPeriods :> Operation { + doc /* The scheduling and management of sleep, meals, and downtime for the crew to ensure their health and performance. */ + } + + action def ExecuteLOIBurn :> Operation { + doc /* The engine burn of the Service Module to slow the spacecraft, allowing it to be captured into a stable lunar orbit. */ + } + action def ConductLunarOrbitCheckouts :> Operation { + doc /* A series of system health checks performed on the CSM and LM while in lunar orbit. */ + } + action def PrepareLMforUndocking :> Operation { + doc /* The process of activating the Lunar Module's systems and configuring it for independent flight. */ + } + action def PerformLMUndocking :> Operation { + doc /* The physical separation of the Lunar Module from the Command Module in lunar orbit. */ + } + + action def ExecutePoweredDescentBurn :> Operation { + doc /* The continuous, throttleable engine burn of the LM Descent Stage to control the descent from orbit to the lunar surface. */ + } + action def MonitorDescentTelemetry :> Operation { + doc /* The real-time tracking of the LM's altitude and velocity during the landing phase. */ + } + action def PerformManualPiloting :> Operation { + doc /* The manual control of the LM by the Commander during the final phase of landing to avoid hazards. */ + } + action def ConductLMPostLandingChecks :> Operation { + doc /* A series of procedures performed after landing to safe the LM's systems and verify its integrity. */ + } + action def PrepareForEVA :> Operation { + doc /* The process of the crew donning their spacesuits and depressurizing the LM cabin for surface exploration. */ + } + action def PerformLunarEVA :> Operation { + doc /* The extravehicular activity where the crew operates on the lunar surface to explore and conduct experiments. */ + } + action def CollectLunarSamples :> Operation { + doc /* The task of gathering and storing rock and soil samples from the lunar surface. */ + } + action def DeployScientificInstruments :> Operation { + doc /* The setup of the Early Apollo Scientific Experiments Package (EASEP) on the lunar surface. */ + } + action def ConcludeEVA :> Operation { + doc /* The process of the crew re-entering the LM, stowing equipment, and closing the hatch. */ + } + action def ManageLunarSurfaceRestPeriod :> Operation { + doc /* The scheduled rest and sleep period for the crew while on the Moon. */ + } + + action def ExecuteLunarAscentBurn :> Operation { + doc /* The firing of the LM Ascent Stage engine to lift off from the lunar surface and return to orbit. */ + } + action def PerformRendezvousManeuvers :> Operation { + doc /* A series of precise orbital maneuvers performed by the LM to match the orbit of and approach the CSM. */ + } + action def ConductLMCSMDocking :> Operation { + doc /* The physical connection of the LM Ascent Stage with the orbiting CSM. */ + } + action def TransferCrewAndSamples :> Operation { + doc /* The movement of the crew and collected lunar samples from the LM back into the Command Module. */ + } + action def JettisonLM :> Operation { + doc /* The final separation from the LM Ascent Stage, leaving it in lunar orbit. */ + } + + action def ExecuteTEIBurn :> Operation { + doc /* The engine burn of the Service Module to propel the CSM out of lunar orbit and onto a trajectory back to Earth. */ + } + action def PrepareCMforReentry :> Operation { + doc /* Final checks and configurations of the Command Module in preparation for atmospheric entry. */ + } + + action def SeparateModules :> Operation { + doc /* The pyrotechnic separation of the Command Module from the Service Module just before reentry. */ + } + action def GuideReentryTrajectory :> Operation { + doc /* The controlled, lifting flight of the Command Module through the atmosphere to manage heating and target the landing zone. */ + } + action def DeployParachutes :> Operation { + doc /* The sequential deployment of drogue and main parachutes to slow the Command Module for a safe splashdown. */ + } + action def ConductSplashdownOperations :> Operation { + doc /* The final water landing of the Command Module and the activation of its recovery systems. */ + } + + action def RetrieveCrewAndCM :> Operation { + doc /* The location and recovery of the crew and capsule from the ocean by naval forces. */ + } + action def InitiateQuarantineProcedures :> Operation { + doc /* The implementation of biological isolation protocols for the crew, capsule, and samples upon their return. */ + } + action def SecureLunarSamples :> Operation { + doc /* The process of packaging and transporting the returned lunar samples to the Lunar Receiving Laboratory. */ + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/ProgramPackage.sysml b/language/src/test/resources/Apollo_11/ProgramPackage.sysml new file mode 100644 index 00000000..15228707 --- /dev/null +++ b/language/src/test/resources/Apollo_11/ProgramPackage.sysml @@ -0,0 +1,107 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package ProgramPackage { + + private import MissionPackage::*; + private import CoSMAPackage::*; + private import AstronautsPackage::*; + + part def ApolloProgram :> Program { + doc /* The Apollo program, also known as Project Apollo, was the United States human spaceflight program led by NASA, which landed the first humans on the Moon in 1969. */ + + part apollo11 : Apollo11Mission :> missions; + + //https://en.wikipedia.org/wiki/Apollo_program + part 'as-201' : Mission { + doc /* First flight of Saturn IB and Block I CSM; suborbital to Atlantic Ocean; qualified heat shield to orbital reentry speed. */ + } :> missions; + part 'as-203' : Mission { + doc /* No spacecraft; observations of liquid hydrogen fuel behavior in orbit to support design of S-IVB restart capability. */ + } :> missions; + part 'as-202' : Mission { + doc /* Suborbital flight of CSM to Pacific Ocean. */ + } :> missions; + part apollo1 : MannedSpaceMission { + doc /* Not flown. All crew members died in a fire during a launch pad test on January 27, 1967. */ + individual part : 'Gus Grissom' :> crew; + individual part : 'Ed White' :> crew; + individual part : 'Roger B. Chaffee' :> crew; + } :> missions; + part apollo4 : Mission { + doc /* First test flight of Saturn V, placed a CSM in a high Earth orbit; demonstrated S-IVB restart; qualified CM heat shield to lunar reentry speed. */ + } :> missions; + part apollo5 : Mission { + doc /* Earth orbital flight test of LM, launched on Saturn IB; demonstrated ascent and descent propulsion; human-rated the LM. No crew. */ + } :> missions; + part apollo6 : Mission { + doc /* Uncrewed, second flight of Saturn V, attempted demonstration of trans-lunar injection, and direct-return abort using SM engine; three engine failures, including failure of S-IVB restart. Flight controllers used SM engine to repeat Apollo 4's flight profile. Human-rated the Saturn V. */ + } :> missions; + part apollo7 : MannedSpaceMission { + doc /* First crewed Earth orbital demonstration of Block II CSM, launched on Saturn IB. First live television broadcast from a crewed mission. */ + individual part : 'Wally Schirra' :> crew; + individual part : 'Walt Cunningham' :> crew; + individual part : 'Donn Eisele' :> crew; + } :> missions; + part apollo8 : MannedSpaceMission { + doc /* First crewed flight of Saturn V; First crewed flight to Moon; CSM made 10 lunar orbits in 20 hours. */ + individual part : 'Frank Borman' :> crew; + individual part : 'James Lovell' :> crew; + individual part : 'William Anders' :> crew; + } :> missions; + part apollo9 : MannedSpaceMission { + doc /* Second crewed flight of Saturn V; First crewed flight of CSM and LM in Earth orbit; demonstrated portable life support system to be used on the lunar surface. */ + individual part : 'James McDivitt' :> crew; + individual part : 'David Scott' :> crew; + individual part : 'Russell Schweickart' :> crew; + } :> missions; + part apollo10 : MannedSpaceMission { + doc /* Dress rehearsal for first lunar landing; flew LM down to 50,000 ft (15 km; 9.5 mi) from lunar surface. */ + individual part : 'Thomas Stafford' :> crew; + individual part : 'John Young' :> crew; + individual part : 'Eugene Cernan' :> crew; + } :> missions; + part apollo12 : MannedSpaceMission { + doc /* Second landing, in Ocean of Storms near Surveyor 3. Surface EVA time: 7h 45m. Samples returned: 75.62 lb (34.30 kg). */ + individual part : 'Pete Conrad' :> crew; + individual part : 'Richard Gordon' :> crew; + individual part : 'Alan Bean' :> crew; + } :> missions; + part apollo13 : MannedSpaceMission { + doc /* Third landing attempt aborted in transit to the Moon, due to SM failure. Crew used LM as "lifeboat" to return to Earth. Mission called a "successful failure". */ + individual part : 'James Lovell' :> crew; + individual part : 'Jack Swigert' :> crew; + individual part : 'Fred Haise' :> crew; + } :> missions; + part apollo14 : MannedSpaceMission { + doc /* Third landing, in Fra Mauro formation. Surface EVA time: 9h 21m. Samples returned: 94.35 lb (42.80 kg). */ + individual part : 'Alan Shepard' :> crew; + individual part : 'Stuart Roosa' :> crew; + individual part : 'Edgar Mitchell' :> crew; + } :> missions; + part apollo15 : MannedSpaceMission { + doc /* Fourth landing, in Hadley-Apennine. First extended mission, used Rover on Moon. Surface EVA time: 18h 33m. Samples returned: 169.10 lb (76.70 kg). */ + individual part : 'David Scott' :> crew; + individual part : 'Alfred Worden' :> crew; + individual part : 'James Irwin' :> crew; + } :> missions; + part apollo16 : MannedSpaceMission { + doc /* Fifth landing, in Plain of Descartes. Second extended mission, used Rover on Moon. Surface EVA time: 20h 14m. Samples returned: 207.89 lb (94.30 kg). */ + individual part : 'John Young' :> crew; + individual part : 'Ken Mattingly' :> crew; + individual part : 'Charles Duke' :> crew; + } :> missions; + part apollo17 : MannedSpaceMission { + doc /* Only Saturn V night launch. Sixth landing, in Taurus-Littrow. Third extended mission, used Rover on Moon. First geologist on the Moon. Apollo's last crewed Moon landing. Surface EVA time: 22h 2m. Samples returned: 243.40 lb (110.40 kg). */ + individual part : 'Eugene Cernan' :> crew; + individual part : 'Ronald Evans' :> crew; + individual part : 'Harrison Schmitt' :> crew; + } :> missions; + + } + +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/StakeholderNeedsPackage.sysml b/language/src/test/resources/Apollo_11/StakeholderNeedsPackage.sysml new file mode 100644 index 00000000..44b6d346 --- /dev/null +++ b/language/src/test/resources/Apollo_11/StakeholderNeedsPackage.sysml @@ -0,0 +1,166 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package StakeholderNeedsPackage { + + private import ModelingMetadata::*; + private import CoSMAPackage::*; + + requirement def <'SHN-N001'> MissionSuccess :> StakeholderNeed { + doc /* The mission shall succeed in all its technical and operational objectives. */ + @Rationale { + text = "The primary responsibility of the agency is to successfully execute the missions it is tasked with, thereby fulfilling its national mandate."; + } + } + + requirement def <'SHN-N002'> AstronautSafety :> StakeholderNeed { + doc /* The mission shall ensure the safety and survival of the astronauts throughout all phases. */ + @Rationale { + text = "The agency has a fundamental duty of care for its personnel, and the success of the human spaceflight program depends on ensuring crew safety."; + } + } + + requirement def <'SHN-N003'> ProgrammaticFunding :> StakeholderNeed { + doc /* The mission's execution and public profile shall be managed to maintain continued public and political support and funding. */ + @Rationale { + text = "The Apollo program's existence is contingent on a massive financial commitment, which requires sustained political and public approval."; + } + } + + requirement def <'SHN-N004'> InternationalPrestige :> StakeholderNeed { + doc /* The mission shall demonstrate technological superiority and achieve its primary objectives before any competing nation. */ + @Rationale { + text = "A core driver of the Apollo program was to win the Space Race, a key element of the Cold War geopolitical landscape."; + } + } + + requirement def <'SHN-N005'> ScientificReturn :> StakeholderNeed { + doc /* The mission shall yield significant scientific data, primarily through the return of lunar samples. */ + @Rationale { + text = "Beyond the political goals, a key justification for the mission is the unique opportunity for scientific discovery."; + } + } + + requirement def <'SHN-N006'> PlanetaryProtection :> StakeholderNeed { + doc /* The mission shall prevent the contamination of Earth's biosphere by potential extraterrestrial life forms. */ + @Rationale { + text = "As a matter of public safety and scientific integrity, the agency must ensure that no harm comes from introducing unsterilized materials to Earth."; + } + } + + requirement def <'SHN-N007'> CrewSurvival :> StakeholderNeed { + doc /* The mission systems and procedures shall ensure the crew can survive all mission phases. */ + @Rationale { + text = "The most fundamental need of any human participant in a high-risk endeavor is to survive the experience."; + } + } + + requirement def <'SHN-N008'> ProceduralSuccess :> StakeholderNeed { + doc /* The mission shall provide the tools, training, and systems necessary for the successful execution of all assigned procedures. */ + @Rationale { + text = "The crew's professional responsibility and the mission's success depend on their ability to perform their tasks correctly."; + } + } + + requirement def <'SHN-N009'> PerformanceUnderPressure :> StakeholderNeed { + doc /* The mission environment and crew selection shall enable the management of extreme stress and pressure to ensure peak performance. */ + @Rationale { + text = "The psychological demands of a lunar mission are extreme; the crew's ability to cope is critical to success and safety."; + } + } + + requirement def <'SHN-N010'> TrainingFidelity :> StakeholderNeed { + doc /* The mission training program shall adequately prepare the crew for all nominal and contingency scenarios. */ + @Rationale { + text = "High-fidelity training is the primary tool for mitigating risks and ensuring the crew can respond correctly to any situation."; + } + } + + requirement def <'SHN-N011'> EnvironmentalHazardProtection :> StakeholderNeed { + doc /* The mission systems shall protect the crew from the known and unknown hazards of the lunar environment. */ + @Rationale { + text = "Hazards such as abrasive dust and unstable ground pose a direct threat to the crew and equipment on the lunar surface."; + } + } + + requirement def <'SHN-N012'> RealtimeProblemSolving :> StakeholderNeed { + doc /* The mission systems shall provide the necessary data and communication links to enable real-time problem solving from the ground. */ + @Rationale { + text = "Unforeseen anomalies are expected, and Mission Control's ability to analyze and solve them in real-time is a critical safety function."; + } + } + + requirement def <'SHN-N013'> DataAccuracy :> StakeholderNeed { + doc /* The mission shall provide accurate and reliable telemetry to support critical ground-based decision making. */ + @Rationale { + text = "The safety of the crew and success of the mission depend on ground controllers making decisions based on correct data."; + } + } + + requirement def <'SHN-N014'> ContinuousSupport :> StakeholderNeed { + doc /* The mission shall enable continuous communication to provide uninterrupted support to the flight crew. */ + @Rationale { + text = "The crew in space relies on the ground team for information, calculations, and support that they cannot manage alone."; + } + } + + requirement def <'SHN-N015'> OperationalCoordination :> StakeholderNeed { + doc /* The mission shall be executed with a high degree of coordination between all flight and ground control teams. */ + @Rationale { + text = "A complex mission requires flawless teamwork and communication across multiple specialized teams to function correctly."; + } + } + + requirement def <'SHN-N016'> LunarModulePerformance :> StakeholderNeed { + doc /* The Lunar Module vehicle shall perform all its functions successfully, including landing, life support, and ascent. */ + @Rationale { + text = "As the manufacturer, the company's primary interest is the successful and reliable performance of its product."; + } + } + + requirement def <'SHN-N017'> ProgrammaticAdherence :> StakeholderNeed { + doc /* The development and delivery of the Lunar Module shall adhere to the programmatic schedule and budget. */ + @Rationale { + text = "Meeting contractual obligations regarding schedule and budget is a primary business need for any contractor."; + } + } + + requirement def <'SHN-N018'> ReputationalSuccess :> StakeholderNeed { + doc /* The success of the Lunar Module shall enhance the company's reputation as a leading aerospace contractor. */ + @Rationale { + text = "A successful high-profile mission provides immense reputational value and secures opportunities for future contracts."; + } + } + + requirement def <'SHN-N019'> NationalPrestige :> StakeholderNeed { + doc /* The mission shall achieve its goal of a crewed lunar landing to demonstrate national technological supremacy. */ + @Rationale { + text = "The mission was a central element of the Cold War Space Race, and achieving the landing was a primary geopolitical objective."; + } + } + + requirement def <'SHN-N020'> PublicConfidence :> StakeholderNeed { + doc /* The mission shall be conducted successfully and safely to bolster public confidence and morale. */ + @Rationale { + text = "A successful mission serves as a unifying national event and a demonstration of the government's capabilities."; + } + } + + requirement def <'SHN-N021'> InvestmentJustification :> StakeholderNeed { + doc /* The mission shall produce sufficient scientific and symbolic returns to justify the significant national financial investment. */ + @Rationale { + text = "The high cost of the program necessitates tangible results, such as scientific knowledge and national prestige, to be considered a worthwhile expenditure."; + } + } + + requirement def <'SHN-N022'> NationalSecurityDemonstration :> StakeholderNeed { + doc /* The mission shall demonstrate advanced technological capabilities relevant to national security. */ + @Rationale { + text = "The capabilities required for a lunar mission (e.g., large rockets, global tracking, precision guidance) are inherently linked to national security interests."; + } + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/StakeholderPackage.sysml b/language/src/test/resources/Apollo_11/StakeholderPackage.sysml new file mode 100644 index 00000000..280e4c5b --- /dev/null +++ b/language/src/test/resources/Apollo_11/StakeholderPackage.sysml @@ -0,0 +1,225 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package StakeholderPackage { + + private import CoSMAPackage::*; + private import AstronautsPackage::*; + private import StakeholderNeedsPackage::*; + + part def GovernmentAgency :> Stakeholder; + part def AerospaceCompany :> Stakeholder; + part def MissionControlPersonnel :> Stakeholder; + part def ScientificCommunity :> Stakeholder; + part def Public :> Stakeholder; + part def Media :> Stakeholder; + part def ForeignNation :> Stakeholder; + + part NASA : GovernmentAgency { + :> influenceLevel = StakeholderInfluenceLevel::high; + :> influenceKind = StakeholderInfluenceKind::direct; + item concern1 : Concern { + doc /* Mission Success (technical & operational) */ + } :> concerns; + item concern2 : Concern { + doc /* Astronaut Safety */ + } :> concerns; + item concern3 : Concern { + doc /* Maintaining Public & Political Funding */ + } :> concerns; + item concern4 : Concern { + doc /* International Prestige (Cold War superiority) */ + } :> concerns; + item concern5 : Concern { + doc /* Scientific Return from Lunar Samples */ + } :> concerns; + item concern6 : Concern { + doc /* Preventing Back Contamination (Quarantine) */ + } :> concerns; + requirement missionSuccess:MissionSuccess :> needs; + requirement astronautSafety:AstronautSafety :> needs; + requirement programmaticFunding:ProgrammaticFunding :> needs; + requirement internationalPrestige:InternationalPrestige :> needs; + requirement scientificReturn:ScientificReturn :> needs; + requirement planetaryProtection:PlanetaryProtection :> needs; + } + + part Apollo11Crew : Stakeholder { + :> influenceLevel = StakeholderInfluenceLevel::high; + :> influenceKind = StakeholderInfluenceKind::direct; + item concern1 : Concern { + doc /* Personal Survival */ + } :> concerns; + item concern2 : Concern { + doc /* Successful Execution of Mission Procedures */ + } :> concerns; + item concern3 : Concern { + doc /* Managing Stress & Performance Pressure */ + } :> concerns; + item concern4 : Concern { + doc /* Adeq :> concerns;uate Training & Preparation */ + } :> concerns; + item concern5 : Concern { + doc /* Unknowns of Lunar Environment (e.g., dust, regolith stability) */ + } :> concerns; + requirement crewSurvival:CrewSurvival :> needs; + requirement proceduralSuccess:ProceduralSuccess :> needs; + requirement performanceUnderPressure:PerformanceUnderPressure :> needs; + requirement trainingFidelity:TrainingFidelity :> needs; + requirement environmentalHazardProtection:EnvironmentalHazardProtection :> needs; + } + + part MissionControl : MissionControlPersonnel { + :> influenceLevel = StakeholderInfluenceLevel::high; + :> influenceKind = StakeholderInfluenceKind::direct; + item concern1 : Concern { + doc /* Real-time Problem Solving (e.g., 1202/1201 alarms) */ + } :> concerns; + item concern2 : Concern { + doc /* Accurate Data Analysis & Decision Making */ + } :> concerns; + item concern3 : Concern { + doc /* Continuous Crew Support & Communication */ + } :> concerns; + item concern4 : Concern { + doc /* Operational Flawlessness & Coordination */ + } :> concerns; + requirement realtimeProblemSolving:RealtimeProblemSolving :> needs; + requirement dataAccuracy:DataAccuracy :> needs; + requirement continuousSupport:ContinuousSupport :> needs; + requirement operationalCoordination:OperationalCoordination :> needs; + } + + part Grumman : AerospaceCompany { + :> influenceLevel = StakeholderInfluenceLevel::medium; + :> influenceKind = StakeholderInfluenceKind::direct; + item concern1 : Concern { + doc /* Successful Lunar Module Performance */ + } :> concerns; + item concern2 : Concern { + doc /* Meeting Schedule & Budget */ + } :> concerns; + item concern3 : Concern { + doc /* Company Reputation */ + } :> concerns; + requirement lunarModulePerformance:LunarModulePerformance :> needs; + requirement programmaticAdherence:ProgrammaticAdherence :> needs; + requirement reputationalSuccess:ReputationalSuccess :> needs; + } + + part USGovernment : GovernmentAgency { + :> influenceLevel = StakeholderInfluenceLevel::high; + :> influenceKind = StakeholderInfluenceKind::direct; + item concern1 : Concern { + doc /* National Prestige (Space Race victory) */ + } :> concerns; + item concern2 : Concern { + doc /* Public Confidence & Morale */ + } :> concerns; + item concern3 : Concern { + doc /* Justifying Financial Investment */ + } :> concerns; + item concern4 : Concern { + doc /* National Security */ + } :> concerns; + requirement nationalPrestige:NationalPrestige :> needs; + requirement publicConfidence:PublicConfidence :> needs; + requirement investmentJustification:InvestmentJustification :> needs; + requirement nationalSecurityDemonstration:NationalSecurityDemonstration :> needs; + } + + part SovietUnion : ForeignNation { + :> influenceLevel = StakeholderInfluenceLevel::low; + :> influenceKind = StakeholderInfluenceKind::indirect; + item concern1 : Concern { + doc /* Loss of Prestige (being beaten to the Moon) */ + } :> concerns; + item concern2 : Concern { + doc /* Assessing US Technological Capabilities */ + } :> concerns; + } + + part Geologists : ScientificCommunity { + :> influenceLevel = StakeholderInfluenceLevel::low; + :> influenceKind = StakeholderInfluenceKind::indirect; + item concern1 : Concern { + doc /* Valuable Lunar Sample Collection */ + } :> concerns; + item concern2 : Concern { + doc /* Deployment of Scientific Instruments (e.g., seismometer) */ + } :> concerns; + item concern3 : Concern { + doc /* Integrity & Non-contamination of Samples */ + } :> concerns; + item concern4 : Concern { + doc /* Access to Data & Samples */ + } :> concerns; + } + + part AmericanPublic : Public { + :> influenceLevel = StakeholderInfluenceLevel::medium; + :> influenceKind = StakeholderInfluenceKind::indirect; + item concern1 : Concern { + doc /* National Pride & Inspiration */ + } :> concerns; + item concern2 : Concern { + doc /* Astronaut Safety */ + } :> concerns; + item concern3 : Concern { + doc /* Cost vs. Other Priorities (minority view) */ + } :> concerns; + } + + part GlobalPublic : Public { + :> influenceLevel = StakeholderInfluenceLevel::low; + :> influenceKind = StakeholderInfluenceKind::indirect; + item concern1 : Concern { + doc /* Shared Human Achievement */ + } :> concerns; + item concern2 : Concern { + doc /* Peaceful Use of Space */ + } :> concerns; + } + + part NewsMedia : Media { + :> influenceLevel = StakeholderInfluenceLevel::medium; + :> influenceKind = StakeholderInfluenceKind::indirect; + item concern1 : Concern { + doc /* Accurate & Timely Reporting */ + } :> concerns; + item concern2 : Concern { + doc /* Access to Information & Officials */ + } :> concerns; + item concern3 : Concern { + doc /* Compelling Narrative */ + } :> concerns; + } + + part AstronautFamilies : Stakeholder { + :> influenceLevel = StakeholderInfluenceLevel::low; + :> influenceKind = StakeholderInfluenceKind::indirect; + item concern1 : Concern { + doc /* Safety of Loved Ones */ + } :> concerns; + item concern2 : Concern { + doc /* Privacy from Public Scrutiny */ + } :> concerns; + } + + part FutureGenerations : Stakeholder { + :> influenceLevel = StakeholderInfluenceLevel::low; + :> influenceKind = StakeholderInfluenceKind::indirect; + item concern1 : Concern { + doc /* Legacy of Exploration) */ + } :> concerns; + item concern2 : Concern { + doc /* Preservation of Knowledge */ + } :> concerns; + } + + +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/SystemPackage.sysml b/language/src/test/resources/Apollo_11/SystemPackage.sysml new file mode 100644 index 00000000..5c410472 --- /dev/null +++ b/language/src/test/resources/Apollo_11/SystemPackage.sysml @@ -0,0 +1,28 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package SystemPackage { + + private import TechnicalComponentsPackage::*; + private import TechnicalIndividualsPackage::*; + private import CoSMAPackage::*; + private import TechnicalPortsPackage::*; + + part def Apollo11MissionSystem :> SystemOfSystems { + individual part launchVehicle : 'SA-506' :> constituentSystems; + + part spacecraft : ApolloSpacecraft :> constituentSystems { + individual part csm : 'CSM-107' :>> commandServiceModule; + individual part lm: 'LM-5' :>> lunarModule; + } + + part spaceSuits[2] : ExtravehicularMobilityUnit :> constituentSystems; + + interface lvToPayload : LVPayloadInterface connect + launchVehicle.instrumentUnit.payloadInterfacePort to spacecraft.spacecraftLMAdapter.launchVehicleInterfacePort; + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/SystemSpecificationPackage.sysml b/language/src/test/resources/Apollo_11/SystemSpecificationPackage.sysml new file mode 100644 index 00000000..28abf049 --- /dev/null +++ b/language/src/test/resources/Apollo_11/SystemSpecificationPackage.sysml @@ -0,0 +1,247 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package SystemSpecificationPackage { + + private import TechnicalRequirementsPackage::**; + private import SystemPackage::*; + + requirement apollo11MissionSystemSpecification { + doc /* Apollo 11 System requirements group */ + subject apollo11MissionSystem : Apollo11MissionSystem; + + requirement 'clr-R001' : SICEngineConfiguration; + requirement 'clr-R002' : SICPropellantCompatibility; + requirement 'clr-R003' : SICGimbalCapability; + requirement 'clr-R026' : SICSeparationSystem; + requirement 'clr-R004' : SIIEngineConfiguration; + requirement 'clr-R005' : SIIPropellantType; + requirement 'clr-R027' : SIIStructuralIntegrity; + requirement 'clr-R006' : SIVBEngineConfiguration; + requirement 'clr-R007' : SIVBRestartCapability; + requirement 'clr-R028' : SIVBAttitudeControlSystem; + requirement 'clr-R008' : IUGuidanceComputer; + requirement 'clr-R009' : IUCommandAuthority; + requirement 'clr-R029' : IUTelemetrySystem; + requirement 'clr-R010' : LESPropulsionType; + requirement 'clr-R011' : LESJettisonCapability; + requirement 'clr-R012' : CMHabitableVolume; + requirement 'clr-R013' : CMHeatShield; + requirement 'clr-R014' : CMParachuteSystem; + requirement 'clr-R030' : CMDockingMechanism; + requirement 'clr-R015' : SMMainPropulsion; + requirement 'clr-R016' : SMAttitudeControl; + requirement 'clr-R017' : SMPowerGeneration; + requirement 'clr-R031' : SMThermalControlSystem; + requirement 'clr-R018' : LMDSThrottleableEngine; + requirement 'clr-R019' : LMDSLandingGear; + requirement 'clr-R032' : LMDSLaunchPlatform; + requirement 'clr-R020' : LMASAscentEngine; + requirement 'clr-R021' : LMASCrewCabin; + requirement 'clr-R033' : LMASRendezvousRadar; + requirement 'clr-R022' : PSAPressureContainment; + requirement 'clr-R023' : PSAMobility; + requirement 'clr-R034' : PSAHelmetVisibility; + requirement 'clr-R024' : PLSSOxygenSupply; + requirement 'clr-R025' : PLSSContaminantRemoval; + requirement 'clr-R035' : PLSSCoolingSystem; + requirement 'clr-R036' : StagingInterfaceLoadTransfer; + requirement 'clr-R037' : StagingInterfaceCleanSeparation; + requirement 'clr-R038' : GuidanceInterfaceCommandIntegrity; + requirement 'clr-R039' : GuidanceInterfaceTelemetryLatency; + requirement 'clr-R040' : CSMInterfacePowerTransfer; + requirement 'clr-R041' : CSMInterfaceLifeSupportIntegrity; + requirement 'clr-R042' : DockingInterfaceStructuralRigidity; + requirement 'clr-R043' : DockingInterfacePressurizedSeal; + requirement 'clr-R044' : LMStagingInterfaceSeparation; + requirement 'clr-R045' : EVAInterfaceSecureConnection; + requirement 'clr-R046' : LVPayloadInterfaceStructural; + requirement 'clr-R047' : SLALMDeployment; + requirement 'clr-R048' : LESInterfaceStructuralIntegrity; + requirement 'clr-R049' : LESInterfaceCommandReliability; + requirement 'clr-R050' : LMDSVelocityLimits; + requirement 'clr-R051' : CabinEnvironmentalControlRequirement; + requirement 'clr-R052' : GNCGuidancePrecision; + requirement 'clr-R053' : RCSControlStability; + requirement 'clr-R054' : LMDSRadarPrecision; + requirement 'clr-R056' : SPSIgnitionReliability; + requirement 'clr-R057' : DPSThrottlingRange; + requirement 'clr-R058' : LMASBurnDuration; + requirement 'clr-R060' : CMHeatShieldThermalPerf; + requirement 'clr-R067' : CommVideoBandwidth; + requirement 'clr-R068' : EMUPressureContainment; + requirement 'clr-R069' : EASEPOperationalDuration; + requirement 'clr-R071' : FlightSoftwareDefectRate; + requirement 'clr-R073' : MaterialVacuumResistance; + requirement 'clr-R075' : ImageResolutionStandard; + requirement 'clr-R076' : WasteStorageVolume; + requirement 'clr-R077' : VHFAudioBandwidth; + requirement 'clr-R078' : SystemRedundancyMapping; + requirement 'clr-R079' : MedicalKitSpecification; + requirement 'clr-R080' : GroundArchivalProtocol; + requirement 'clr-R081' : CrewSeatLoadFactor; + requirement 'clr-R082' : LaunchAbortThresholds; + requirement 'clr-R083' : SeparationTimerPrecision; + requirement 'clr-R084' : CabinPressureHold; + requirement 'clr-R085' : TimingSynchError; + requirement 'clr-R086' : EngineStartLatency; + requirement 'clr-R087' : StagingShockLimit; + requirement 'clr-R088' : CutoffDeltaVError; + requirement 'clr-R089' : CockpitDisplayRefresh; + requirement 'clr-R090' : TelemetrySamplingRate; + requirement 'clr-R091' : PostTliSeparationVelocity; + requirement 'clr-R092' : SlaSeparationVelocity; + requirement 'clr-R093' : TranspositionManeuverRate; + requirement 'clr-R094' : SextantAngularAccuracy; + requirement 'clr-R095' : StateVectorIntegrationLatency; + requirement 'clr-R096' : CommandTurnaroundLatency; + requirement 'clr-R097' : GroundStationSensitivity; + requirement 'clr-R098' : RelayNetworkBitErrorRate; + requirement 'clr-R099' : TimelineDriftAlert; + requirement 'clr-R100' : SleepAcousticLimit; + requirement 'clr-R101' : TargetOrbitPerigee; + requirement 'clr-R102' : HatchClearanceDimensions; + requirement 'clr-R103' : LmComputerAlignmentTime; + requirement 'clr-R104' : DockingLatchTorqueThreshold; + requirement 'clr-R105' : UndockingSeparationVelocity; + requirement 'clr-R106' : DskyDisplayBrightness; + requirement 'clr-R107' : LandingRadarLockTime; + requirement 'clr-R108' : PostLandingSafeTime; + requirement 'clr-R109' : LmCabinIntegrityLeakRate; + requirement 'clr-R110' : SymbolicMountRigidity; + requirement 'clr-R111' : SampleToolMechanicalAdvantage; + requirement 'clr-R112' : EasepThermalInsulation; + requirement 'clr-R113' : EvaCommunicationRange; + requirement 'clr-R114' : SurfaceTimelineSync; + requirement 'clr-R115' : LmAscentDeltaVMinimum; + requirement 'clr-R116' : RendezvousOrbitTarget; + requirement 'clr-R117' : ReentryFlightPathAngle; + + satisfy 'clr-R001' by apollo11MissionSystem.launchVehicle.stage1; + satisfy 'clr-R002' by apollo11MissionSystem.launchVehicle.stage1; + satisfy 'clr-R003' by apollo11MissionSystem.launchVehicle.stage1; + satisfy 'clr-R004' by apollo11MissionSystem.launchVehicle.stage2; + satisfy 'clr-R005' by apollo11MissionSystem.launchVehicle.stage2; + satisfy 'clr-R006' by apollo11MissionSystem.launchVehicle.stage3; + satisfy 'clr-R007' by apollo11MissionSystem.launchVehicle.stage3; + satisfy 'clr-R008' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R009' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R010' by apollo11MissionSystem.spacecraft.launchEscapeSystem; + satisfy 'clr-R011' by apollo11MissionSystem.spacecraft.launchEscapeSystem; + satisfy 'clr-R012' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R013' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R014' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R015' by apollo11MissionSystem.spacecraft.csm.serviceModule; + satisfy 'clr-R016' by apollo11MissionSystem.spacecraft.csm.serviceModule; + satisfy 'clr-R017' by apollo11MissionSystem.spacecraft.csm.serviceModule; + satisfy 'clr-R018' by apollo11MissionSystem.spacecraft.lm.lunarModuleDescentStage; + satisfy 'clr-R019' by apollo11MissionSystem.spacecraft.lm.lunarModuleDescentStage; + satisfy 'clr-R050' by apollo11MissionSystem.spacecraft.lm.lunarModuleDescentStage; + satisfy 'clr-R020' by apollo11MissionSystem.spacecraft.lm.lunarModuleAscentStage; + satisfy 'clr-R021' by apollo11MissionSystem.spacecraft.lm.lunarModuleAscentStage; + satisfy 'clr-R022' by apollo11MissionSystem.spaceSuits.psa; + satisfy 'clr-R023' by apollo11MissionSystem.spaceSuits.psa; + satisfy 'clr-R024' by apollo11MissionSystem.spaceSuits.plss; + satisfy 'clr-R025' by apollo11MissionSystem.spaceSuits.plss; + satisfy 'clr-R026' by apollo11MissionSystem.launchVehicle.stage1; + satisfy 'clr-R027' by apollo11MissionSystem.launchVehicle.stage2; + satisfy 'clr-R028' by apollo11MissionSystem.launchVehicle.stage3; + satisfy 'clr-R029' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R030' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R031' by apollo11MissionSystem.spacecraft.csm.serviceModule; + satisfy 'clr-R032' by apollo11MissionSystem.spacecraft.lm.lunarModuleDescentStage; + satisfy 'clr-R033' by apollo11MissionSystem.spacecraft.lm.lunarModuleAscentStage; + satisfy 'clr-R034' by apollo11MissionSystem.spaceSuits.psa; + satisfy 'clr-R035' by apollo11MissionSystem.spaceSuits.plss; + satisfy 'clr-R036' by apollo11MissionSystem.launchVehicle.stage1ToStage2; + satisfy 'clr-R036' by apollo11MissionSystem.launchVehicle.stage2ToStage3; + satisfy 'clr-R037' by apollo11MissionSystem.launchVehicle.stage1ToStage2; + satisfy 'clr-R037' by apollo11MissionSystem.launchVehicle.stage2ToStage3; + satisfy 'clr-R038' by apollo11MissionSystem.launchVehicle.iuToStage3; + satisfy 'clr-R039' by apollo11MissionSystem.launchVehicle.iuToStage3; + satisfy 'clr-R040' by apollo11MissionSystem.spacecraft.csm.cmSMUmbilical; + satisfy 'clr-R041' by apollo11MissionSystem.spacecraft.csm.cmSMUmbilical; + satisfy 'clr-R042' by apollo11MissionSystem.spacecraft.cmLMDocking; + satisfy 'clr-R043' by apollo11MissionSystem.spacecraft.cmLMDocking; + satisfy 'clr-R044' by apollo11MissionSystem.spacecraft.lm.lmInterstage; + satisfy 'clr-R045' by apollo11MissionSystem.spaceSuits.suitToPLSSUmbilical; + satisfy 'clr-R046' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R046' by apollo11MissionSystem.spacecraft.spacecraftLMAdapter; + satisfy 'clr-R047' by apollo11MissionSystem.spacecraft.spacecraftLMAdapter; + satisfy 'clr-R048' by apollo11MissionSystem.spacecraft.lesConnection; + satisfy 'clr-R049' by apollo11MissionSystem.spacecraft.lesConnection; + satisfy 'clr-R050' by apollo11MissionSystem.spacecraft.lm.lunarModuleDescentStage; + + satisfy 'clr-R086' by apollo11MissionSystem.launchVehicle.stage1; + satisfy 'clr-R087' by apollo11MissionSystem.launchVehicle.stage2; + satisfy 'clr-R088' by apollo11MissionSystem.launchVehicle.stage3; + satisfy 'clr-R091' by apollo11MissionSystem.launchVehicle.stage3; + + satisfy 'clr-R008' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R052' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R071' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R082' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R085' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R090' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R094' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R095' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R114' by apollo11MissionSystem.launchVehicle.instrumentUnit; + + satisfy 'clr-R051' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R060' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R075' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R076' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R079' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R081' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R084' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R089' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R099' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R100' by apollo11MissionSystem.spacecraft.csm.commandModule; + satisfy 'clr-R117' by apollo11MissionSystem.spacecraft.csm.commandModule; + + satisfy 'clr-R053' by apollo11MissionSystem.spacecraft.csm.serviceModule; + satisfy 'clr-R056' by apollo11MissionSystem.spacecraft.csm.serviceModule; + satisfy 'clr-R073' by apollo11MissionSystem.spacecraft.csm.serviceModule; + satisfy 'clr-R078' by apollo11MissionSystem.spacecraft.csm.serviceModule; + satisfy 'clr-R093' by apollo11MissionSystem.spacecraft.csm.serviceModule; + satisfy 'clr-R101' by apollo11MissionSystem.spacecraft.csm.serviceModule; + + satisfy 'clr-R054' by apollo11MissionSystem.spacecraft.lm.lunarModuleDescentStage; + satisfy 'clr-R057' by apollo11MissionSystem.spacecraft.lm.lunarModuleDescentStage; + satisfy 'clr-R069' by apollo11MissionSystem.spacecraft.lm.lunarModuleDescentStage; + satisfy 'clr-R107' by apollo11MissionSystem.spacecraft.lm.lunarModuleDescentStage; + satisfy 'clr-R108' by apollo11MissionSystem.spacecraft.lm.lunarModuleDescentStage; + satisfy 'clr-R112' by apollo11MissionSystem.spacecraft.lm.lunarModuleDescentStage; + + satisfy 'clr-R058' by apollo11MissionSystem.spacecraft.lm.lunarModuleAscentStage; + satisfy 'clr-R067' by apollo11MissionSystem.spacecraft.lm.lunarModuleAscentStage; + satisfy 'clr-R102' by apollo11MissionSystem.spacecraft.lm.lunarModuleAscentStage; + satisfy 'clr-R103' by apollo11MissionSystem.spacecraft.lm.lunarModuleAscentStage; + satisfy 'clr-R106' by apollo11MissionSystem.spacecraft.lm.lunarModuleAscentStage; + satisfy 'clr-R109' by apollo11MissionSystem.spacecraft.lm.lunarModuleAscentStage; + satisfy 'clr-R115' by apollo11MissionSystem.spacecraft.lm.lunarModuleAscentStage; + satisfy 'clr-R116' by apollo11MissionSystem.spacecraft.lm.lunarModuleAscentStage; + + satisfy 'clr-R068' by apollo11MissionSystem.spaceSuits.psa; + satisfy 'clr-R110' by apollo11MissionSystem.spaceSuits.psa; + satisfy 'clr-R111' by apollo11MissionSystem.spaceSuits.psa; + satisfy 'clr-R113' by apollo11MissionSystem.spaceSuits.psa; + satisfy 'clr-R024' by apollo11MissionSystem.spaceSuits.plss; + satisfy 'clr-R025' by apollo11MissionSystem.spaceSuits.plss; + satisfy 'clr-R035' by apollo11MissionSystem.spaceSuits.plss; + + + satisfy 'clr-R113' by apollo11MissionSystem.spacecraft.cmLMDocking; + satisfy 'clr-R092' by apollo11MissionSystem.spacecraft.spacecraftLMAdapter; + satisfy 'clr-R083' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R096' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R097' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R098' by apollo11MissionSystem.launchVehicle.instrumentUnit; + satisfy 'clr-R080' by apollo11MissionSystem.launchVehicle.instrumentUnit; + + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/TechnicalComponentsPackage.sysml b/language/src/test/resources/Apollo_11/TechnicalComponentsPackage.sysml new file mode 100644 index 00000000..872c17db --- /dev/null +++ b/language/src/test/resources/Apollo_11/TechnicalComponentsPackage.sysml @@ -0,0 +1,253 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package TechnicalComponentsPackage { + + private import CoSMAPackage::*; + private import CoSMAQuantitiesAndUnitsPackage::*; + private import ShapeItems::*; + private import SI::*; + private import LogicalComponentsPackage::*; + private import TechnicalPortsPackage::*; + + abstract part def PropelledSpacecraft :> FuelledComponent { + attribute maxThrust :> ISQ::force; + attribute specificImpulse :> CoSMAQuantitiesAndUnitsPackage::specificImpulse; + } + + abstract part def FuelledComponent :> HardwareComponent { + attribute propellantMass :> ISQ::mass; + attribute dryMass :> ISQ::mass; + attribute :>> mass = dryMass + propellantMass; + } + + abstract part def RocketEngine :> HardwareComponent { + doc /* An abstract representation of a rocket engine, defining its core performance attributes. */ + attribute thrustVacuum :> ISQ::force; + attribute specificImpulseVacuum :> CoSMAQuantitiesAndUnitsPackage::specificImpulse; + } + + abstract part def RocketStage :> FuelledComponent { + doc /* An abstract representation of a single stage of a rocket, containing engines and propellant. */ + part engines[1..*] ordered : RocketEngine; + } + + abstract part def MultistageRocket :> System { + doc /* An abstract representation of a rocket composed of multiple stages. */ + part stages[1..*] ordered : RocketStage; + } + + part def SaturnVInstrumentUnit :> HardwareComponent, PowerConsumer { + doc /* The 'brain' of the Saturn V, providing guidance and control during ascent. */ + attribute dryMass :> ISQ::mass = 1950 [kg]; + attribute :>> failureRate = 5E-6 [1/h]; + attribute :>> powerLoad = 450 [W]; + + port stageControlPort : ControlPort; + port payloadInterfacePort : PayloadInterfacePort; + } + + part def ApolloLaunchEscapeSystem :> HardwareComponent, PowerConsumer { + doc /* A solid-fueled rocket tower mounted atop the Command Module to pull it away from the launch vehicle in an emergency. */ + attribute :>> mass = 4170 [kg]; + attribute :>> powerLoad = 50 [W]; + attribute :>> failureRate = 1E-7 [1/h]; + + port cmInterfacePort : ~LaunchEscapeSystemPort; + } + + part def ApolloCommandModule :> HardwareComponent, PowerConsumer { + doc /* The conical crew cabin, control center, and reentry vehicle. */ + attribute :>> mass = 5840 [kg]; + attribute :>> powerLoad = 2000 [W]; + attribute :>> failureRate = 1.5E-6 [1/h]; + + port umbilicalPort : ~UmbilicalPort; + port dockingPort : DockingPort; + port lesInterfacePort : LaunchEscapeSystemPort; + } + + part def ApolloServiceModule :> PropelledSpacecraft, PowerConsumer, PowerProvider { + doc /* The primary support module for the Command Module, containing the main engine, power systems, and consumables. */ + attribute :>> dryMass = 6160 [kg]; + attribute :>> propellantMass = 18440 [kg]; + attribute :>> maxThrust = 91 ['kN']; + attribute :>> specificImpulse = 314 ['s']; + attribute :>> powerGenerated = 3000 [W]; + attribute :>> powerLoad = 500 [W]; + attribute :>> failureRate = 2.0E-6 [1/h]; + + port umbilicalPort : UmbilicalPort; + port launchVehicleInterfacePort : ~StagingPort; + } + + part def ApolloCommandServiceModule :> HardwareComponent, PowerConsumer, PowerProvider { + doc /* The combined Command and Service Module (CSM), which functions as the primary spacecraft for lunar transit and Earth return. */ + part commandModule : ApolloCommandModule; + part serviceModule : ApolloServiceModule; + + attribute :>> powerGenerated = serviceModule.powerGenerated; + attribute :>> powerLoad = commandModule.powerLoad + serviceModule.powerLoad; + + interface cmSMUmbilical : CSMInterface connect serviceModule.umbilicalPort to commandModule.umbilicalPort; + } + + part def ApolloLunarModule :> HardwareComponent, PowerConsumer, PowerProvider { + doc /* The two-stage vehicle that performed the lunar landing and ascent. */ + + part lunarModuleDescentStage : LunarModuleDescentStage; + part lunarModuleAscentStage : LunarModuleAscentStage; + + attribute :>> powerGenerated = lunarModuleDescentStage.powerGenerated + lunarModuleAscentStage.powerGenerated; + attribute :>> powerLoad = lunarModuleDescentStage.powerLoad + lunarModuleAscentStage.powerLoad; + + interface lmInterstage : LMStagingInterface connect lunarModuleDescentStage.upperStagePort to lunarModuleAscentStage.lowerStagePort; + } + + part def LunarModuleDescentStage :> PropelledSpacecraft, PowerConsumer, PowerProvider { + doc /* The lower portion of the Lunar Module, used for the powered landing and as a launch platform for the ascent stage. */ + attribute :>> dryMass = 2100 [kg]; + attribute :>> propellantMass = 8250 [kg]; + attribute :>> maxThrust = 45 ['kN']; + attribute :>> specificImpulse = 305 ['s']; + attribute :>> powerGenerated = 1500 [W]; + attribute :>> powerLoad = 1000 [W]; + attribute :>> failureRate = 3.0E-6 [1/h]; + + port upperStagePort : LMStagingPort; + } + + part def LunarModuleAscentStage :> PropelledSpacecraft, PowerConsumer, PowerProvider { + doc /* The upper portion of the Lunar Module, which served as the crew cabin and ascent vehicle to leave the lunar surface. */ + attribute :>> dryMass = 2220 [kg]; + attribute :>> propellantMass = 2370 [kg]; + attribute :>> maxThrust = 16 ['kN']; + attribute :>> specificImpulse = 311 ['s']; + attribute :>> powerGenerated = 1500 [W]; + attribute :>> powerLoad = 1200 [W]; + attribute :>> failureRate = 2.5E-6 [1/h]; + + port lowerStagePort : ~LMStagingPort; + port dockingPort : DockingPort; + } + + part def ApolloSpacecraftLMAdapter :> HardwareComponent { + doc /* A conical structure that housed the Lunar Module during launch and connected the Apollo spacecraft to the Saturn V. */ + attribute :>> mass = 1840 [kg]; + + port launchVehicleInterfacePort : ~PayloadInterfacePort; + port csmInterfacePort : StagingPort; + } + + part def ApolloSpacecraft :> System, Spacecraft { + doc /* The complete payload stack for the Apollo mission, including the CSM, LM, SLA, and Launch Escape System. */ + part launchEscapeSystem : ApolloLaunchEscapeSystem; + part commandServiceModule : ApolloCommandServiceModule; + part lunarModule : ApolloLunarModule; + part spacecraftLMAdapter : ApolloSpacecraftLMAdapter; + + interface cmLMDocking : DockingInterface connect commandServiceModule.commandModule.dockingPort to lunarModule.lunarModuleAscentStage.dockingPort; + + interface : StagingInterface connect spacecraftLMAdapter.csmInterfacePort to commandServiceModule.serviceModule.launchVehicleInterfacePort; + interface lesConnection : LESInterface connect commandServiceModule.commandModule.lesInterfacePort to launchEscapeSystem.cmInterfacePort; + } + + part def SaturnV :> MultistageRocket, LaunchSystem { + doc /* The three-stage, super heavy-lift launch vehicle used to send the Apollo spacecraft to the Moon. */ + attribute height :> ISQ::length = 110.6 [m]; + attribute launchMass :> ISQ::mass = 2970000 [kg]; + attribute payloadToLunarTransferOrbit :> ISQ::mass = 43500 [kg]; + + part stage1 : 'S-IC'; + part stage2 : 'S-II'; + part stage3 : 'S-IVB'; + part instrumentUnit : SaturnVInstrumentUnit; + part :>> stages[3] = (stage1, stage2, stage3); + + interface stage1ToStage2 : StagingInterface connect stage1.upperStagePort to stage2.lowerStagePort; + interface stage2ToStage3 : StagingInterface connect stage2.upperStagePort to stage3.lowerStagePort; + interface iuToStage3 : GuidanceInterface connect instrumentUnit.stageControlPort to stage3.controlPort; + } + + part def 'F-1' :> RocketEngine { + doc /* A single-chamber liquid-propellant rocket engine, the most powerful ever built, used in the S-IC first stage. */ + attribute thrustSeaLevel :> ISQ::force = 6770 ['kN']; + attribute :>> thrustVacuum = 7770 ['kN']; + attribute :>> specificImpulseVacuum = 304 ['s']; + } + + part def 'J-2' :> RocketEngine { + doc /* A liquid-fuel cryogenic rocket engine used in the S-II and S-IVB stages, notable for its restart capability. */ + attribute :>> thrustVacuum = 1033 ['kN']; + attribute :>> specificImpulseVacuum = 421 ['s']; + } + + part def 'S-IVB' :> RocketStage { + doc /* The third stage of the Saturn V, responsible for the final push into Earth orbit and the critical Translunar Injection burn. */ + attribute :>> propellantMass = 109500 [kg]; + attribute :>> dryMass = 13500 [kg]; + + port lowerStagePort : ~StagingPort; + port controlPort : ~ControlPort; + + part engine : 'J-2'; + part :>> engines[1] = (engine); + } + + part def 'S-II' :> RocketStage { + doc /* The second stage of the Saturn V, providing massive thrust in the upper atmosphere and vacuum of space. */ + attribute :>> propellantMass = 443000 [SI::kg]; + attribute :>> dryMass = 36200 [kg]; + + port lowerStagePort : ~StagingPort; + port upperStagePort : StagingPort; + + part engine1 : 'J-2'; + part engine2 : 'J-2'; + part engine3 : 'J-2'; + part engine4 : 'J-2'; + part engine5 : 'J-2'; + part :>> engines[5] = (engine1, engine2, engine3, engine4, engine5); + } + + part def 'S-IC' :> RocketStage { + doc /* The first stage of the Saturn V, providing the initial ~7.7 million pounds of thrust for liftoff. */ + attribute :>> propellantMass = 2077000 [kg]; + attribute :>> dryMass = 137000 [kg]; + + port upperStagePort : StagingPort; + + part engine1 : 'F-1'; + part engine2 : 'F-1'; + part engine3 : 'F-1'; + part engine4 : 'F-1'; + part engine5 : 'F-1'; + part :>> engines[5] = (engine1, engine2, engine3, engine4, engine5); + } + + part def ExtravehicularMobilityUnit :> System, EVASystem { + doc /* The 'A7L' spacesuit, a self-contained personal spacecraft providing life support for lunar EVAs. */ + attribute massOnEarth :> ISQ::mass = 83 [kg]; + attribute nominalOperatingPressure :> ISQ::pressure = 25.5 ['kPa']; + attribute lifeSupportDuration :> ISQ::time = 7 ['h']; + + part psa: PressureSuiteAssembly; + part plss: PortableLifeSupportSystem; + + interface suitToPLSSUmbilical : EVAInterface connect plss.umbilicalPort to psa.umbilicalPort; + } + + part def PressureSuiteAssembly :> HardwareComponent { + doc /* The main suit portion, providing pressure and mobility. */ + port umbilicalPort : ~EVAUmbilicalPort; + } + + part def PortableLifeSupportSystem :> HardwareComponent { + doc /* The 'backpack' containing oxygen, CO2 scrubbers, cooling water, and communications equipment. */ + port umbilicalPort : EVAUmbilicalPort; + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/TechnicalIndividualsPackage.sysml b/language/src/test/resources/Apollo_11/TechnicalIndividualsPackage.sysml new file mode 100644 index 00000000..2a42a6d0 --- /dev/null +++ b/language/src/test/resources/Apollo_11/TechnicalIndividualsPackage.sysml @@ -0,0 +1,215 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package TechnicalIndividualsPackage { + + private import TechnicalComponentsPackage::*; + + // https:>//en.wikipedia.org/wiki/Saturn_V + individual part def 'SA-500F' :> SaturnV { + doc /* Facilities integration. Used to check precise fits and test facilities operation on Pad 39A before a flight model was ready. First stage scrapped, second stage converted to S-II-F/D, third stage on display at Kennedy Space Center. */ + } + individual part def 'SA-500D' :> SaturnV { + doc /* Dynamic testing. Used to evaluate the vehicle's response to vibrations. On display at the U.S. Space & Rocket Center, Huntsville, Alabama. */ + } + individual part def 'S-IC-T' :> SaturnV { + doc /* All Systems Test. First stage used for static test firing at Marshall Space Flight Center. On display at Kennedy Space Center. */ + } + individual part def 'SA-501' :> SaturnV { + doc /* Apollo 4 First uncrewed, all-up test flight. */ + } + individual part def 'SA-502' :> SaturnV { + doc /* Apollo 6. Second uncrewed test flight; J-2 engine problems caused early shutdown of two engines in second stage, and prevented third stage restart. */ + } + individual part def 'SA-503' :> SaturnV { + doc /* Apollo 8. First crewed flight; first trans-lunar injection of Apollo command and service module. */ + } + individual part def 'SA-504' :> SaturnV { + doc /* Apollo 9. Crewed low Earth orbit test of complete Apollo spacecraft with the Lunar Module (LM). */ + } + individual part def 'SA-505' :> SaturnV { + doc /* Apollo 10. Second crewed trans-lunar injection of complete Apollo spacecraft with LM; Only Saturn V launched from Pad 39B. */ + } + individual part def 'SA-506' :> SaturnV { + doc /* Apollo 11. First crewed lunar landing, at Sea of Tranquility. */ + } + individual part def 'SA-507' :> SaturnV { + doc /* Apollo 12. Vehicle was struck twice by lightning shortly after liftoff, but did not suffer serious damage. Made second crewed lunar landing, near Surveyor 3 at Ocean of Storms*/ + } + individual part def 'SA-508' :> SaturnV { + doc /* Apollo 13. Severe pogo oscillations in second stage caused early center engine shutdown; guidance compensated by burning remaining engines longer. Lunar landing mission was aborted by service module failure. */ + } + individual part def 'SA-509' :> SaturnV { + doc /* Apollo 14. Third crewed lunar landing, near Fra Mauro, Apollo 13's intended landing site. */ + } + individual part def 'SA-510' :> SaturnV { + doc /* Apollo 15. Fourth crewed lunar landing, at Hadley-Apennine. First extended Apollo mission, carrying lunar orbital Scientific Instrument Module and Lunar Roving Vehicle. */ + } + individual part def 'SA-511' :> SaturnV { + doc /* Apollo 16. Fifth crewed lunar landing, at Descartes Highlands. */ + } + individual part def 'SA-512' :> SaturnV { + doc /* Apollo 17. Only night launch. Sixth and final crewed lunar landing, at Taurus-Littrow. */ + } + individual part def 'SA-513' :> SaturnV { + doc /* Skylab 1. Uncrewed launch of the Skylab orbital workshop, which replaced the third stage, S-IVB-513, on display at Johnson Space Center. Originally designated for canceled Apollo 18. */ + } + individual part def 'SA-514' :> SaturnV { + doc /* Unused. Originally designated for canceled Apollo 18 or 19; never used. It was proposed for launching an International Skylab. This station would have been serviced by Apollo, Soyuz and later by the Space Shuttle. The first stage (S-IC-14) on display at Johnson Space Center, second and third stage (S-II-14, S-IV-14) on display at Kennedy Space Center. The S-II interstage is located at Parque de las Ciencias in Puerto Rico. */ + } + individual part def 'SA-515' :> SaturnV { + doc /* Unused. Originally designated for Apollo 20, never used. Later it was proposed to launch the backup Skylab station into orbit sometime between January 1975 and April 1976. That way, it could expand the Apollo-Soyuz mission by 56-90 days. The first stage was on display at Michoud Assembly Facility, until June 2016 then was moved to the INFINITY Science Center in Mississippi. The second stage (S-II-15) is on display at Johnson Space Center. The third stage was converted to a backup Skylab orbital workshop and is on display at the National Air and Space Museum. */ + } + + // https:>//en.wikipedia.org/wiki/Apollo_command_and_service_module + individual part def 'CSM-098' :> ApolloCommandServiceModule { + doc /* 2TV-1 Used in thermal vacuum tests. CSM on display at Academy of Science Museum, Moscow, Russia as individual part def of the Apollo Soyuz Test Project display. */ + } + individual part def 'CM-099' :> ApolloCommandServiceModule { + doc /* 2S-1 Skylab flight crew interface training; impact tests. Scrapped */ + } + individual part def 'CSM-100' :> ApolloCommandServiceModule { + doc /* 2S-2 static structural testing. Command module "transferred to Smithsonian as an artifact", service module on display at New Mexico Museum of Space History */ + } + individual part def 'CSM-101' :> ApolloCommandServiceModule { + doc /* Apollo 7. Command module was on display at National Museum of Science and Technology, Ottawa, Ontario, Canada from 1974 until 2004, now at the Frontiers of Flight Museum, Dallas, Texas after 30 years of being on loan. */ + } + individual part def 'CSM-102' :> ApolloCommandServiceModule { + doc /* Launch Complex 34 checkout vehicle. Command module scrapped; service module is at JSC on top of the Little Joe II in Rocket Park with Boiler Plate 22 command module. */ + } + individual part def 'CSM-103' :> ApolloCommandServiceModule { + doc /* Apollo 8. Command module on display at the Museum of Science and Industry in Chicago */ + } + individual part def 'CSM-104' :> ApolloCommandServiceModule { + doc /* Gumdrop Apollo 9. Command module on display at San Diego Air and Space Museum */ + } + individual part def 'CSM-105' :> ApolloCommandServiceModule { + doc /* acoustic tests On display at National Air and Space Museum, Washington, D.C. as individual part def of the Apollo Soyuz Test Project display. */ + } + individual part def 'CSM-106' :> ApolloCommandServiceModule { + doc /* Charlie Brown Apollo 10. Command module on display at Science Museum, London */ + } + individual part def 'CSM-107' :> ApolloCommandServiceModule { + doc /* Columbia Apollo 11. Command module on display at National Air and Space Museum, Washington, D.C. */ + } + individual part def 'CSM-108' :> ApolloCommandServiceModule { + doc /* Yankee Clipper Apollo 12. Command module on display at Virginia Air & Space Center, Hampton, Virginia; previously on display at the National Naval Aviation Museum at Naval Air Station Pensacola, Pensacola, Florida (exchanged for CSM-116) */ + } + individual part def 'CSM-109' :> ApolloCommandServiceModule { + doc /* Odyssey Apollo 13. Command module on display at Kansas Cosmosphere and Space Center */ + } + individual part def 'CSM-110' :> ApolloCommandServiceModule { + doc /* Kitty Hawk Apollo 14. Command module on display at the Kennedy Space Center */ + } + individual part def 'CSM-111' :> ApolloCommandServiceModule { + doc /* Apollo Soyuz Test Project. Command module currently on display at California Science Center in Los Angeles, California (formerly displayed at the Kennedy Space Center Visitor Complex) */ + } + individual part def 'CSM-112' :> ApolloCommandServiceModule { + doc /* Endeavour Apollo 15. Command module on display at National Museum of the United States Air Force, Wright-Patterson Air Force Base, Dayton, Ohio */ + } + individual part def 'CSM-113' :> ApolloCommandServiceModule { + doc /* Casper Apollo 16. Command module on display at U.S. Space & Rocket Center, Huntsville, Alabama */ + } + individual part def 'CSM-114' :> ApolloCommandServiceModule { + doc /* America Apollo 17. Command module on display at Space Center Houston, Houston, Texas */ + } + individual part def 'CSM-115' :> ApolloCommandServiceModule { + doc /* Apollo 19. Never fully completed - service module does not have its SPS nozzle installed. On display as individual part def of the Saturn V display at Johnson Space Center, Houston, Texas */ + } + individual part def 'CSM-115a' :> ApolloCommandServiceModule { + doc /* Apollo 20. Never fully completed - internal structures not installed, used for spare individual part defs. Remaining items sent to Japan for exhibition in 1978 and never returned, possibly scrapped. */ + } + individual part def 'CSM-116' :> ApolloCommandServiceModule { + doc /* Skylab 2. Command module on display at National Museum of Naval Aviation, Naval Air Station Pensacola, Pensacola, Florida */ + } + individual part def 'CSM-117' :> ApolloCommandServiceModule { + doc /* Skylab 3. Command module on display at Great Lakes Science Center, current location of the NASA Glenn Research Center Visitor Center, Cleveland, Ohio */ + } + individual part def 'CSM-118' :> ApolloCommandServiceModule { + doc /* Skylab 4. Command module on display at Oklahoma History Center (formerly displayed at the National Air and Space Museum, Washington, D.C.) */ + } + individual part def 'CSM-119' :> ApolloCommandServiceModule { + doc /* Skylab Rescue and ASTP backup. On display at the Kennedy Space Center*/ + } + + // https:>//en.wikipedia.org/wiki/Apollo_Lunar_Module + individual part def 'LTA-1' :> ApolloLunarModule { + doc /* Not flown Cradle of Aviation Museum (Long Island, New York) */ + } + individual part def 'LTA-2R' :> ApolloLunarModule { + doc /* Apollo 6. Re-entered Earth's atmosphere */ + } + individual part def 'LTA-3A' :> ApolloLunarModule { + doc /* Not flown. Kansas Cosmosphere and Space Center */ + } + individual part def 'LTA-3DR' :> ApolloLunarModule { + doc /* Non-flight descent stage. Franklin Institute */ + } + individual part def 'LTA-5D' :> ApolloLunarModule { + doc /* Not flown. White Sands Test Facility */ + } + individual part def 'LTA-8A' :> ApolloLunarModule { + doc /* Thermal-vacuum tests Ground tests in 1968 Space Center Houston */ + } + individual part def 'LTA-10R' :> ApolloLunarModule { + doc /* Apollo 4. Re-entered Earth's atmosphere */ + } + individual part def 'MSC-16' :> ApolloLunarModule { + doc /* Lunar Module Trainer. Museum of Science and Industry (Chicago) */ + } + individual part def 'TM-5' :> ApolloLunarModule { + doc /* Non-flight. Museum of Life and Science (Durham, North Carolina) */ + } + individual part def 'PA-1' :> ApolloLunarModule { + doc /* Not flown. White Sands Test Facility */ + } + individual part def 'LM-1' :> ApolloLunarModule { + doc /* Apollo 5. Re-entered Earth's atmosphere */ + } + individual part def 'LM-2' :> ApolloLunarModule { + doc /* Intended for second uncrewed flight, used instead for ground testing. Landing gear added for drop testing. Lacks Alignment Optical Telescope and flight computer National Air and Space Museum (Washington, D.C.) */ + } + individual part def 'LM-3' :> ApolloLunarModule { + doc /* Spider, Apollo 9. Descent and ascent stages reentered Earth's atmosphere separately */ + } + individual part def 'LM-4' :> ApolloLunarModule { + doc /* Snoopy, Apollo 10. Descent stage may have hit the Moon, ascent stage in heliocentric orbit. Snoopy is the only flown LM ascent stage known to have survived intact (possibly asteroid 2018 AV2). */ + } + individual part def 'LM-5' :> ApolloLunarModule { + doc /* Eagle, Apollo 11. Descent stage on lunar surface in Sea of Tranquility, ascent stage left in lunar orbit (could be still orbiting the moon) */ + } + individual part def 'LM-6' :> ApolloLunarModule { + doc /* Intrepid, Apollo 12. Descent stage on lunar surface at Ocean of Storms, ascent stage deliberately crashed into Moon */ + } + individual part def 'LM-7' :> ApolloLunarModule { + doc /* Aquarius, Apollo 13. Successfully served as a lifeboat for the crew for four days after the critical failure of the Service module. Re-entered Earth's atmosphere and burned up over Fiji */ + } + individual part def 'LM-8' :> ApolloLunarModule { + doc /* Antares, Apollo 14. Descent stage on lunar surface at Fra Mauro, ascent stage deliberately crashed into Moon */ + } + individual part def 'LM-9' :> ApolloLunarModule { + doc /* Not flown, intended as Apollo 15, last H-class mission. On display at the Kennedy Space Center (Apollo/Saturn V Center) */ + } + individual part def 'LM-10' :> ApolloLunarModule { + doc /* Falcon, Apollo 15. Descent stage on lunar surface at Hadley-Apennine, ascent stage deliberately crashed into Moon */ + } + individual part def 'LM-11' :> ApolloLunarModule { + doc /* Orion, Apollo 16. Descent stage on lunar surface at Descartes Highlands, ascent stage left in lunar orbit, crashed on Moon*/ + } + individual part def 'LM-12' :> ApolloLunarModule { + doc /* Challenger, Apollo 17. Descent stage on lunar surface at Taurus-Littrow, ascent stage deliberately crashed into Moon */ + } + individual part def 'LM-13' :> ApolloLunarModule { + doc /* Not flown, intended as Apollo 19. individual part defially completed by Grumman, restored and on display at Cradle of Aviation Museum (Long Island, New York). Also used during 1998 miniseries From the Earth to the Moon. */ + } + individual part def 'LM-14' :> ApolloLunarModule { + doc /* Not flown, intended as Apollo 20.Incomplete, most likely scrapped */ + } + individual part def 'LM-15' :> ApolloLunarModule { + doc /* Not flown, intended for modification into Apollo Telescope Mount. Incomplete,scrapped */ + } +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/TechnicalPortsPackage.sysml b/language/src/test/resources/Apollo_11/TechnicalPortsPackage.sysml new file mode 100644 index 00000000..06552d3d --- /dev/null +++ b/language/src/test/resources/Apollo_11/TechnicalPortsPackage.sysml @@ -0,0 +1,124 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package TechnicalPortsPackage { + + private import SI::*; + private import ISQ::*; + + item def StructuralLoad { doc /* Represents the transfer of physical forces (compression, tension, torsion). */ } + item def CommandSignal { doc /* Represents a discrete command or electrical signal. */ } + item def TelemetryData { doc /* Represents a flow of vehicle health and status data. */ } + item def ElectricalPower { doc /* Represents a flow of electrical energy. */ } + item def LifeSupportFlows { doc /* Represents a flow of oxygen, water, and thermal control fluids. */ } + + port def PayloadInterfacePort { + doc /* Defines the connection point on the launch vehicle that structurally supports and electrically interfaces with the spacecraft payload before separation. */ + inout item loads : StructuralLoad; + out item commands : CommandSignal; + in item telemetry : TelemetryData; + out item power : ElectricalPower; + } + + port def StagingPort { + doc /* A single definition for a staging interface port, viewed from the 'source' (lower) stage. */ + inout item loads : StructuralLoad; + out item commands : CommandSignal; + } + + port def ControlPort { + doc /* A single definition for a guidance interface port, viewed from the 'controller' (e.g., Instrument Unit). */ + out item guidanceCmds : CommandSignal; + out item thrustCmds : CommandSignal; + in item telemetry : TelemetryData; + out item power : ElectricalPower; + } + + port def UmbilicalPort { + doc /* A single definition for an umbilical port, viewed from the 'supplier' (e.g., Service Module). */ + out item power : ElectricalPower; + out item lifeSupport : LifeSupportFlows; + out item dataAndControl : CommandSignal; + } + + port def DockingPort { + doc /* A symmetric port for docking, where flows can be bidirectional. */ + inout item loads : StructuralLoad; + inout item power : ElectricalPower; + inout item data : TelemetryData; + } + + port def LMStagingPort { + doc /* A single definition for the Lunar Module staging port, viewed from the 'platform' (Descent Stage). */ + inout item loads : StructuralLoad; + out item commands : CommandSignal; + out item powerAndData : ElectricalPower; + } + + port def EVAUmbilicalPort { + doc /* A single definition for the spacesuit umbilical, viewed from the 'supplier' (the PLSS backpack). */ + out item lifeSupport : LifeSupportFlows; + out item power : ElectricalPower; + inout item commsAndData : TelemetryData; + } + + port def LaunchEscapeSystemPort { + doc /* Defines the connection point on the Command Module that supports and controls the LES. */ + inout item loads : StructuralLoad; + out item abortSignal : CommandSignal; + out item jettisonSignal : CommandSignal; + } + + interface def StagingInterface { + doc /* Defines the contract for a connection between two rocket stages. */ + end source : StagingPort; + end target : ~StagingPort; + } + + interface def GuidanceInterface { + doc /* Defines the contract for a connection between a controller (IU) and a controlled component (S-IVB). */ + end controller : ControlPort; + end controlled : ~ControlPort; + } + + interface def CSMInterface { + doc /* Defines the contract for the umbilical connection between the Command and Service Modules. */ + end supplier : UmbilicalPort; + end consumer : ~UmbilicalPort; + } + + interface def DockingInterface { + doc /* Defines the contract for a symmetric docking connection between two vehicles. */ + end vehicle1 : DockingPort; + end vehicle2 : DockingPort; + } + + interface def LMStagingInterface { + doc /* Defines the contract for the connection between the two stages of the Lunar Module. */ + end platform : LMStagingPort; + end ascender : ~LMStagingPort; + } + + interface def EVAInterface { + doc /* Defines the contract for the connection between the spacesuit and its life support backpack. */ + end plss : EVAUmbilicalPort; + end psa : ~EVAUmbilicalPort; + } + + interface def LVPayloadInterface { + doc /* Defines the contract for the primary connection between the launch vehicle (Instrument Unit) and the spacecraft payload (SLA). */ + end launchVehicle : PayloadInterfacePort; + end payload : ~PayloadInterfacePort; + } + + interface def LESInterface { + doc /* Defines the contract for the connection between the Command Module and the Launch Escape System. */ + end commandModule : LaunchEscapeSystemPort; + end launchEscapeSystem : ~LaunchEscapeSystemPort; + } + +} \ No newline at end of file diff --git a/language/src/test/resources/Apollo_11/TechnicalRequirementsPackage.sysml b/language/src/test/resources/Apollo_11/TechnicalRequirementsPackage.sysml new file mode 100644 index 00000000..868ae540 --- /dev/null +++ b/language/src/test/resources/Apollo_11/TechnicalRequirementsPackage.sysml @@ -0,0 +1,1208 @@ +// +// Copyright (c) 2026 AIRBUS and its affiliates. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +package TechnicalRequirementsPackage { + + private import SI::*; + private import ISQ::*; + private import ScalarValues::*; + private import CoSMAQuantitiesAndUnitsPackage::*; + private import USCustomaryUnits::*; + private import ModelingMetadata::*; + private import CoSMAPackage::*; + private import FunctionalRequirementsPackage::*; + + requirement def <'CLR-R001'> SICEngineConfiguration { + doc /* The S-IC stage shall incorporate five F-1 engines. */ + @Rationale { + text = "This configuration is required to generate the necessary thrust to lift the massive Saturn V vehicle off the launch pad."; + } + #refinement dependency SICEngineConfiguration to FunctionalRequirementsPackage::'FLR-R008'; + } + + requirement def <'CLR-R002'> SICPropellantCompatibility { + doc /* The S-IC stage shall be designed to store and deliver RP-1 (Kerosene) and Liquid Oxygen (LOX) to its engines. */ + @Rationale { + text = "The choice of the F-1 engine dictates the required propellant types for the first stage."; + } + #refinement dependency SICPropellantCompatibility to FunctionalRequirementsPackage::'FLR-R001'; + } + + requirement def <'CLR-R003'> SICGimbalCapability { + doc /* The S-IC stage shall provide a gimbaling mechanism for its engines to enable thrust vector control. */ + @Rationale { + text = "Gimbaling is the primary means of steering the vehicle during the first stage of ascent, as aerodynamic surfaces are ineffective at low speeds."; + } + #refinement dependency SICGimbalCapability to FunctionalRequirementsPackage::'FLR-R013'; + } + + requirement def <'CLR-R026'> SICSeparationSystem { + doc /* The S-IC stage shall incorporate a pyrotechnic separation system to cleanly detach from the S-II stage. */ + @Rationale { + text = "A reliable separation system is critical to jettison the massive first stage and allow the second stage to ignite without obstruction."; + } + #refinement dependency SICSeparationSystem to FunctionalRequirementsPackage::'FLR-R014'; + } + + + requirement def <'CLR-R004'> SIIEngineConfiguration { + doc /* The S-II stage shall incorporate five J-2 engines. */ + @Rationale { + text = "This configuration provides the required thrust for second-stage flight in the upper atmosphere and vacuum where efficiency is paramount."; + } + #refinement dependency SIIEngineConfiguration to FunctionalRequirementsPackage::'FLR-R010'; + } + + requirement def <'CLR-R005'> SIIPropellantType { + doc /* The S-II stage shall use Liquid Hydrogen (LH2) and Liquid Oxygen (LOX) propellants. */ + @Rationale { + text = "The high specific impulse of hydrolox propellant is critical for the efficiency of the upper stages to minimize vehicle mass."; + } + #refinement dependency SIIPropellantType to FunctionalRequirementsPackage::'FLR-R001'; + } + + requirement def <'CLR-R027'> SIIStructuralIntegrity { + doc /* The S-II stage shall maintain structural integrity under the loads of its own thrust and the mass of the upper stages. */ + @Rationale { + text = "The S-II stage structure must not fail under the combined stresses of acceleration and the weight of the fully fueled third stage and spacecraft."; + } + #refinement dependency SIIStructuralIntegrity to FunctionalRequirementsPackage::'FLR-R010'; + } + + + + requirement def <'CLR-R006'> SIVBEngineConfiguration { + doc /* The S-IVB stage shall incorporate a single J-2 engine. */ + @Rationale { + text = "A single, highly reliable engine provides the required thrust for both Earth orbit insertion and the subsequent Translunar Injection maneuver."; + } + #refinement dependency SIVBEngineConfiguration to FunctionalRequirementsPackage::'FLR-R011'; + } + + requirement def <'CLR-R007'> SIVBRestartCapability { + doc /* The S-IVB's J-2 engine shall be capable of restarting in a zero-gravity environment. */ + @Rationale { + text = "Engine restart is a critical capability, as the stage must fire once for orbit insertion and again for the TLI burn hours later."; + } + #refinement dependency SIVBRestartCapability to FunctionalRequirementsPackage::'FLR-R019'; + } + + requirement def <'CLR-R028'> SIVBAttitudeControlSystem { + doc /* The S-IVB stage shall incorporate an attitude control system to maintain stable orientation during coast phases. */ + @Rationale { + text = "The stage must maintain a correct and stable attitude in orbit to ensure proper thermal conditions and alignment for the TLI burn."; + } + #refinement dependency SIVBAttitudeControlSystem to FunctionalRequirementsPackage::'FLR-R020'; + } + + + requirement def <'CLR-R008'> IUGuidanceComputer { + doc /* The SaturnVInstrumentUnit shall house the primary guidance and navigation computer for the launch vehicle. */ + @Rationale { + text = "A dedicated computer is required to process trajectory data and execute the complex ascent flight plan autonomously."; + } + #refinement dependency IUGuidanceComputer to FunctionalRequirementsPackage::'FLR-R013'; + } + + requirement def <'CLR-R009'> IUCommandAuthority { + doc /* The SaturnVInstrumentUnit shall issue all primary commands for engine ignition, cutoff, and stage separation during ascent. */ + @Rationale { + text = "A single, authoritative control unit is necessary to ensure precise and synchronized execution of mission-critical events."; + } + #refinement dependency IUCommandAuthority to FunctionalRequirementsPackage::'FLR-R014'; + } + + requirement def <'CLR-R029'> IUTelemetrySystem { + doc /* The SaturnVInstrumentUnit shall gather and transmit vehicle health and status data to ground telemetry systems. */ + @Rationale { + text = "Real-time data on the launch vehicle's performance is critical for ground controllers to monitor the ascent."; + } + #refinement dependency IUTelemetrySystem to FunctionalRequirementsPackage::'FLR-R017'; + } + + + requirement def <'CLR-R010'> LESPropulsionType { + doc /* The ApolloLaunchEscapeSystem shall utilize a high-thrust solid rocket motor. */ + @Rationale { + text = "Solid rockets provide the rapid, high-impulse thrust needed to pull the crew capsule away from a failing launch vehicle with minimal delay."; + } + #refinement dependency LESPropulsionType to FunctionalRequirementsPackage::'FLR-R016'; + } + + requirement def <'CLR-R011'> LESJettisonCapability { + doc /* The ApolloLaunchEscapeSystem shall be capable of being safely jettisoned from the spacecraft after the period of maximum atmospheric stress. */ + @Rationale { + text = "The LES is dead weight after the initial ascent phase and must be discarded to ensure mission efficiency."; + } + #refinement dependency LESJettisonCapability to FunctionalRequirementsPackage::'FLR-R016'; + } + + + requirement def <'CLR-R012'> CMHabitableVolume { + doc /* The ApolloCommandModule shall provide a pressurized, habitable volume for a crew of three. */ + @Rationale { + text = "The Command Module serves as the primary living and working quarters for the crew for the majority of the mission."; + } + #refinement dependency CMHabitableVolume to FunctionalRequirementsPackage::'FLR-R004'; + } + + requirement def <'CLR-R013'> CMHeatShield { + doc /* The ApolloCommandModule shall incorporate a heat shield capable of protecting the crew and structure from the heat of atmospheric reentry. */ + @Rationale { + text = "Protection from the extreme temperatures of reentry is a fundamental requirement for crew survival."; + } + #refinement dependency CMHeatShield to FunctionalRequirementsPackage::'FLR-R080'; + } + + requirement def <'CLR-R014'> CMParachuteSystem { + doc /* The ApolloCommandModule shall house a system of parachutes to decelerate the vehicle for a safe water landing. */ + @Rationale { + text = "Aerodynamic decelerators are required to reduce the capsule's velocity to survivable limits for splashdown."; + } + #refinement dependency CMParachuteSystem to FunctionalRequirementsPackage::'FLR-R081'; + } + + requirement def <'CLR-R030'> CMDockingMechanism { + doc /* The ApolloCommandModule shall incorporate a probe and drogue docking mechanism. */ + @Rationale { + text = "A reliable and proven docking mechanism is required to physically connect with the Lunar Module in Earth and Lunar orbit."; + } + #refinement dependency CMDockingMechanism to FunctionalRequirementsPackage::'FLR-R023'; + } + + requirement def <'CLR-R052'> GNCGuidancePrecision { + doc /* The Apollo 11 Mission's guidance system shall calculate mid-course correction burns with a delta-V accuracy of +/- 0.1 meters per second, + ensuring the trajectory remains within mission-defined corridors. */ + @Rationale { + text = "Precise calc of trajectory adjustments is vital for minimizing fuel consumption and ensuring the spacecraft stays on the optimal path, supporting mission efficiency and success."; + } + + attribute actualDeltaVcalcAccuracy :> ISQ::speed; + attribute maxDeltaVcalcAccuracy :> ISQ::speed = 0.1 [m/s]; + attribute trajectoryWithinCorridor: Boolean; + + require constraint { + (actualDeltaVcalcAccuracy <= maxDeltaVcalcAccuracy) and + trajectoryWithinCorridor + } + #refinement dependency 'CLR-R052' to FunctionalRequirementsPackage::'FLR-R028'; + } + + requirement def <'CLR-R053'> RCSControlStability { + doc /* The Apollo 11 Mission's control system shall maintain spacecraft attitude within +/- 0.5 degrees of commanded orientation + during orbital and coast phases. */ + @Rationale { + text = "Stable spacecraft attitude is necessary for accurate navigation, efficient engine burns, proper thermal control, and reliable communication, impacting multiple critical mission functions."; + } + + attribute actualAttitudeDeviation :> ISQ::angularMeasure; + attribute maxAttitudeDeviation :> ISQ::angularMeasure = 0.5 ['°']; + + require constraint { actualAttitudeDeviation <= maxAttitudeDeviation } + #refinement dependency 'CLR-R053' to FunctionalRequirementsPackage::'FLR-R096'; + } + + requirement def <'CLR-R054'> LMDSRadarPrecision { + doc /* The Apollo 11 Mission's lunar lander's navigation system shall provide real-time altitude and velocity data + with an accuracy of +/- 1 meter for altitude and +/- 0.1 meters per second for velocity during the final 50 meters of powered descent. */ + @Rationale { + text = "High-fidelity real-time navigation data is critical for the lunar lander's autonomous and manual control during the final, most hazardous, phase of descent, ensuring a safe touchdown."; + } + + attribute actualAltitudeAccuracy :> ISQ::length; + attribute maxAltitudeAccuracy :> ISQ::length = 1 [m]; + + attribute actualVelocityAccuracy :> ISQ::speed; + attribute maxVelocityAccuracy :> ISQ::speed = 0.1 [m/s]; + + require constraint { + (actualAltitudeAccuracy <= maxAltitudeAccuracy) and + (actualVelocityAccuracy <= maxVelocityAccuracy) + } + #refinement dependency 'CLR-R054' to FunctionalRequirementsPackage::'FLR-R097'; + } + + requirement def <'CLR-R015'> SMMainPropulsion { + doc /* The ApolloServiceModule shall provide a restartable main engine for major in-space maneuvers. */ + @Rationale { + text = "A high-thrust, reliable main engine is required for critical mission events like Lunar Orbit Insertion and Trans-Earth Injection."; + } + #refinement dependency SMMainPropulsion to FunctionalRequirementsPackage::'FLR-R024'; + } + + requirement def <'CLR-R016'> SMAttitudeControl { + doc /* The ApolloServiceModule shall provide a reaction control system for attitude control and minor velocity changes. */ + @Rationale { + text = "The RCS is essential for orienting the spacecraft for thermal control, communications, and main engine burns."; + } + #refinement dependency SMAttitudeControl to FunctionalRequirementsPackage::'FLR-R025'; + } + + requirement def <'CLR-R017'> SMPowerGeneration { + doc /* The ApolloServiceModule shall house fuel cells to generate the primary electrical power for the Command/Service Module. */ + @Rationale { + text = "A continuous and reliable source of electrical power is required to operate all onboard systems, including life support."; + } + #refinement dependency SMPowerGeneration to FunctionalRequirementsPackage::'FLR-R030'; + } + + requirement def <'CLR-R031'> SMThermalControlSystem { + doc /* The ApolloServiceModule shall incorporate radiators to reject waste heat from the spacecraft into space. */ + @Rationale { + text = "An active thermal control system is necessary to prevent onboard systems and the crew cabin from overheating."; + } + #refinement dependency SMThermalControlSystem to FunctionalRequirementsPackage::'FLR-R031'; + } + + requirement def <'CLR-R051'> CabinEnvironmentalControlRequirement { + doc /* The Apollo 11 Mission's spacecraft environmental control system shall maintain cabin temperature between 20°C and 25°C + and oxygen partial pressure between 2.5 pounds per square inch and 4.0 pounds per square inch for all 8 days of the mission, for a crew of three. */ + @Rationale { + text = "Maintaining a stable and safe cabin environment is crucial for astronaut health, comfort, and performance throughout the mission duration, directly supporting the 'Go to Moon' goal and human safety."; + } + + attribute actualCabinTemperatureMin :> ISQ::thermodynamicTemperature; + attribute actualCabinTemperatureMax :> ISQ::thermodynamicTemperature; + attribute minCabinTemperatureReqd :> ISQ::thermodynamicTemperature = 20 ['°C']; + attribute maxCabinTemperatureReqd :> ISQ::thermodynamicTemperature = 25 ['°C']; + + attribute actualOxygenPressureMin :> ISQ::pressure; + attribute actualOxygenPressureMax :> ISQ::pressure; + attribute minOxygenPressureReqd :> ISQ::pressure = 2.5 ['pound-force per square inch (psi)']; + attribute maxOxygenPressureReqd :> ISQ::pressure = 4.0 ['pound-force per square inch (psi)']; + + attribute missionDuration :> ISQ::time; + + require constraint { + (actualCabinTemperatureMin >= minCabinTemperatureReqd) and + (actualCabinTemperatureMax <= maxCabinTemperatureReqd) and + (actualOxygenPressureMin >= minOxygenPressureReqd) and + (actualOxygenPressureMax <= maxOxygenPressureReqd) + } + #refinement dependency 'CLR-R051' to FunctionalRequirementsPackage::'FLR-R102'; + } + + + requirement def <'CLR-R018'> LMDSThrottleableEngine { + doc /* The LunarModuleDescentStage shall provide a main engine with a throttleable thrust range. */ + @Rationale { + text = "A variable thrust is essential for the powered descent, allowing the crew to precisely control the rate of descent for a soft landing."; + } + #refinement dependency LMDSThrottleableEngine to FunctionalRequirementsPackage::'FLR-R046'; + } + + requirement def <'CLR-R019'> LMDSLandingGear { + doc /* The LunarModuleDescentStage shall incorporate a landing gear system capable of absorbing the energy of a lunar touchdown. */ + @Rationale { + text = "The landing gear must prevent structural damage to the lander and protect the crew from the forces of the final landing impact."; + } + #refinement dependency LMDSLandingGear to FunctionalRequirementsPackage::'FLR-R002'; + } + + requirement def <'CLR-R032'> LMDSLaunchPlatform { + doc /* The LunarModuleDescentStage shall provide a stable, structurally sound platform for the ascent stage to launch from. */ + @Rationale { + text = "The descent stage must serve as a one-time launch pad on the Moon, withstanding the forces of the ascent engine ignition."; + } + #refinement dependency LMDSLaunchPlatform to FunctionalRequirementsPackage::'FLR-R065'; + } + + requirement def <'CLR-R050'> LMDSVelocityLimits { + doc /* The LunarModuleDescentStage shall command thrust to ensure that at the moment of footpad touchdown, the vehicle's velocities do not exceed the following limits: + * Vertical Velocity: <= 3.05 meters per second (10 feet per second) + * Horizontal Velocity: <= 1.22 meters per second (4 feet per second) + */ + @Rationale { + text = "These limits prevent structural damage to the ascent stage interface or a post-impact tip-over of the LM."; + } + #refinement dependency LMDSVelocityLimits to FunctionalRequirementsPackage::'FLR-R082'; + } + + requirement def <'CLR-R020'> LMASAscentEngine { + doc /* The LunarModuleAscentStage shall provide a fixed-thrust engine capable of lifting the stage from the lunar surface into orbit. */ + @Rationale { + text = "A highly reliable, non-throttleable engine provides the simplest and most robust means of achieving lunar orbit for rendezvous."; + } + #refinement dependency LMASAscentEngine to FunctionalRequirementsPackage::'FLR-R066'; + } + + requirement def <'CLR-R021'> LMASCrewCabin { + doc /* The LunarModuleAscentStage shall provide a pressurized cabin for a crew of two. */ + @Rationale { + text = "The ascent stage serves as the flight deck and habitat for the crew during lunar orbit and surface operations."; + } + #refinement dependency LMASCrewCabin to FunctionalRequirementsPackage::'FLR-R062'; + } + + requirement def <'CLR-R033'> LMASRendezvousRadar { + doc /* The LunarModuleAscentStage shall incorporate a radar system to track the Command Module during rendezvous. */ + @Rationale { + text = "An independent tracking capability is required for the LM to compute its trajectory relative to the CSM for a successful rendezvous."; + } + #refinement dependency LMASRendezvousRadar to FunctionalRequirementsPackage::'FLR-R067'; + } + + requirement def <'CLR-R022'> PSAPressureContainment { + doc /* The PressureSuiteAssembly shall maintain a positive internal pressure environment for the astronaut. */ + @Rationale { + text = "Maintaining pressure is the most fundamental requirement for keeping an astronaut alive in the vacuum of space."; + } + #refinement dependency PSAPressureContainment to FunctionalRequirementsPackage::'FLR-R053'; + } + + requirement def <'CLR-R023'> PSAMobility { + doc /* The PressureSuiteAssembly shall allow sufficient mobility for the crew to perform required EVA tasks. */ + @Rationale { + text = "The suit must not be so rigid that it prevents the crew from walking, bending, and using tools effectively."; + } + #refinement dependency PSAMobility to FunctionalRequirementsPackage::'FLR-R055'; + } + + requirement def <'CLR-R034'> PSAHelmetVisibility { + doc /* The PressureSuiteAssembly shall provide a helmet with a wide, unobstructed field of view and protective visors. */ + @Rationale { + text = "Clear and wide visibility is essential for navigation, task performance, and hazard identification on the lunar surface."; + } + #refinement dependency PSAHelmetVisibility to FunctionalRequirementsPackage::'FLR-R055'; + } + + requirement def <'CLR-R024'> PLSSOxygenSupply { + doc /* The PortableLifeSupportSystem shall contain and supply breathable oxygen to the crew member. */ + @Rationale { + text = "A finite supply of oxygen is required for the duration of the extravehicular activity."; + } + #refinement dependency PLSSOxygenSupply to FunctionalRequirementsPackage::'FLR-R054'; + } + + requirement def <'CLR-R025'> PLSSContaminantRemoval { + doc /* The PortableLifeSupportSystem shall remove carbon dioxide and other contaminants from the suit's atmosphere. */ + @Rationale { + text = "Recirculating the suit's atmosphere requires the continuous removal of harmful metabolic byproducts like CO2."; + } + #refinement dependency PLSSContaminantRemoval to FunctionalRequirementsPackage::'FLR-R053'; + } + + requirement def <'CLR-R035'> PLSSCoolingSystem { + doc /* The PortableLifeSupportSystem shall circulate cooling fluid to regulate astronaut body temperature. */ + @Rationale { + text = "An active cooling system is required to remove excess body heat and prevent overheating during strenuous activity in the suit."; + } + #refinement dependency PLSSCoolingSystem to FunctionalRequirementsPackage::'FLR-R053'; + } + + requirement def <'CLR-R036'> StagingInterfaceLoadTransfer { + doc /* The StagingInterface shall be capable of transferring all structural loads from the upper stage to the lower stage during powered ascent. */ + @Rationale { + text = "Failure to transfer loads would result in catastrophic structural failure of the launch vehicle."; + } + #refinement dependency StagingInterfaceLoadTransfer to FunctionalRequirementsPackage::'FLR-R008'; + } + + requirement def <'CLR-R037'> StagingInterfaceCleanSeparation { + doc /* The StagingInterface shall ensure a clean separation with no re-contact between stages upon receiving a valid separation command. */ + @Rationale { + text = "Re-contact or debris could damage the upper stage engine, preventing ignition and causing mission failure."; + } + #refinement dependency StagingInterfaceCleanSeparation to FunctionalRequirementsPackage::'FLR-R014'; + } + + requirement def <'CLR-R038'> GuidanceInterfaceCommandIntegrity { + doc /* The GuidanceInterface shall transmit control commands with a data integrity of 99.999% or greater. */ + @Rationale { + text = "Corrupted guidance commands could lead to loss of vehicle control."; + } + #refinement dependency GuidanceInterfaceCommandIntegrity to FunctionalRequirementsPackage::'FLR-R013'; + } + + requirement def <'CLR-R039'> GuidanceInterfaceTelemetryLatency { + doc /* The GuidanceInterface shall provide real-time telemetry from the stage to the controller with a latency of less than 10 milliseconds. */ + @Rationale { + text = "Low latency is critical for the guidance computer to make timely adjustments to the vehicle's trajectory."; + } + #refinement dependency GuidanceInterfaceTelemetryLatency to FunctionalRequirementsPackage::'FLR-R017'; + } + + requirement def <'CLR-R040'> CSMInterfacePowerTransfer { + doc /* The CSMInterface shall transfer electrical power from the supplier to the consumer with a voltage drop of less than 2%. */ + @Rationale { + text = "Efficient power transfer is necessary to ensure all Command Module systems are adequately powered."; + } + #refinement dependency CSMInterfacePowerTransfer to FunctionalRequirementsPackage::'FLR-R030'; + } + + requirement def <'CLR-R041'> CSMInterfaceLifeSupportIntegrity { + doc /* The CSMInterface shall transport life support consumables with zero leakage. */ + @Rationale { + text = "Any leakage of oxygen or water would be a critical, life-threatening failure."; + } + #refinement dependency CSMInterfaceLifeSupportIntegrity to FunctionalRequirementsPackage::'FLR-R025'; + } + + requirement def <'CLR-R042'> DockingInterfaceStructuralRigidity { + doc /* The DockingInterface shall form a rigid structural connection capable of withstanding attitude control maneuvers. */ + @Rationale { + text = "The two docked spacecraft must behave as a single, rigid body to ensure stable flight control."; + } + #refinement dependency DockingInterfaceStructuralRigidity to FunctionalRequirementsPackage::'FLR-R023'; + } + + requirement def <'CLR-R043'> DockingInterfacePressurizedSeal { + doc /* The DockingInterface shall create a pressurized seal between the two vehicle cabins. */ + @Rationale { + text = "A secure, pressurized tunnel is required to allow for the safe transfer of crew members between vehicles without spacesuits."; + } + #refinement dependency DockingInterfacePressurizedSeal to FunctionalRequirementsPackage::'FLR-R071'; + } + + requirement def <'CLR-R044'> LMStagingInterfaceSeparation { + doc /* The LMStagingInterface shall execute a clean pyrotechnic separation of the Ascent Stage from the Descent Stage. */ + @Rationale { + text = "A reliable separation is critical for the Ascent Stage to lift off from the lunar surface unimpeded."; + } + #refinement dependency LMStagingInterfaceSeparation to FunctionalRequirementsPackage::'FLR-R065'; + } + + requirement def <'CLR-R045'> EVAInterfaceSecureConnection { + doc /* The EVAInterface shall provide secure, quick-disconnect fittings for all fluid and data connections. */ + @Rationale { + text = "Connections must be reliable and easy for a gloved astronaut to operate, while preventing accidental disconnection during an EVA."; + } + #refinement dependency EVAInterfaceSecureConnection to FunctionalRequirementsPackage::'FLR-R053'; + } + + requirement def <'CLR-R046'> LVPayloadInterfaceStructural { + doc /* The interface between the SaturnVInstrumentUnit and the ApolloSpacecraftLMAdapter shall withstand all structural loads during launch and ascent. */ + @Rationale { + text = "This interface bears the entire mechanical load of the 45-ton Apollo spacecraft stack during its most violent flight phase."; + } + #refinement dependency LVPayloadInterfaceStructural to FunctionalRequirementsPackage::'FLR-R008'; + } + + requirement def <'CLR-R047'> SLALMDeployment { + doc /* The ApolloSpacecraftLMAdapter shall deploy the Lunar Module upon command with sufficient force to prevent re-contact. */ + @Rationale { + text = "A successful and clean deployment of the LM after transposition and docking is critical to beginning the lunar phase of the mission."; + } + #refinement dependency SLALMDeployment to FunctionalRequirementsPackage::'FLR-R022'; + } + + requirement def <'CLR-R048'> LESInterfaceStructuralIntegrity { + doc /* The interface between the ApolloCommandModule and the ApolloLaunchEscapeSystem shall maintain structural integrity under all launch and ascent aerodynamic loads. */ + @Rationale { + text = "A structural failure of this interface could cause the LES to detach prematurely, endangering the crew and the mission."; + } + #refinement dependency LESInterfaceStructuralIntegrity to FunctionalRequirementsPackage::'FLR-R016'; + } + + requirement def <'CLR-R049'> LESInterfaceCommandReliability { + doc /* The interface between the ApolloCommandModule and the ApolloLaunchEscapeSystem shall reliably transmit abort and jettison commands to the LES motors. */ + @Rationale { + text = "The failure to transmit an abort command in an emergency would be catastrophic. The failure to jettison the LES would prevent mission continuation."; + } + #refinement dependency LESInterfaceCommandReliability to FunctionalRequirementsPackage::'FLR-R016'; + } + + requirement def <'CLR-R055'> SICThrustMagnitude { + doc /* The Apollo 11 Mission's launch vehicle's first stage propulsion shall provide a minimum thrust of 34.5 Meganewtons at liftoff. */ + @Rationale { + text = "Sufficient thrust from the first stage is fundamental to overcome Earth's gravity and initiate the launch sequence, enabling the entire mission."; + } + + attribute actualLiftoffThrust :> ISQ::force; + attribute minLiftoffThrust :> ISQ::force = 34.5 [MN]; + + require constraint { actualLiftoffThrust >= minLiftoffThrust } + + } + + requirement def <'CLR-R056'> SPSIgnitionReliability { + doc /* The Apollo 11 Mission's in-space propulsion system shall be capable of performing at least 3 full-duration major burns + (e.g., Lunar Orbit Insertion, Trans-Earth Injection) with a 99.8% ignition success rate for each burn. */ + @Rationale { + text = "The reliability of in-space propulsion is paramount for achieving and departing lunar orbit, directly impacting mission success and crew safety; failure means being stranded."; + } + + attribute actualMajorBurnCount: Integer; + attribute minMajorBurnCount: Integer = 3; + + attribute actualIgnitionSuccessRate: RatioValue; + attribute minIgnitionSuccessRate: RatioValue = 99.8['%']; + + require constraint { + (actualMajorBurnCount >= minMajorBurnCount) and + (actualIgnitionSuccessRate >= minIgnitionSuccessRate) + } + #refinement dependency 'CLR-R056' to FunctionalRequirementsPackage::'FLR-R024'; + } + + requirement def <'CLR-R057'> DPSThrottlingRange { + doc /* The Apollo 11 Mission's lunar lander's descent propulsion system shall provide throttleable thrust + from 10% to 100% of maximum thrust to enable precise lunar landing control. */ + @Rationale { + text = "Throttling capability provides the fine control necessary to manage descent rate and fuel consumption during the lunar landing, crucial for achieving a soft and controlled touchdown."; + } + + attribute actualMinThrottlePercentage: RatioValue; + attribute minRequiredThrottlePercentage: RatioValue = 10['%']; + + attribute actualMaxThrottlePercentage: RatioValue; + attribute maxRequiredThrottlePercentage: RatioValue = 100['%']; + + require constraint { + (actualMinThrottlePercentage <= minRequiredThrottlePercentage) and + (actualMaxThrottlePercentage >= maxRequiredThrottlePercentage) + } + #refinement dependency 'CLR-R057' to FunctionalRequirementsPackage::'FLR-R099'; + } + + requirement def <'CLR-R058'> LMASBurnDuration { + doc /* The Apollo 11 Mission's lunar lander's ascent propulsion system shall achieve a burn duration of <= 400 seconds + to insert the ascent stage into lunar orbit. */ + @Rationale { + text = "A specific burn duration is required to ensure the ascent stage achieves the correct lunar orbit for rendezvous, directly enabling the crew's return to the Command Module."; + } + + attribute actualAscentBurnDuration :> ISQ::time; + attribute maxAscentBurnDuration :> ISQ::time = 400 [s]; + + require constraint { actualAscentBurnDuration <= maxAscentBurnDuration } + #refinement dependency 'CLR-R058' to FunctionalRequirementsPackage::'FLR-R066'; + } + + requirement def <'CLR-R059'> PrimaryStructureLoadLimit { + doc /* All primary structural elements of the Apollo 11 Mission launch system shall withstand launch loads of up to 4 gees + without permanent deformation or failure. */ + @Rationale { + text = "Structural integrity during the high-stress launch phase is absolutely essential to prevent catastrophic failure and ensure the vehicle and crew reach orbit safely."; + } + + attribute actualMaxLaunchLoadWithstood :> ISQ::acceleration; + attribute requiredMaxLaunchLoadWithstood :> ISQ::acceleration = 4 [gn]; + + attribute permanentDeformationObserved: Boolean; + attribute structuralFailureObserved: Boolean; + + require constraint { + (actualMaxLaunchLoadWithstood >= requiredMaxLaunchLoadWithstood) and + not permanentDeformationObserved and + not structuralFailureObserved + } + } + + requirement def <'CLR-R060'> CMHeatShieldThermalPerf { + doc /* The Apollo 11 Mission's crew vehicle heat shield shall ablate as designed and limit internal crew compartment + temperature rise to less than 5°C during atmospheric re-entry. */ + @Rationale { + text = "The heat shield is critical for crew survival during re-entry by protecting against extreme temperatures, directly addressing human safety."; + } + + attribute actualInternalTemperatureRise :> ISQ::thermodynamicTemperature; + attribute maxInternalTemperatureRise :> ISQ::thermodynamicTemperature = 5 ['°C']; + + attribute heatShieldAblationAsDesigned: Boolean; + + require constraint { + (actualInternalTemperatureRise < maxInternalTemperatureRise) and + heatShieldAblationAsDesigned + } + #refinement dependency 'CLR-R060' to FunctionalRequirementsPackage::'FLR-R100'; + } + + requirement def <'CLR-R061'> PyrotechnicInitiationReliability { + doc /* All pyrotechnic devices (e.g., stage separation, parachute deployment) used in the Apollo 11 Mission + shall have a 99.99% initiation reliability. */ + @Rationale { + text = "Highly reliable pyrotechnic devices are crucial for sequential mission events like stage separations and parachute deployment, as failures in these systems could lead to catastrophic mission loss or crew fatalities."; + } + + attribute actualInitiationReliability: RatioValue; + attribute minInitiationReliability: RatioValue = 99.99['%']; + + require constraint { actualInitiationReliability >= minInitiationReliability } + } + + requirement def <'CLR-R062'> DockingMechanismReliability { + doc /* The Apollo 11 Mission's spacecraft docking system shall enable two spacecraft to mate and form a rigid connection + in lunar orbit, capable of withstanding dynamic loads during rendezvous maneuvers, + with a 99.5% success rate for capture and latching. */ + @Rationale { + text = "Reliable docking is essential for transferring crew and samples, making it a critical path to crew return and scientific goals. Failure would mean being stranded in lunar orbit."; + } + + attribute actualCaptureLatchingSuccessRate: RatioValue; + attribute minCaptureLatchingSuccessRate: RatioValue = 99.5['%']; + + attribute connectionRigidityMaintained: Boolean; + attribute withstandsDynamicLoads: Boolean; + + require constraint { + (actualCaptureLatchingSuccessRate >= minCaptureLatchingSuccessRate) and + connectionRigidityMaintained and + withstandsDynamicLoads + } + } + + requirement def <'CLR-R063'> LMDSLandingGearEnergy { + doc /* The Apollo 11 Mission's lunar lander's landing gear shall absorb impact energy equivalent to a 3 meters per second vertical velocity + and 1 meter per second horizontal velocity at touchdown without structural failure. */ + @Rationale { + text = "The landing gear must reliably absorb the forces of lunar touchdown to protect the lander structure, its internal systems, and the crew."; + } + + attribute maxImpactVerticalVelocityAbsorbed :> ISQ::speed; + attribute minImpactVerticalVelocityRequired :> ISQ::speed = 3 [m/s]; + + attribute maxImpactHorizontalVelocityAbsorbed :> ISQ::speed; + attribute minImpactHorizontalVelocityRequired :> ISQ::speed = 1 [m/s]; + + attribute structuralFailureOccurred: Boolean; + + require constraint { + (maxImpactVerticalVelocityAbsorbed >= minImpactVerticalVelocityRequired) and + (maxImpactHorizontalVelocityAbsorbed >= minImpactHorizontalVelocityRequired) and + not structuralFailureOccurred + } + } + + requirement def <'CLR-R064'> ECSWaterSupplyRate { + doc /* The Apollo 11 Mission's crew's potable water system shall provide a minimum of 2 kilograms of potable water per crew member per day. */ + @Rationale { + text = "Adequate potable water is a fundamental requirement for sustaining crew health and life throughout the mission."; + } + + attribute actualWaterProvidedPerCrewPerDay :> ISQ::mass; + attribute minWaterRequiredPerCrewPerDay :> ISQ::mass = 2 [kg]; + + require constraint { actualWaterProvidedPerCrewPerDay >= minWaterRequiredPerCrewPerDay } + } + + requirement def <'CLR-R065'> ECSFilterEfficiency { + doc /* The Apollo 11 Mission's cabin atmosphere purification system shall maintain carbon dioxide levels below 0.5% by volume + and remove particulate matter >= 0.5 microns with 99% efficiency. */ + @Rationale { + text = "Maintaining breathable air free of harmful contaminants is a continuous and critical life support function, directly impacting crew health and safety."; + } + + attribute actualCO2LevelMax: RatioValue; + attribute maxCO2LevelReqd: RatioValue = 0.5['%']; + + attribute actualParticulateRemovalEfficiency: RatioValue; + attribute minParticulateRemovalEfficiency: RatioValue = 99['%']; + + require constraint { + (actualCO2LevelMax <= maxCO2LevelReqd) and + (actualParticulateRemovalEfficiency >= minParticulateRemovalEfficiency) + } + } + + requirement def <'CLR-R066'> DataHandlingIntegrity { + doc /* The Apollo 11 Mission's data acquisition system shall record and store all critical telemetry data for the entire mission duration, + with no less than 99.9% data integrity. */ + @Rationale { + text = "High data integrity ensures that ground control has accurate information for real-time decision-making, post-flight analysis, and mission lessons learned."; + } + + attribute actualDataIntegrityPercentage: RatioValue; + attribute minDataIntegrityPercentage: RatioValue = 99.9['%']; + + require constraint { actualDataIntegrityPercentage >= minDataIntegrityPercentage } + } + + requirement def <'CLR-R067'> CommVideoBandwidth { + doc /* The Apollo 11 Mission spacecraft shall be capable of transmitting live video from the lunar surface to Earth + with a resolution of at least 320x240 pixels and a frame rate of >= 10 frames per second. */ + @Rationale { + text = "Live video transmission from the lunar surface significantly enhances public engagement and inspiration, and provides valuable real-time visual context for mission operations."; + } + + attribute actualVideoWidth: Integer; + attribute minVideoWidth: Integer = 320; + + attribute actualVideoHeight: Integer; + attribute minVideoHeight: Integer = 240; + + attribute actualFrameRate :> ISQ::frequency; + attribute minFrameRate :> ISQ::frequency = 10 ['fps']; + + require constraint { + (actualVideoWidth >= minVideoWidth) and + (actualVideoHeight >= minVideoHeight) and + (actualFrameRate >= minFrameRate) + } + #refinement dependency 'CLR-R067' to FunctionalRequirementsPackage::'FLR-R103'; + } + + requirement def <'CLR-R068'> EMUPressureContainment { + doc /* The Apollo 11 Mission's Extravehicular Mobility Unit shall maintain internal pressure at 25.5 kilopascals with no more than 5% pressure loss per hour during Extravehicular Activity. */ + @Rationale { + text = "Maintaining internal pressure in the Extravehicular Mobility Unit is critical for astronaut safety and performance during Extravehicular Activity in the vacuum of space."; + } + + attribute actualEMUInternalPressure :> ISQ::pressure; + attribute nominalEMUInternalPressure :> ISQ::pressure = 25.5 ['kPa']; + + attribute actualPressureLossRate: RatioValue; + attribute maxPressureLossRate: RatioValue = 5['%']; + + require constraint { + (actualPressureLossRate <= maxPressureLossRate) + } + #refinement dependency 'CLR-R068' to FunctionalRequirementsPackage::'FLR-R104'; + } + + requirement def <'CLR-R069'> EASEPOperationalDuration { + doc /* The Apollo 11 Mission's deployed scientific instruments shall be operational for a minimum of 30 days post-deployment + and transmit at least 100 Kilobytes of scientific data per day for this period. */ + @Rationale { + text = "Ensuring long-term operation and sufficient data transmission from deployed instruments maximizes the scientific return and provides continuous monitoring of the lunar environment."; + } + + attribute actualOperationalDuration :> ISQ::time; + attribute minOperationalDuration :> ISQ::time = 30['d']; + + attribute actualDailyDataTransmission :> ISQ::storageCapacity; + attribute minDailyDataTransmission :> ISQ::storageCapacity = 100 ['kB']; + + require constraint { + (actualOperationalDuration >= minOperationalDuration) and + (actualDailyDataTransmission >= minDailyDataTransmission) + } + #refinement dependency 'CLR-R069' to FunctionalRequirementsPackage::'FLR-R059'; + } + + requirement def <'CLR-R070'> MissionSystemReliability { + doc /* All mission-critical flight systems of the Apollo 11 Mission (e.g., primary propulsion, life support, main computer) + shall demonstrate a statistical reliability of >= 0.999 (three nines) for their operational lifetimes. */ + @Rationale { + text = "Extremely high reliability for critical systems is foundational to ensuring mission success and astronaut safety, given the inherent risks and remote operating environment."; + } + + attribute actualSystemReliability: Real; + attribute minRequiredReliability: Real = 0.999; + + require constraint { actualSystemReliability >= minRequiredReliability } + } + + requirement def <'CLR-R071'> FlightSoftwareDefectRate { + doc /* The Apollo 11 Mission's flight software for primary guidance and control shall have zero critical defects (Severity 1 or 2) + identified during a minimum of 2,000 hours of integrated hardware-in-the-loop simulation prior to flight. */ + @Rationale { + text = "Zero critical software defects are essential for autonomous and commanded operations, as software failures could directly jeopardize mission success and crew safety."; + } + + attribute actualCriticalDefectsCount: Integer; + attribute maxCriticalDefectsAllowed: Integer = 0; + + attribute actualSimulationHours :> ISQ::time; + attribute minSimulationHoursRequired :> ISQ::time = 2000 [h]; + + require constraint { + (actualCriticalDefectsCount <= maxCriticalDefectsAllowed) and + (actualSimulationHours >= minSimulationHoursRequired) + } + #refinement dependency 'CLR-R071' to FunctionalRequirementsPackage::'FLR-R105'; + } + + requirement def <'CLR-R072'> ComponentAcceptanceRate { + doc /* All flight components of the Apollo 11 Mission shall undergo acceptance testing to verify conformance to specifications + before integration, with <= 0.1% non-conformance rate. */ + @Rationale { + text = "Rigorous acceptance testing ensures that only compliant and reliable components are integrated into the flight system, minimizing risks from faulty parts."; + } + + attribute actualNonConformanceRate: RatioValue; + attribute maxNonConformanceRate: RatioValue = 0.1['%']; + + require constraint { actualNonConformanceRate <= maxNonConformanceRate } + } + + requirement def <'CLR-R073'> MaterialVacuumResistance { + doc /* All spacecraft materials of the Apollo 11 Mission shall withstand long-term exposure to the space environment + (vacuum, radiation, thermal cycling) for up to 14 days without critical degradation of structural integrity + or functional performance. */ + @Rationale { + text = "Material robustness in the extreme space environment is fundamental to ensuring the long-term integrity and functionality of the spacecraft, directly impacting mission safety and success."; + } + + attribute actualDegradationLevel: RatioValue; // e.g., % loss of strength/performance (0-100) + attribute maxDegradationLevel: RatioValue = 0['%']; // 'without critical degradation' + + attribute actualExposureDuration :> ISQ::time; + attribute minExposureDurationReqd :> ISQ::time = 14 [d]; + + require constraint { + (actualDegradationLevel <= maxDegradationLevel) and + (actualExposureDuration >= minExposureDurationReqd) + } + #refinement dependency 'CLR-R073' to FunctionalRequirementsPackage::'FLR-R106'; + } + + requirement def <'CLR-R074'> ElectronicEMIImmunity { + doc /* The entire Apollo 11 Mission system shall be designed to withstand the electromagnetic interference (EMI) environment + of launch and space operations without functional degradation. */ + @Rationale { + text = "Immunity to electromagnetic interference ensures that all electronic systems operate reliably without disruption from internal or external electromagnetic noise, vital for mission control and safety."; + } + + attribute functionalDegradationFromEMI: Boolean; + + require constraint { not functionalDegradationFromEMI } + } + + requirement def <'CLR-R075'> ImageResolutionStandard { + doc /* The visual data capture system shall provide a minimum resolution of 2k for still images + and 16mm equivalent for motion film. */ + @Rationale { + text = "High-resolution imagery is necessary to meet scientific documentation and public prestige goals."; + } + #refinement dependency 'CLR-R075' to FunctionalRequirementsPackage::'FLR-R107'; + } + + requirement def <'CLR-R076'> WasteStorageVolume { + doc /* The waste containment system shall provide a minimum of 0.5 cubic feet of sealed storage + per crew member for an 8-day mission. */ + @Rationale { + text = "Prevents cabin contamination and maintains crew hygiene during flight."; + } + #refinement dependency 'CLR-R076' to FunctionalRequirementsPackage::'FLR-R108'; + } + + requirement def <'CLR-R077'> VHFAudioBandwidth { + doc /* The cross-vehicle audio link shall operate within the 250-300 MHz range with a signal-to-noise + ratio of at least 20dB. */ + @Rationale { + text = "Ensures clear voice coordination between the LM and CSM during critical lunar operations."; + } + #refinement dependency 'CLR-R077' to FunctionalRequirementsPackage::'FLR-R109'; + } + + requirement def <'CLR-R078'> SystemRedundancyMapping { + doc /* All Level-1 critical electronic components shall be duplicated in an 'A' and 'B' bus + configuration with automatic failover. */ + @Rationale { + text = "Implements the fault tolerance required to prevent mission loss from a single component failure."; + } + #refinement dependency 'CLR-R078' to FunctionalRequirementsPackage::'FLR-R110'; + } + + requirement def <'CLR-R079'> MedicalKitSpecification { + doc /* The onboard medical kit shall contain antibiotics, analgesics, and minor surgical tools + certified for use in zero-gravity. */ + @Rationale { + text = "Enables the crew to manage health incidents without immediate Earth-based assistance."; + } + #refinement dependency 'CLR-R079' to FunctionalRequirementsPackage::'FLR-R111'; + } + + requirement def <'CLR-R080'> GroundArchivalProtocol { + doc /* Mission telemetry shall be recorded on magnetic tape at three geographically distinct + sites with 99.9% data parity. */ + @Rationale { + text = "Ensures long-term preservation of mission data for future scientific analysis."; + } + #refinement dependency 'CLR-R080' to FunctionalRequirementsPackage::'FLR-R112'; + } + + requirement def <'CLR-R081'> CrewSeatLoadFactor { + doc /* The crew seating system shall attenuate peak launch acceleration to ensure loads + experienced by the crew do not exceed 6g. */ + @Rationale { + text = "Ensures crew safety during the high-stress launch phase."; + } + #refinement dependency 'CLR-R081' to FunctionalRequirementsPackage::'FLR-R003'; + } + + requirement def <'CLR-R082'> LaunchAbortThresholds { + doc /* The Instrument Unit shall trigger an automatic abort if the vehicle attitude deviation + exceeds 5 degrees or if tank pressure drops below 90% of nominal. */ + @Rationale { + text = "Ensures a safe abort sequence if critical limits are violated."; + } + #refinement dependency 'CLR-R082' to FunctionalRequirementsPackage::'FLR-R006'; + } + + requirement def <'CLR-R083'> SeparationTimerPrecision { + doc /* Pyrotechnic separation events shall be triggered within 50 milliseconds of the + command issue to prevent re-contact. */ + @Rationale { + text = "Ensures clean separation of stages and modules."; + } + #refinement dependency 'CLR-R083' to FunctionalRequirementsPackage::'FLR-R014'; + } + + requirement def <'CLR-R084'> CabinPressureHold { + doc /* The crew cabin shall maintain a pressure leak rate of less than 0.1 psi per hour at a nominal pressure of 5.0 psi. */ + @Rationale { + text = "Defines the boundary for cabin integrity for crew survival in vacuum."; + } + #refinement dependency 'CLR-R084' to FunctionalRequirementsPackage::'FLR-R004'; + } + + requirement def <'CLR-R085'> TimingSynchError { + doc /* The master mission clock system shall maintain synchronization across all segments with a drift of less than 1ms per 24 hours. */ + @Rationale { + text = "Precise timing is required to synchronize thousands of events across ground and flight segments."; + } + #refinement dependency 'CLR-R085' to FunctionalRequirementsPackage::'FLR-R005'; + } + + requirement def <'CLR-R086'> EngineStartLatency { + doc /* The S-IC engine ignition sequence shall complete within 150ms of the authenticated launch command. */ + @Rationale { + text = "Timely ignition is critical to meet the planetary launch window and intended trajectory."; + } + #refinement dependency 'CLR-R086' to FunctionalRequirementsPackage::'FLR-R007'; + } + + requirement def <'CLR-R087'> StagingShockLimit { + doc /* Separation pyrotechnics shall not exceed a peak shock load of 50g on adjacent structural interfaces. */ + @Rationale { + text = "Limits mechanical stress on the second stage to prevent damage during first-stage jettison."; + } + #refinement dependency 'CLR-R087' to FunctionalRequirementsPackage::'FLR-R009'; + } + + requirement def <'CLR-R088'> CutoffDeltaVError { + doc /* Residual thrust from the S-IVB engine post-cutoff shall not exceed 0.05 m/s. */ + @Rationale { + text = "Precise termination of thrust is necessary to achieve stable Earth orbit insertion."; + } + #refinement dependency 'CLR-R088' to FunctionalRequirementsPackage::'FLR-R012'; + } + + requirement def <'CLR-R089'> CockpitDisplayRefresh { + doc /* Mission-critical flight displays in the CM cockpit shall have a minimum data refresh rate of 2 Hz. */ + @Rationale { + text = "Provides the crew with real-time situational awareness for manual intervention or aborts."; + } + #refinement dependency 'CLR-R089' to FunctionalRequirementsPackage::'FLR-R015'; + } + + requirement def <'CLR-R090'> TelemetrySamplingRate { + doc /* High-rate telemetry channels for engine health shall be sampled at a minimum of 100 samples per second. */ + @Rationale { + text = "High-fidelity data is needed for ground-based automated verification of propulsion health."; + } + #refinement dependency 'CLR-R090' to FunctionalRequirementsPackage::'FLR-R018'; + } + + requirement def <'CLR-R091'> PostTliSeparationVelocity { + doc /* The S-IVB auxiliary propulsion system shall provide a minimum delta-V of 1.0 m/s for post-TLI separation. */ + @Rationale { + text = "Ensures the spent third stage moves away from the spacecraft to prevent re-contact."; + } + #refinement dependency 'CLR-R091' to FunctionalRequirementsPackage::'FLR-R019'; + } + + requirement def <'CLR-R092'> SlaSeparationVelocity { + doc /* The SLA separation springs shall provide a minimum separation velocity of 0.3 meters per second. */ + @Rationale { + text = "Mechanical force is required to move the spacecraft away from the adapter for transposition."; + } + #refinement dependency 'CLR-R092' to FunctionalRequirementsPackage::'FLR-R021'; + } + + requirement def <'CLR-R093'> TranspositionManeuverRate { + doc /* The RCS shall provide a minimum angular acceleration of 2.0 deg/sec² for transposition maneuvers. */ + @Rationale { + text = "Defines the control authority needed to rotate the CM 180 degrees for docking."; + } + #refinement dependency 'CLR-R093' to FunctionalRequirementsPackage::'FLR-R022'; + } + + requirement def <'CLR-R094'> SextantAngularAccuracy { + doc /* The onboard sextant shall provide an angular measurement accuracy of +/- 10 arcseconds. */ + @Rationale { + text = "Required for precise celestial navigation fixes to update the state vector."; + } + #refinement dependency 'CLR-R094' to FunctionalRequirementsPackage::'FLR-R026'; + } + + requirement def <'CLR-R095'> StateVectorIntegrationLatency { + doc /* The navigation computer shall integrate new tracking data into the state vector within 500ms of receipt. */ + @Rationale { + text = "Minimizes latency in trajectory models for accurate course correction calculations."; + } + #refinement dependency 'CLR-R095' to FunctionalRequirementsPackage::'FLR-R027'; + } + + requirement def <'CLR-R096'> CommandTurnaroundLatency { + doc /* The MSFN ground stations shall maintain an uplink command turnaround latency of less than 2.0 seconds. */ + @Rationale { + text = "Fast turnaround is essential for ground controllers to react to time-sensitive anomalies."; + } + #refinement dependency 'CLR-R096' to FunctionalRequirementsPackage::'FLR-R033'; + } + + requirement def <'CLR-R097'> GroundStationSensitivity { + doc /* The Unified S-Band system shall have a minimum receiver sensitivity of -120 dBm. */ + @Rationale { + text = "Ensures weak signals from lunar distances are accurately tracked."; + } + #refinement dependency 'CLR-R097' to FunctionalRequirementsPackage::'FLR-R034'; + } + + requirement def <'CLR-R098'> RelayNetworkBitErrorRate { + doc /* The ground communication network shall maintain a Bit Error Rate (BER) of less than 10⁻⁶ across all relay sites. */ + @Rationale { + text = "High signal fidelity ensures voice and telemetry remain intelligible."; + } + #refinement dependency 'CLR-R098' to FunctionalRequirementsPackage::'FLR-R035'; + } + + requirement def <'CLR-R099'> TimelineDriftAlert { + doc /* The mission timeline management software shall trigger an alert if execution drifts more than 5 minutes from plan. */ + @Rationale { + text = "Maintains operational discipline for synchronized orbital events."; + } + #refinement dependency 'CLR-R099' to FunctionalRequirementsPackage::'FLR-R036'; + } + + requirement def <'CLR-R100'> SleepAcousticLimit { + doc /* Ambient noise levels in the crew sleep area shall be limited to 55 dBA. */ + @Rationale { + text = "Technical requirement for ensuring restorative crew sleep."; + } + #refinement dependency 'CLR-R100' to FunctionalRequirementsPackage::'FLR-R037'; + } + + requirement def <'CLR-R101'> TargetOrbitPerigee { + doc /* The LOI burn shall target a lunar orbit perigee of 60 +/- 5 nautical miles. */ + @Rationale { + text = "Achieving specific orbit parameters is critical for landing and rendezvous."; + } + #refinement dependency 'CLR-R101' to FunctionalRequirementsPackage::'FLR-R039'; + } + + requirement def <'CLR-R102'> HatchClearanceDimensions { + doc /* The LM crew transfer hatch shall provide a minimum clear opening of 32 x 32 inches. */ + @Rationale { + text = "Ensures astronauts in bulky suits can safely move between modules."; + } + #refinement dependency 'CLR-R102' to FunctionalRequirementsPackage::'FLR-R042'; + } + + requirement def <'CLR-R103'> LmComputerAlignmentTime { + doc /* The LM primary guidance computer shall be initialized and aligned within 60 minutes of activation. */ + @Rationale { + text = "Verifies configuration readiness before undocking."; + } + #refinement dependency 'CLR-R103' to FunctionalRequirementsPackage::'FLR-R043'; + } + + requirement def <'CLR-R104'> DockingLatchTorqueThreshold { + doc /* The LM docking latches shall require a minimum of 300 inch-pounds of torque to achieve a rigid seal. */ + @Rationale { + text = "Defines the mechanical requirement for securing the interface between vehicles."; + } + #refinement dependency 'CLR-R104' to FunctionalRequirementsPackage::'FLR-R044'; + } + + requirement def <'CLR-R105'> UndockingSeparationVelocity { + doc /* The undocking maneuver shall target a relative separation velocity of 0.1 +/- 0.05 meters per second. */ + @Rationale { + text = "Prevents re-contact between CSM and LM after separation."; + } + #refinement dependency 'CLR-R105' to FunctionalRequirementsPackage::'FLR-R045'; + } + + requirement def <'CLR-R106'> DskyDisplayBrightness { + doc /* The LM DSKY displays shall be readable under direct sunlight (minimum 500 nits brightness). */ + @Rationale { + text = "Necessary for reading landing data during the bright lunar day."; + } + #refinement dependency 'CLR-R106' to FunctionalRequirementsPackage::'FLR-R047'; + } + + requirement def <'CLR-R107'> LandingRadarLockTime { + doc /* The landing radar shall achieve frequency lock within 5 seconds of the Radar Enable command. */ + @Rationale { + text = "Rapid data acquisition is required to update altitude before final descent."; + } + #refinement dependency 'CLR-R107' to FunctionalRequirementsPackage::'FLR-R048'; + } + + requirement def <'CLR-R108'> PostLandingSafeTime { + doc /* The LM post-landing safe sequence shall complete within 60 seconds of touchdown. */ + @Rationale { + text = "Securing propulsion prevents hazardous pressure build-up on the surface."; + } + #refinement dependency 'CLR-R108' to FunctionalRequirementsPackage::'FLR-R051'; + } + + requirement def <'CLR-R109'> LmCabinIntegrityLeakRate { + doc /* The LM cabin integrity test shall confirm a leak rate of <= 0.05 psi/hour before EVA egress. */ + @Rationale { + text = "Ensures cabin can be re-pressurized before crew departs."; + } + #refinement dependency 'CLR-R109' to FunctionalRequirementsPackage::'FLR-R052'; + } + + requirement def <'CLR-R110'> SymbolicMountRigidity { + doc /* The flag assembly shall withstand a 10-Newton lateral deployment force without collapsing. */ + @Rationale { + text = "Quantitative requirement to ensure national symbol remains upright."; + } + #refinement dependency 'CLR-R110' to FunctionalRequirementsPackage::'FLR-R056'; + } + + requirement def <'CLR-R111'> SampleToolMechanicalAdvantage { + doc /* Lunar sample tongs shall provide a minimum 5:1 mechanical leverage for rock collection. */ + @Rationale { + text = "Compensates for reduced manual dexterity of EVA gloves."; + } + #refinement dependency 'CLR-R111' to FunctionalRequirementsPackage::'FLR-R057'; + } + + requirement def <'CLR-R112'> EasepThermalInsulation { + doc /* EASEP experiment packages shall utilize 20-layer aluminized Mylar for thermal insulation. */ + @Rationale { + text = "Protects instruments from extreme lunar thermal cycles."; + } + #refinement dependency 'CLR-R112' to FunctionalRequirementsPackage::'FLR-R059'; + } + + requirement def <'CLR-R113'> EvaCommunicationRange { + doc /* Astronaut radio systems shall maintain voice link at a maximum range of 500 meters from the LM. */ + @Rationale { + text = "Defines the technical boundary for safe astronaut travel on the surface."; + } + #refinement dependency 'CLR-R113' to FunctionalRequirementsPackage::'FLR-R061'; + } + + requirement def <'CLR-R114'> SurfaceTimelineSync { + doc /* Surface operations shall synchronize to UTC time with an accuracy of +/- 0.5 seconds. */ + @Rationale { + text = "Synchronization is vital for managing the timeline relative to the CSM orbit."; + } + #refinement dependency 'CLR-R114' to FunctionalRequirementsPackage::'FLR-R064'; + } + + requirement def <'CLR-R115'> LmAscentDeltaVMinimum { + doc /* The LM ascent stage shall provide a minimum delta-V of 1,850 m/s to achieve lunar orbit. */ + @Rationale { + text = "Specifies required propulsive performance to escape Moon gravity."; + } + #refinement dependency 'CLR-R115' to FunctionalRequirementsPackage::'FLR-R066'; + } + + requirement def <'CLR-R116'> RendezvousOrbitTarget { + doc /* The rendezvous radar shall target an orbital node within 5 km of the CSM. */ + @Rationale { + text = "Approach accuracy ensures vehicles are within terminal docking range."; + } + #refinement dependency 'CLR-R116' to FunctionalRequirementsPackage::'FLR-R068'; + } + + requirement def <'CLR-R117'> ReentryFlightPathAngle { + doc /* The CM reentry flight path angle shall be targeted at -6.5 degrees +/- 0.2 degrees. */ + @Rationale { + text = "Precise angle manages heating and prevents atmospheric skipping."; + } + #refinement dependency 'CLR-R117' to FunctionalRequirementsPackage::'FLR-R079'; + } +} \ No newline at end of file