Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
12cb8f6
#683 CifContext: add `isActivityRequirement` method
AndreaPuffo Feb 10, 2026
58705a8
#683 PokaYokeProfileValidator: allow activity requirement constraints
AndreaPuffo Feb 10, 2026
6fe4ef6
#683 PokaYokeProfileValidator: rename method
AndreaPuffo Feb 10, 2026
212a07b
#683 PokaYokeUmlProfileUtil, PokaYokeProfileValidator: rename stereotype
AndreaPuffo Feb 11, 2026
3bb41f9
#683 UmlToCifTranslator: update JavaDoc.
AndreaPuffo Feb 25, 2026
0fa177a
#683 CifContext: move method `isActivityRequirement`.
AndreaPuffo Feb 25, 2026
a468205
#683 CifContext, UmlToCifTranslator, PYProfileValidator: rename method
AndreaPuffo Feb 25, 2026
19fa69f
#683 CifContext: remove `isActivityRequirementConstraint`
AndreaPuffo Feb 25, 2026
6b5dc4d
#683 PokaYokeUmlProfileUtil: add `isRequirementConstraint` method
AndreaPuffo Feb 25, 2026
8a1f8c1
#683 PokaYokeProfileValidator, UmlToCifTranslator: use new method
AndreaPuffo Feb 25, 2026
ee430c6
#683 PokaYokeUmlProfileUtil: rename method.
AndreaPuffo Feb 25, 2026
3127da1
#683 PokaYokeProfileValidator: create set union before check.
AndreaPuffo Feb 25, 2026
5aa521f
#683 PokaYokeProfileValidator: rename method.
AndreaPuffo Feb 25, 2026
ab173a0
#683 PokaYokeProfileValidator: use scoped context.
AndreaPuffo Feb 25, 2026
549e163
#683 Apply suggestions from code review
AndreaPuffo Mar 9, 2026
8cd8aac
#683 PokaYokeProfileValidator: change variable name after review
AndreaPuffo Mar 9, 2026
f689a77
#683 PokaYokeUmlProfileUtil: move methods.
AndreaPuffo Mar 9, 2026
686be24
#683 PokaYokeUmlProfileUtil: rename methods.
AndreaPuffo Mar 9, 2026
281f185
#683 PokaYokeUmlProfileUtil: rename methods
AndreaPuffo Mar 9, 2026
1c52cc8
#683 PokaYokeUmlProfileUtil:
AndreaPuffo Mar 9, 2026
49a6a8e
#683 CifContext: remove `isPrimitiveTypeConstraint`
AndreaPuffo Mar 9, 2026
3312f5d
#683 CifContext: remove `isOccurrenceConstraint`
AndreaPuffo Mar 9, 2026
e623614
#683 CifContext: remove method to check activity pre/post condition
AndreaPuffo Mar 9, 2026
0487e95
#638 PokaYokeProfileValidator: update if-clause with new methods
AndreaPuffo Mar 10, 2026
2f63429
#638 PokaYokeUmlProfileUtil: add comment
AndreaPuffo Mar 10, 2026
f0ba3f0
#638 UmlToCifTranslator: reformat file
AndreaPuffo Mar 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1649,17 +1649,26 @@ private List<Invariant> createDisableEventsWhenDoneRequirements() {
}

/**
* Translates all UML class constraints that are in context to CIF requirement invariants.
* Translates all UML class constraints that are in context and all activity's constraints to CIF requirement
* invariants.
*
* @return The translated CIF requirement invariants.
*/
private List<Invariant> translateRequirements() {
List<Invariant> cifInvariants = new ArrayList<>();

// Translate class requirements.
for (Constraint umlConstraint: activity.getContext().getOwnedRules()) {
cifInvariants.addAll(translateRequirement(umlConstraint));
}

// Translate activity requirements.
for (Constraint umlConstraint: activity.getOwnedRules()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it sufficient to translate the requirements like this? Should we also include all requirements of other activities that we call, etc? (all other 'relevant' activities)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this to be consistent with the occurrence constraints: these are considered only during the activity synthesis, not when an activity is called. Better to have a conversation offline about this.

if (PokaYokeUmlProfileUtil.isRequirementConstraint(umlConstraint)) {
cifInvariants.addAll(translateRequirement(umlConstraint));
}
}

return cifInvariants;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public class PokaYokeUmlProfileUtil {

private static final String ST_FORMAL_CONSTRAINT = SynthMLPackage.Literals.FORMAL_CONSTRAINT.getName();

public static final String ST_CLASS_REQUIREMENT = SynthMLPackage.Literals.REQUIREMENT.getName();
public static final String ST_REQUIREMENT = SynthMLPackage.Literals.REQUIREMENT.getName();

public static final String ST_SYNTHESIS_PRECONDITION = SynthMLPackage.Literals.SYNTHESIS_PRECONDITION.getName();

Expand Down Expand Up @@ -112,8 +112,7 @@ public class PokaYokeUmlProfileUtil {
+ ST_FORMAL_CONSTRAINT;

/** Qualified name for the {@link Requirement} stereotype. */
public static final String REQUIREMENT_STEREOTYPE = POKA_YOKE_PROFILE + NamedElement.SEPARATOR
+ ST_CLASS_REQUIREMENT;
public static final String REQUIREMENT_STEREOTYPE = POKA_YOKE_PROFILE + NamedElement.SEPARATOR + ST_REQUIREMENT;

/** Qualified name for the {@link SynthesisPrecondition} stereotype. */
public static final String SYNTHESIS_PRECONDITION_STEREOTYPE = POKA_YOKE_PROFILE + NamedElement.SEPARATOR
Expand Down Expand Up @@ -528,8 +527,8 @@ public static List<Stereotype> getSupportedConstraintStereotypes(Constraint cons
getStereotype(constraint, ST_USAGE_PRECONDITION));
} else if (isPostconditionConstraint(constraint)) {
return List.of(getStereotype(constraint, ST_POSTCONDITION));
} else if (isClassRequirement(constraint)) {
return List.of(getStereotype(constraint, ST_CLASS_REQUIREMENT));
} else if (isClassRequirementConstraint(constraint)) {
return List.of(getStereotype(constraint, ST_REQUIREMENT));
} else {
return List.of();
}
Expand Down Expand Up @@ -564,12 +563,22 @@ public static boolean isUsagePrecondition(Constraint constraint) {
return appliedStereotypes.get(0).getName().equals(ST_USAGE_PRECONDITION);
}

public static boolean isRequirementConstraint(Constraint constraint) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move isPostconditionConstraint and isClassRequirement to just above isSynthesisPrecondition, to have methods with similar implementation close together?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are three methods for 'where' the constraint is (precondition/postcondition of activity, rule of a class/activity), and three methods about what kind (synthesis pre, usage pre, requirement).
I'm thinking the names could be clearer. Maybe:

  • isSynthesisPreconditionConstraint/isUsagePreconditionConstraint/isRequirementConstraint to just check the stereotype that is applied, more or less as we have now (but all end their name with Constraint).
  • isPreconditionConstraint/isPostconditionConstraint/isClassRequirementConstraint -> isContainedAsActivityPrecondition/isContainedAsActivityPostcondition/isContainedAsClassOrActivityOwnedRule to see where they are contained in the model. That distinguishes their names better.

List<Stereotype> appliedStereotypes = constraint.getAppliedStereotypes();

if (appliedStereotypes.isEmpty()) {
return false;
}

return appliedStereotypes.get(0).getName().equals(ST_REQUIREMENT);
}

private static boolean isPostconditionConstraint(Constraint constraint) {
return (constraint.eContainer() instanceof Activity activity)
&& activity.getPostconditions().contains(constraint);
}

private static boolean isClassRequirement(Constraint constraint) {
private static boolean isClassRequirementConstraint(Constraint constraint) {
return (constraint.eContainer() instanceof Classifier clazz) && clazz.getOwnedRules().contains(constraint);
}

Expand All @@ -592,7 +601,7 @@ public static void setConstraintStereotype(Constraint constraint, Stereotype ste
}

private static String getQualifiedStereotypeName(String stereotypeName) {
if (ST_CLASS_REQUIREMENT.equals(stereotypeName)) {
if (ST_REQUIREMENT.equals(stereotypeName)) {
return REQUIREMENT_STEREOTYPE;
} else if (ST_SYNTHESIS_PRECONDITION.equals(stereotypeName)) {
return SYNTHESIS_PRECONDITION_STEREOTYPE;
Expand All @@ -616,7 +625,7 @@ public static void setConstraintExpression(Constraint constraint, String newValu

public static String getStereotypeName(Stereotype st) {
// Returns a slightly better formatted name for the preconditions.
if (st.getName().equals(ST_CLASS_REQUIREMENT)) {
if (st.getName().equals(ST_REQUIREMENT)) {
return "Requirement";
} else if (st.getName().equals(ST_SYNTHESIS_PRECONDITION)) {
return "Synthesis precondition";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Stack;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.escet.cif.parser.ast.AInvariant;
import org.eclipse.escet.cif.parser.ast.automata.AAssignmentUpdate;
Expand Down Expand Up @@ -544,8 +545,15 @@ private void checkValidActivity(Activity activity) {
.filter(IntervalConstraint.class::isInstance).map(IntervalConstraint.class::cast)
.collect(Collectors.toCollection(LinkedHashSet::new));

if (!members.equals(Sets.union(preAndPostconditions, intervalConstraints))) {
error("Activity should contain only precondition, postcondition, and interval constraint members.",
Set<Constraint> activityRequirements = activity.getOwnedRules().stream()
.filter(r -> PokaYokeUmlProfileUtil.isRequirementConstraint(r)).map(Constraint.class::cast)
.collect(Collectors.toCollection(LinkedHashSet::new));

Set<Constraint> allowedConstraints = Stream.of(preAndPostconditions, intervalConstraints, activityRequirements)
.flatMap(Set::stream).collect(Collectors.toSet());

if (!members.equals(allowedConstraints)) {
error("Activity should contain only precondition, postcondition, constraints and interval constraint members.",
UMLPackage.Literals.NAMESPACE__MEMBER);
}

Expand Down Expand Up @@ -1003,8 +1011,10 @@ private void checkValidConstraint(Constraint constraint) {

if (CifContext.isActivityPrePostconditionConstraint(constraint)) {
checkValidActivityPrePostconditionConstraint(constraint);
} else if (CifContext.isClassConstraint(constraint)) {
checkValidClassConstraint(constraint);
} else if (CifContext.isClassConstraint(constraint)
|| (PokaYokeUmlProfileUtil.isRequirementConstraint(constraint)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it ever be a requirement constraint and not a class constraint? What constraints that we support are allowed in classes that are not requirements?
In other words, can't we only check for being a requirement constraint, as that also matches checkValidRequirementConstraint?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fixed with the new methods.

{
checkValidRequirementConstraint(constraint);
} else if (CifContext.isOccurrenceConstraint(constraint)) {
checkValidOccurrenceConstraint((IntervalConstraint)constraint);
} else if (CifContext.isPrimitiveTypeConstraint(constraint)) {
Expand Down Expand Up @@ -1058,7 +1068,7 @@ private void checkValidActivityPrePostconditionConstraint(Constraint constraint)
}
}

private void checkValidClassConstraint(Constraint constraint) {
private void checkValidRequirementConstraint(Constraint constraint) {
// Check that the constraint has the right stereotype applied.
List<Stereotype> stereotypes = constraint.getAppliedStereotypes();

Expand All @@ -1068,7 +1078,7 @@ private void checkValidClassConstraint(Constraint constraint) {
return;
}

if (!stereotypes.get(0).getName().equals(PokaYokeUmlProfileUtil.ST_CLASS_REQUIREMENT)) {
if (!stereotypes.get(0).getName().equals(PokaYokeUmlProfileUtil.ST_REQUIREMENT)) {
error(String.format("Constraint '%s' must have a requirement stereotype applied.", constraint.getName()),
UMLPackage.Literals.CONSTRAINT__SPECIFICATION);
return;
Expand All @@ -1080,7 +1090,7 @@ private void checkValidClassConstraint(Constraint constraint) {
}

try {
new CifTypeChecker(getGlobalContext(constraint)).checkInvariant(CifParserHelper.parseInvariant(constraint));
new CifTypeChecker(getScopedContext(constraint)).checkInvariant(CifParserHelper.parseInvariant(constraint));
} catch (RuntimeException e) {
error("Invalid invariant: " + e.getLocalizedMessage(), UMLPackage.Literals.CONSTRAINT__SPECIFICATION);
}
Expand Down