Commit ac2194c5 authored by Martti Käärik's avatar Martti Käärik
Browse files

Latest from part 1 + some EVL customisations in exporter.

parent 48304a52
Loading
Loading
Loading
Loading
Loading
+41 −58
Original line number Diff line number Diff line
@@ -195,15 +195,15 @@ context DataElementMapping {

  //All parameters shall be mapped
  constraint ParameterMappings {
    check:     (self.mappableDataElement.oclIsTypeOf(SimpleDataType)
    check:     (self.mappableDataElement.oclIsKindOf(SimpleDataType) or self.mappableDataElement.oclIsKindOf(DataInstance)
      or (self.mappableDataElement.oclIsTypeOf(StructuredDataType)
      and self.mappableDataElement.oclAsType(StructuredDataType).member->forAll(p | 
               self.parameterMapping->exists(m | m.parameter = p)))
      or (self.mappableDataElement.oclIsKindOf(Action) 
      and self.mappableDataElement.oclAsType(Action).formalParameter->forAll(p | 
               self.parameterMapping->exists(m | m.parameter = p)))
               self.parameterMapping->exists(m | m.parameter = p)) 
      and self.parameterMapping->forAll(p | 
               self.mappableDataElement.oclAsType(Action).formalParameter->includes(p.parameter)))
               self.mappableDataElement.oclAsType(Action).formalParameter->includes(p.parameter))))
    message:   self.prefix() + 
               "If the 'mappableDataElement' refers to a 'StructuredDataType', an 'Action' or a 'Function' definition, all the 'Parameters' contained in the 'mappableDataElement' shall be mapped."
  }
@@ -235,13 +235,20 @@ context SimpleDataInstance {
               "The inherited reference 'dataType' from 'DataInstance' shall refer to instances of 'SimpleDataType' solely."
  }

  //SimpleDataInstance container in EnumDataType
  constraint  EnumDataInstanceContainment {
    check:     not self.dataType.oclIsKindOf(EnumDataType) or self.eContainer() = self.dataType
    message:   self.prefix() + 
               "A 'SimpleDataInstance' whose 'dataType' property refers to an 'EnumDataType' shall be contained in that 'EnumDataType'."
  }

  //[Figure 6.3: Structured data type and instance]
}

context StructuredDataType {
  //Different member names in a structured data type
  constraint DistinguishableMemberNames {
    check:     self.allMembers()->isUnique(e | e.name)
    check:     self.allMembers()->collect(e | e.name).isUnique()
    message:   self.prefix() + 
               "All 'Member' names of a 'StructuredDataType' (including the names of inherited 'Members') shall be distinguishable."
  }
@@ -269,7 +276,7 @@ context StructuredDataInstance {

  //Unique assignments for each 'Member' of the 'StructuredDataType'
  constraint UniqueMemberAssignments {
    check:     self.memberAssignment->isUnique(m | m.member)
    check:     self.memberAssignment->collect(m | m.member).isUnique()
    message:   self.prefix() + 
               "There shall be at most one 'memberAssignment' for each 'Member' of the 'StructuredDataType' that the 'StructuredDataInstance', which contains this 'MemberAssignment', refers to."
  }
@@ -371,11 +378,6 @@ context ProcedureParameter {
  //[There are no constraints specified.]
}

context ParameterKind {
  //[There are no constraints specified.]
  //[Figure 6.6: Action, function, parameter and variable]
}

context Parameter {
  //[There are no constraints specified.]
}
@@ -396,25 +398,14 @@ context Function {
  //[There are no constraints specified.]
}

context UnassignedMemberTreatment {
  //[There are no constraints specified.]
}

context PredefinedFunction {
  //[There are no constraints specified.]
}

context EnumDataType {
  //SimpleDataInstance container in EnumDataType
  constraint  EnumDataInstanceContainment {
    check:     OclInvalid
    message:   self.prefix() + 
               "A 'SimpleDataInstance' whose 'dataType' property refers to an 'EnumDataType' shall be contained in that 'EnumDataType'."
  }

  //No extensions for EnumDataType
  constraint  EnumDataTypeExtensions {
    check:     OclInvalid
    check:     self.extension.oclIsUndefined()
    message:   self.prefix() + 
               "The 'extension' property of an 'EnumDataType' shall be empty."
  }
@@ -434,7 +425,7 @@ context DataUse {
    check:     not self.resolveDataType().oclIsKindOf(StructuredDataType)
      or self.reduction->isEmpty()
      or self.resolveDataType().oclAsType(StructuredDataType).allMembers()->includes(self.reduction->first().member)
      and self.reduction->select(m | self.reduction->indexOf(m) > 0)->forAll(m |
      and self.reduction->select(m | self.reduction->indexOf(m) > 1)->forAll(m |
              self.reduction->at(self.reduction->indexOf(m)-1).member.dataType.oclIsKindOf(StructuredDataType)
          and self.reduction->at(self.reduction->indexOf(m)-1).member.dataType.oclAsType(StructuredDataType).allMembers()
      ->includes(m.member))
@@ -508,7 +499,7 @@ context DataInstanceUse {

  //No 'item' if 'dataInstance' is specified
  constraint NoItemWithDataInstance {
    check:     not self.dataInstance.oclIsUndefined() and self.item->isEmpty()
    check:     not self.dataInstance.oclIsUndefined() implies self.item->isEmpty()
    message:   self.prefix() + 
               "The 'item' property shall be empty if the 'dataInstance' property is specified."
  }
@@ -560,7 +551,7 @@ context VariableUse {
  //Local variables of tester components only
  constraint VariableUseComponentRole {
    check:     self.componentInstance.type.allVariables()->includes(self.variable)  
          and self.componentInstance.role = ComponentInstanceRole::Tester
          and self.componentInstance.role = ComponentInstanceRole#Tester
    message:   self.prefix() + 
               "All variables used in a 'DataUse' specification via a 'VariableUse' shall be local to the same 'componentInstance' and the 'componentInstance' shall be in the role 'Tester'."
  }
@@ -605,9 +596,9 @@ context LiteralValueUse {
  //Integer type for integer value
  constraint LiteralValueIntType {
    check:     not self.intValue.oclIsUndefined() 
          implies (self.dataType.oclIsUndefined() or self.dataType.conformsTo('Integer'))
          implies (self.dataType.oclIsUndefined() or self.dataType.oclIsKindOf(Time) or self.dataType.conformsTo('Integer'))
    message:   self.prefix() + 
               "If 'intValue' is specified then the 'dataType' is either unspecified or the specified 'DataType' conforms to predefined type 'Integer'."
               "If 'intValue' is specified then the 'dataType' is either unspecified or the specified 'DataType' is instanceof of 'Time' or conforms to predefined type 'Integer'."
  }

  //Boolean type for Boolean value
@@ -734,10 +725,10 @@ context TimeOperation {
  //Time operations on tester components only
  constraint TimeOperationComponentRole {
    check:     (not self.componentInstance.oclIsUndefined()
           and self.componentInstance.role = ComponentInstanceRole::Tester)
           and self.componentInstance.role = ComponentInstanceRole#Tester)
      or (self.oclIsTypeOf(Quiescence)
           and not self.oclAsType(Quiescence).gateReference.oclIsUndefined()
           and self.oclAsType(Quiescence).gateReference.component.role = ComponentInstanceRole::Tester)
           and self.oclAsType(Quiescence).gateReference.component.role = ComponentInstanceRole#Tester)
    message:   self.prefix() + 
               "A 'TimeOperation' shall be performed only on a 'ComponentInstance' in the role 'Tester'."
  }
@@ -773,7 +764,7 @@ context Timer {
context TimerOperation {
  //Timer operations on tester components only
  constraint TimerOperationComponentRole {
    check:     self.componentInstance.role = ComponentInstanceRole::Tester
    check:     self.componentInstance.role = ComponentInstanceRole#Tester
    message:   self.prefix() + 
               "A 'TimerOperation' shall be performed only on a 'ComponentInstance' in the role 'Tester'."
  }
@@ -801,9 +792,9 @@ context TimeOut {
context GateType {
  //Compatible 'DataType's. 
  constraint GateType {
    check:     (self.kind = GateTypeKind::Procedure and self.allDataTypes()->forAll(t |
    check:     (self.kind = GateTypeKind#Procedure and self.allDataTypes()->forAll(t |
      t.oclIsTypeOf(ProcedureSignature)))
      or (self.kind = GateTypeKind::Message and self.allDataTypes()->forAll(t | t.oclIsTypeOf(StructuredDataType)
      or (self.kind = GateTypeKind#Message and self.allDataTypes()->forAll(t | t.oclIsTypeOf(StructuredDataType)
                  or t.oclIsKindOf(SimpleDataType) or t.oclIsTypeOf(CollectionDataType)))
    message:   self.prefix() + 
               "The 'DateType's specified for the 'GateType' shall correspond the kind of the 'GateType'. For 'GateType' of kind 'Procedure' only 'ProcedureSignature's shall be specified as data types. For 'GateType' of kind 'Message' only 'StructuredDataType's, 'SimpleDataType's and 'CollectionDataType's shall be specified as data types. "
@@ -811,10 +802,6 @@ context GateType {

}

context GateTypeKind {
  //[There are no constraints specified.]
}

context GateInstance {
  //[There are no constraints specified.]
}
@@ -828,10 +815,6 @@ context ComponentInstance {
  //[There are no constraints specified.]
}

context ComponentInstanceRole {
  //[There are no constraints specified.]
}

context GateReference {
  //Gate instance of the referred component instance
  constraint GateInstanceReference {
@@ -863,8 +846,8 @@ context Connection {
context TestConfiguration {
  //'TestConfiguration' and components roles
  constraint ComponentRoles {
    check:     self.componentInstance->exists(c | c.role = ComponentInstanceRole::Tester)
      and self.componentInstance->exists(c | c.role = ComponentInstanceRole::SUT)
    check:     self.componentInstance->exists(c | c.role = ComponentInstanceRole#Tester)
      and self.componentInstance->exists(c | c.role = ComponentInstanceRole#SUT)
    message:   self.prefix() + 
               "A 'TestConfiguration' shall contain at least one 'Tester' and one 'SUT' 'ComponentInstance'."
  }
@@ -880,7 +863,7 @@ context TestConfiguration {
  //Minimal 'TestConfiguration'
  constraint MinimalTestConfiguration {
    check:     self.connection->exists(c |
              c.endPoint.component.role->includesAll(Set{ComponentInstanceRole::SUT, ComponentInstanceRole::Tester}))
              c.endPoint.component.role->includesAll(Set{ComponentInstanceRole#SUT, ComponentInstanceRole#Tester}))
    message:   self.prefix() + 
               "Each 'TestConfiguration' shall specify at least one 'Connection' that connects a 'GateInstance' of a 'ComponentInstance' in the role 'Tester' with a 'GateInstance' of a 'ComponentInstance' in the role 'SUT'."
  }
@@ -888,10 +871,9 @@ context TestConfiguration {
  //At most one connection between any two 'GateInstance'/'ComponentInstance' pairs
  constraint UniqueConnections {
    check:     self.connection->forAll(c1 | self.connection->one(c2 |
              not c1.endPoint->reject(ep1 | c2.endPoint->any(ep2 |
              not c1.endPoint->reject(ep1 | not c2.endPoint->exists(ep2 |
                  ep1.component = ep2.component and ep1.gate = ep2.gate
              ) = null)->isEmpty()
      ))
              ))->isEmpty()))
    message:   self.prefix() + 
               "Given the set of 'Connection's contained in a 'TestConfiguration'. There shall be no two 'Connection's containing 'GateReference's that in turn refer to identical pairs of 'GateInstance'/'ComponentInstance'."
  }
@@ -928,7 +910,8 @@ context Block {

  //Guard for each participating tester in locally ordered test descriptions
  constraint GuardsForParticipatingComponents {
    check:     self.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole::SUT)
    check:     self.`guard`->size() = 0
          or self.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole#SUT)
              ->forAll(c | self.`guard`->exists(ex | ex.componentInstance = c))
          or not self.getParentTestDescription().isLocallyOrdered
    message:   self.prefix() + 
@@ -1003,7 +986,7 @@ context BoundedLoopBehaviour {

  //Iteration count in locally ordered test descriptions
  constraint  IterationCountsForParticipatingComponents {
    check:     self.block.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole::SUT)
    check:     self.block.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole#SUT)
              ->forAll(c | self.numIteration->exists(ex | ex.componentInstance = c))
          or not self.getParentTestDescription().isLocallyOrdered
    message:   self.prefix() + 
@@ -1029,7 +1012,7 @@ context OptionalBehaviour {
    check:     self.block.behaviour->first().oclIsKindOf(Interaction) 
      and self.block.behaviour->first().oclAsType(Interaction) 
              ->collect(i | i.sourceGate.component->union(i.target.targetGate.component))
              ->forAll(c | c.role = ComponentInstanceRole::Tester)
              ->forAll(c | c.role = ComponentInstanceRole#Tester)
    message:   self.prefix() + 
               "The block of an 'OptionalBehaviour' shall start with a tester-to-tester 'Interaction'. "
  }
@@ -1096,7 +1079,7 @@ context AlternativeBehaviour {
              ->union(b.behaviour->reject(oclIsKindOf(OptionalBehaviour))
                  ->select(oclIsKindOf(MultipleCombinedBehaviour)).oclAsType(MultipleCombinedBehaviour).block)
          );          targetComponent->includesAll(
              nonOptionalBlocks.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole::SUT))
              nonOptionalBlocks.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole#SUT))
          or not self.getParentTestDescription().isLocallyOrdered; }
    message:   self.prefix() + 
               "If the 'AlternativeBehaviour' is contained in a locally ordered 'TestDescription' then no other tester 'ComponentInstance' shall participate in any block than the target of the first tester-input event and 'ComponentInstance's participating in blocks of contained 'OptionalBehaviour's. "
@@ -1156,7 +1139,7 @@ context ExceptionalBehaviour {

  //Guarded component shall be a 'Tester' component
  constraint ExceptionalGuardedComponent {
    check:     self.guardedComponent.oclIsUndefined() or self.guardedComponent.role = ComponentInstanceRole::Tester
    check:     self.guardedComponent.oclIsUndefined() or self.guardedComponent.role = ComponentInstanceRole#Tester
    message:   self.prefix() + 
               "The 'guardedComponent' shall refer to a 'ComponentInstance' with the role of 'Tester'."
  }
@@ -1186,7 +1169,7 @@ context ExceptionalBehaviour {
              ->union(b.behaviour->reject(oclIsKindOf(OptionalBehaviour))
                  ->select(oclIsKindOf(MultipleCombinedBehaviour)).oclAsType(MultipleCombinedBehaviour).block)
          );          targetComponent->includesAll(
              nonOptionalBlocks.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole::SUT))
              nonOptionalBlocks.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole#SUT))
          or not self.getParentTestDescription().isLocallyOrdered; }
    message:   self.prefix() + 
               "If the 'ExceptionalBehaviour' is contained in a locally ordered 'TestDescription' then no other tester 'ComponentInstance' shall participate in any block than the target of the first tester-input event and 'ComponentInstance's participating in blocks of contained 'OptionalBehaviour's . "
@@ -1225,7 +1208,7 @@ context PeriodicBehaviour {

  //Period for each tester in locally ordered test descriptions
  constraint PeriodForParticipatingComponents {
    check:     self.block.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole::SUT)
    check:     self.block.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole#SUT)
              ->forAll(c | self.period->exists(ex | ex.componentInstance = c))
          or not self.getParentTestDescription().isLocallyOrdered
    message:   self.prefix() + 
@@ -1293,7 +1276,7 @@ context Assertion {

  //No 'SpecialValueUse'
  constraint AssertionNoSpecialValueUse {
    check:     not self.otherwise.oclIsKindOf(SpecialValueUse)
    check:     self.otherwise.oclIsUndefined() or not self.otherwise.oclIsKindOf(SpecialValueUse)
    message:   self.prefix() + 
               "The 'otherwise' shall not evaluate to an instance of a 'SpecialValueUse'."
  }
@@ -1442,9 +1425,9 @@ context ProcedureCall {

  //Matching procedure arguments
  constraint ProcedureCallArguments {
    check:     (self.replyTo.oclIsUndefined() and self.signature.parameter->select(p | p.kind = ParameterKind::In)
    check:     (self.replyTo.oclIsUndefined() and self.signature.parameter->select(p | p.kind = ParameterKind#In)
              ->forAll(p | self.argument.parameter->includes(p)))
          or (not self.replyTo.oclIsUndefined() and self.signature.parameter->reject(p | p.kind = ParameterKind::In)
          or (not self.replyTo.oclIsUndefined() and self.signature.parameter->reject(p | p.kind = ParameterKind#In)
              ->forAll(p | self.argument.parameter->includes(p)))
    message:   self.prefix() + 
               "For a 'ProcedureCall' with empty 'replyTo' there shall be one 'ParameterBinding' instance in the 'argument' for each 'ProcedureParameter' with kind 'In' in the associated 'ProcedureSignature'. For a 'ProcedureCall' with 'replyTo' there shall be one 'ParameterBinding' instance in the 'argument' for each 'ProcedureParameter' with kind 'Out' or 'Exception' in the associated 'ProcedureSignature'. "
@@ -1481,7 +1464,7 @@ context Target {

  //Variable of a tester component only
  constraint TargetVariableComponentRole {
    check:     self.valueAssignment->isEmpty () or self.targetGate.component.role = ComponentInstanceRole::Tester
    check:     self.valueAssignment->isEmpty () or self.targetGate.component.role = ComponentInstanceRole#Tester
    message:   self.prefix() + 
               "If a 'ValueAssignment' is specified, the 'ComponentInstance' referenced by 'targetGate' shall be in the role 'Tester'."
  }
@@ -1586,7 +1569,7 @@ context ComponentInstanceBinding {
context ActionBehaviour {
  //'ActionBehaviour' on 'Tester' components only
  constraint ActionBehaviourComponentRole {
    check:     self.componentInstance.oclIsUndefined() or self.componentInstance.role = ComponentInstanceRole::Tester
    check:     self.componentInstance.oclIsUndefined() or self.componentInstance.role = ComponentInstanceRole#Tester
    message:   self.prefix() + 
               "The 'ComponentInstance' that an 'ActionBehaviour' refers to shall be of role 'Tester'."
  }
+15 −16
Original line number Diff line number Diff line
@@ -133,15 +133,15 @@ context DataElementMapping

  -- All parameters shall be mapped
  inv ParameterMappings ('If the \'mappableDataElement\' refers to a \'StructuredDataType\', an \'Action\' or a \'Function\' definition, all the \'Parameters\' contained in the \'mappableDataElement\' shall be mapped.' + self.toString()):
        (self.mappableDataElement.oclIsTypeOf(SimpleDataType)
        (self.mappableDataElement.oclIsKindOf(SimpleDataType) or self.mappableDataElement.oclIsKindOf(DataInstance)
      or (self.mappableDataElement.oclIsTypeOf(StructuredDataType)
      and self.mappableDataElement.oclAsType(StructuredDataType).member->forAll(p | 
               self.parameterMapping->exists(m | m.parameter = p)))
      or (self.mappableDataElement.oclIsKindOf(Action) 
      and self.mappableDataElement.oclAsType(Action).formalParameter->forAll(p | 
               self.parameterMapping->exists(m | m.parameter = p)))
               self.parameterMapping->exists(m | m.parameter = p)) 
      and self.parameterMapping->forAll(p | 
               self.mappableDataElement.oclAsType(Action).formalParameter->includes(p.parameter)))
               self.mappableDataElement.oclAsType(Action).formalParameter->includes(p.parameter))))
  


@@ -152,6 +152,11 @@ context SimpleDataInstance
        self.dataType.oclIsKindOf(SimpleDataType)
  

  -- SimpleDataInstance container in EnumDataType
  inv  EnumDataInstanceContainment ('A \'SimpleDataInstance\' whose \'dataType\' property refers to an \'EnumDataType\' shall be contained in that \'EnumDataType\'.' + self.toString()):
        not self.dataType.oclIsKindOf(EnumDataType) or self.oclContainer() = self.dataType
  

  -- [Figure 6.3: Structured data type and instance]


@@ -249,14 +254,9 @@ context CollectionDataInstance


context EnumDataType
  -- SimpleDataInstance container in EnumDataType
  inv  EnumDataInstanceContainment ('A \'SimpleDataInstance\' whose \'dataType\' property refers to an \'EnumDataType\' shall be contained in that \'EnumDataType\'.' + self.toString()):
        OclInvalid
  

  -- No extensions for EnumDataType
  inv  EnumDataTypeExtensions ('The \'extension\' property of an \'EnumDataType\' shall be empty.' + self.toString()):
        OclInvalid
        self.extension.oclIsUndefined()
  


@@ -272,7 +272,7 @@ context DataUse
        not self.resolveDataType().oclIsKindOf(StructuredDataType)
      or self.reduction->isEmpty()
      or self.resolveDataType().oclAsType(StructuredDataType).allMembers()->includes(self.reduction->first().member)
      and self.reduction->select(m | self.reduction->indexOf(m) > 0)->forAll(m |
      and self.reduction->select(m | self.reduction->indexOf(m) > 1)->forAll(m |
              self.reduction->at(self.reduction->indexOf(m)-1).member.dataType.oclIsKindOf(StructuredDataType)
          and self.reduction->at(self.reduction->indexOf(m)-1).member.dataType.oclAsType(StructuredDataType).allMembers()
      ->includes(m.member))
@@ -326,7 +326,7 @@ context DataInstanceUse

  -- No 'item' if 'dataInstance' is specified
  inv NoItemWithDataInstance ('The \'item\' property shall be empty if the \'dataInstance\' property is specified.' + self.toString()):
        not self.dataInstance.oclIsUndefined() and self.item->isEmpty()
        not self.dataInstance.oclIsUndefined() implies self.item->isEmpty()
  


@@ -384,9 +384,9 @@ context LiteralValueUse
  

  -- Integer type for integer value
  inv LiteralValueIntType ('If \'intValue\' is specified then the \'dataType\' is either unspecified or the specified \'DataType\' conforms to predefined type \'Integer\'.' + self.toString()):
  inv LiteralValueIntType ('If \'intValue\' is specified then the \'dataType\' is either unspecified or the specified \'DataType\' is instanceof of \'Time\' or conforms to predefined type \'Integer\'.' + self.toString()):
        not self.intValue.oclIsUndefined() 
          implies (self.dataType.oclIsUndefined() or self.dataType.conformsTo('Integer'))
          implies (self.dataType.oclIsUndefined() or self.dataType.oclIsKindOf(Time) or self.dataType.conformsTo('Integer'))
  

  -- Boolean type for Boolean value
@@ -574,8 +574,7 @@ context TestConfiguration
        self.connection->forAll(c1 | self.connection->one(c2 |
              not c1.endPoint->reject(ep1 | not c2.endPoint->exists(ep2 |
                  ep1.component = ep2.component and ep1.gate = ep2.gate
              ))->isEmpty()
      ))
              ))->isEmpty()))
  


@@ -875,7 +874,7 @@ context Assertion

  -- No 'SpecialValueUse'
  inv AssertionNoSpecialValueUse ('The \'otherwise\' shall not evaluate to an instance of a \'SpecialValueUse\'.' + self.toString()):
        not self.otherwise.oclIsKindOf(SpecialValueUse)
        self.otherwise.oclIsUndefined() or not self.otherwise.oclIsKindOf(SpecialValueUse)
  

  -- [Figure 9.5: Interaction behaviour]
+14 −1
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -118,11 +119,17 @@ public class ConstraintExporter {
			return getEvlConstraint(cx);
	}

	//TODO:  enums shall be excluded
	Collection<Object> ignoreClasses = Arrays.asList("ParameterKind", "UnassignedMemberTreatment", "GateTypeKind", "ComponentInstanceRole");
	Pattern letPattern = Pattern.compile("\\s*let(.+?)\\s*in\\s(.*)", Pattern.DOTALL);
	Pattern isUniquePattern = Pattern.compile("->isUnique\\((.+?)\\)", Pattern.DOTALL);
	Pattern wsPattern = Pattern.compile("(\\s*)(.*)", Pattern.DOTALL);

	private String getEvlConstraint(Content cx) {
		String content = "context " + cx.getParent().getText().replaceAll(".+\\s", "") + " {" + "\n";
		String className = cx.getParent().getText().replaceAll(".+\\s", "");
		if (ignoreClasses.contains(className))
			return "";
		String content = "context " + className + " {" + "\n";
		for (Content cs : cx.getContent()) {
			var lines = Arrays.asList(cs.getText().split("\n"));
			var idIndex = 2;
@@ -145,6 +152,8 @@ public class ConstraintExporter {
				var id = lines.get(idIndex).replaceAll("inv: ", "").replaceAll(":", "");
				var ocl = String.join("\n      ", lines.subList(idIndex + 1, lines.size()))
						.replaceAll("(import|function|guard)([\\W])", "`$1`$2")
						.replaceAll("::", "#")
						.replaceAll("oclContainer", "eContainer")
				// .replaceAll("\\s+", " ")
				;

@@ -175,6 +184,10 @@ public class ConstraintExporter {
					ocl += " }";
				}

				Matcher m2 = isUniquePattern.matcher(ocl);
				// Use . not -> otherwise Epsilon won't execute imported operation
				ocl = m2.replaceAll("->collect($1).isUnique()");

				content += "  //" + title + "\n";
				content += "  constraint " + id + " {" + "\n";
				content += "    check" + (isStatementBlock ? " " : ": ") + ocl + "\n";
+1622 −0

File added.

Preview size limit exceeded, changes collapsed.

+4 −0
Original line number Diff line number Diff line
@@ -37,6 +37,10 @@ operation String size() : Integer {
	return self.length();
}

operation Any isUnique(): Boolean {
	return self.forAll(v1 | self.select(v2 | v1 == v2).size() == 1);
}

//TODO: is it possible to define custom predicated operations?
//operation Collection isUnique() : Boolean {
//    return not self.isEmpty();
Loading