Commit b4192cfa authored by Philip Makedonski's avatar Philip Makedonski
Browse files

+ added support for defaultTester and effectiveComponent operation, #116

* made TimerOperation.componentInstance optional
* add Variables to DataElementUse
* updated constraints and scope provider
parent a2e6d05e
Loading
Loading
Loading
Loading
+22 −4
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import org.etsi.mts.tdl.CastDataUse;
import org.etsi.mts.tdl.CollectionDataType;
import org.etsi.mts.tdl.ComponentInstance;
import org.etsi.mts.tdl.ComponentInstanceBinding;
import org.etsi.mts.tdl.ComponentInstanceRole;
import org.etsi.mts.tdl.Connection;
import org.etsi.mts.tdl.DataElementMapping;
import org.etsi.mts.tdl.DataElementUse;
@@ -388,6 +389,11 @@ public class TDLScopeProvider extends AbstractDeclarativeScopeProvider {
					} else if (dataElement instanceof StructuredDataType) {
						IScope scope = Scopes.scopeFor(((StructuredDataType)dataElement).allMembers());
						return scope;
					} else if (dataElement instanceof Variable) {
						if (((Variable) dataElement).getDataType() instanceof StructuredDataType) {
							IScope scope = Scopes.scopeFor(((StructuredDataType)((Variable) dataElement).getDataType()).allMembers());
							return scope;
						}
					} else if (dataElement == null) {
						//TODO: use more widely! Will save a lot of the code in here...
						//if reduction?
@@ -677,8 +683,8 @@ public class TDLScopeProvider extends AbstractDeclarativeScopeProvider {
//				}
//			}
			if (context instanceof VariableUse) {
				if (((VariableUse)context).getComponentInstance()!=null && ((VariableUse)context).getComponentInstance().getType()!=null) {
					IScope scope = Scopes.scopeFor(((VariableUse)context).getComponentInstance().getType().allVariables());
				if (((VariableUse)context).effectiveComponent()!=null && ((VariableUse)context).effectiveComponent().getType()!=null) {
					IScope scope = Scopes.scopeFor(((VariableUse)context).effectiveComponent().getType().allVariables());
					return scope;
				}
			}
@@ -689,8 +695,8 @@ public class TDLScopeProvider extends AbstractDeclarativeScopeProvider {
				}
			}
		} else if (reference.getEType().getInstanceClass() == Timer.class) {
			if (context instanceof TimerOperation && ((TimerOperation)context).getComponentInstance().getType()!=null) {
				IScope scope = Scopes.scopeFor(((TimerOperation)context).getComponentInstance().getType().allTimers());
			if (context instanceof TimerOperation && ((TimerOperation)context).effectiveComponent() != null && ((TimerOperation)context).effectiveComponent().getType()!=null) {
				IScope scope = Scopes.scopeFor(((TimerOperation)context).effectiveComponent().getType().allTimers());
				return scope;
			}
		} else if (context instanceof Extension) {
@@ -703,6 +709,7 @@ public class TDLScopeProvider extends AbstractDeclarativeScopeProvider {
			EList<EObject> elements = new BasicEList<>();
			elements.addAll(getScopedElementsOfType(context, MappableDataElement.class));
			elements.addAll(getContainerParameters((Element) context));
			elements.addAll(getAllTesterVariables((Element)context));
			//TODO: filter enums
//			if 
			if (!((InternalEObject) context).eIsSet(tdlPackage.DATA_ELEMENT_USE__DATA_ELEMENT)) {
@@ -762,6 +769,17 @@ public class TDLScopeProvider extends AbstractDeclarativeScopeProvider {
		return super.getScope(context, reference);
	}

	private List<Variable> getAllTesterVariables(Element context) {
		if (context.getParentTestDescription() == null) {
			return Collections.emptyList();
		}
		return context.getParentTestDescription().getTestConfiguration().getComponentInstance().stream()
			.filter(c->c.getRole() == ComponentInstanceRole.TESTER)
			.flatMap(c->c.getType().allVariables().stream())
			.toList()
			;
	}

	protected String getGateReferenceNameSeparator() {
		return ".";
	}
+38 −36
Original line number Diff line number Diff line
@@ -401,9 +401,11 @@ context FunctionCall
context VariableUse
  -- Local variables of tester components only
  inv VariableUseComponentRole ('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\'.' + self.toString()):
        self.componentInstance.type.allVariables()->includes(self.variable)  
          and self.componentInstance.role = ComponentInstanceRole::Tester
        self.effectiveComponent().oclIsUndefined() or self.effectiveComponent().type.allVariables()->includes(self.variable)  
          and self.effectiveComponent().role = ComponentInstanceRole::Tester
  
--applicable on 'LocalExpression', 'VariableUse', 'TimeOperation', and 'ActionBehaviour', 
--returns the 'ComponentInstance' specified for the element or the 'defaultTester' from the nearest containing 'Block' that has the 'defaultTester' specified.



@@ -519,7 +521,7 @@ context TimeConstraint
              ->union(self.timeConstraintExpression.argument)
              ->select(du | du.oclIsKindOf(VariableUse))
              ->forAll(du | self.container().oclAsType(Behaviour).getParticipatingComponents()->includes(
                  du.oclAsType(VariableUse).componentInstance))
                  du.oclAsType(VariableUse).effectiveComponent()))
  

  -- Use of local time labels only
@@ -539,13 +541,13 @@ context TimeOperation
  -- Component required in locally ordered test description
  inv TimeOperationComponent ('If the \'TimeOperation\' is contained in a locally ordered \'TestDescription\' then the \'componentInstance\' shall be specified.' + self.toString()):
        self.getParentTestDescription().isLocallyOrdered 
          implies not self.componentInstance.oclIsUndefined()
          implies not self.effectiveComponent().oclIsUndefined()
  

  -- Time operations on tester components only
  inv TimeOperationComponentRole ('A \'TimeOperation\' shall be performed only on a \'ComponentInstance\' in the role \'Tester\'.' + self.toString()):
        (not self.componentInstance.oclIsUndefined()
           and self.componentInstance.role = ComponentInstanceRole::Tester)
        (not self.effectiveComponent().oclIsUndefined()
           and self.effectiveComponent().role = ComponentInstanceRole::Tester)
      or (self.oclIsTypeOf(Quiescence)
           and not self.oclAsType(Quiescence).gateReference.oclIsUndefined()
           and self.oclAsType(Quiescence).gateReference.component.role = ComponentInstanceRole::Tester)
@@ -561,7 +563,7 @@ context TimeOperation
context Quiescence
  -- Exclusive use of gate reference or component instance
  inv QuiescenceTarget ('If a \'GateReference\' is provided, a \'ComponentInstance\' shall not be provided and vice versa.' + self.toString()):
        self.gateReference.oclIsUndefined() xor self.componentInstance.oclIsUndefined()
        self.gateReference.oclIsUndefined() xor self.effectiveComponent().oclIsUndefined()
  

  -- [Figure 7.3: Timer and timer operations]
@@ -570,7 +572,7 @@ context Quiescence
context TimerOperation
  -- Timer operations on tester components only
  inv TimerOperationComponentRole ('A \'TimerOperation\' shall be performed only on a \'ComponentInstance\' in the role \'Tester\'.' + self.toString()):
        self.componentInstance.role = ComponentInstanceRole::Tester
        self.effectiveComponent().oclIsUndefined() or self.effectiveComponent().role = ComponentInstanceRole::Tester
  


@@ -669,7 +671,7 @@ context Block
  inv GuardsForParticipatingComponents ('If the \'Block\' is contained in a locally ordered \'TestDescription\' then exactly one guard shall be specified for every participating \'ComponentInstance\' in the associated \'TestConfiguration\' that has the role \'Tester\' or there shall be no guards at all. ' + self.toString()):
        self.guard->size() = 0
          or self.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole::SUT)
              ->forAll(c | self.guard->one(ex | ex.componentInstance = c))
              ->forAll(c | self.guard->one(ex | ex.effectiveComponent() = c))
          or not self.getParentTestDescription().isLocallyOrdered
  

@@ -684,7 +686,7 @@ context LocalExpression
  -- Local expressions in locally ordered test descriptions have 'ComponentInstance' specified
  inv LocalExpressionComponent ('If the \'LocalExpression\' is contained in a locally ordered \'TestDescription\' then the componentInstance shall be specified. ' + self.toString()):
        self.getParentTestDescription().isLocallyOrdered 
          implies not self.componentInstance.oclIsUndefined()
          implies not self.effectiveComponent().oclIsUndefined()
  

  -- Only local variables and time labels in case of locally ordered test description
@@ -694,14 +696,14 @@ context LocalExpression
              ->union(self.expression.argument)
              ->including(self.expression)
              ->select(du | du.oclIsKindOf(VariableUse))
              ->forAll(du | du.oclAsType(VariableUse).componentInstance = self.componentInstance)
              ->forAll(du | du.oclAsType(VariableUse).effectiveComponent() = self.effectiveComponent())
          and self.expression.argument
              ->closure(a | a.dataUse.argument)->collect(pb | pb.dataUse)
              ->union(self.expression.argument)
              ->including(self.expression)
              ->select(du | du.oclIsKindOf(TimeLabelUse))
              ->forAll(du | du.oclAsType(TimeLabelUse).timeLabel.container().oclAsType(Behaviour)
                  .getParticipatingComponents()->includes(self.componentInstance))
                  .getParticipatingComponents()->includes(self.effectiveComponent()))
  


@@ -720,7 +722,7 @@ context BoundedLoopBehaviour
  -- Iteration count in locally ordered test descriptions
  inv  IterationCountsForParticipatingComponents ('If the \'BoundedLoopBehaviour\' is contained in a locally ordered \'TestDescription\' then a numIteration shall be specified for every participating \'ComponentInstance\' that has the role \'Tester\'.' + self.toString()):
        self.block.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole::SUT)
              ->forAll(c | self.numIteration->exists(ex | ex.componentInstance = c))
              ->forAll(c | self.numIteration->exists(ex | ex.effectiveComponent() = c))
          or not self.getParentTestDescription().isLocallyOrdered
  

@@ -775,8 +777,8 @@ context AlternativeBehaviour
        let initial = self.block.behaviour->first() in
          Set{}
          ->includingAll(initial->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component)
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance)
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance)
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).effectiveComponent())
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).effectiveComponent())
          ->size() = 1 or not self.getParentTestDescription().isLocallyOrdered
  

@@ -785,8 +787,8 @@ context AlternativeBehaviour
        let initial = self.block.behaviour->first(),
          targetComponent = Set{}
          ->includingAll(initial->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component)
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance)
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance),
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).effectiveComponent())
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).effectiveComponent()),
          nonOptionalBlocks = self.block->closure(
              b | b.behaviour->reject(oclIsKindOf(OptionalBehaviour))
                  ->select(oclIsKindOf(SingleCombinedBehaviour)).oclAsType(SingleCombinedBehaviour).block
@@ -804,8 +806,8 @@ context AlternativeBehaviour
        let initial = self.block.behaviour->first(),
          targetComponent = Set{}
          ->includingAll(initial->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component)
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance)
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance)
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).effectiveComponent())
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).effectiveComponent())
          in
          self.block.behaviour->select(oclIsKindOf(OptionalBehaviour))->isEmpty()
          or 
@@ -855,8 +857,8 @@ context ExceptionalBehaviour
        let initial = self.block.behaviour->first(),
          targetComponent = Set{}
          ->includingAll(initial->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component)
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance)
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance)
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).effectiveComponent())
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).effectiveComponent())
          in
          guardedComponent->includesAll(targetComponent)
          or not self.getParentTestDescription().isLocallyOrdered
@@ -867,8 +869,8 @@ context ExceptionalBehaviour
        let initial = self.block.behaviour->first(),
          targetComponent = Set{}
          ->includingAll(initial->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component)
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance)
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance),
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).effectiveComponent())
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).effectiveComponent()),
          nonOptionalBlocks = self.block->closure(
              b | b.behaviour->reject(oclIsKindOf(OptionalBehaviour))
                  ->select(oclIsKindOf(SingleCombinedBehaviour)).oclAsType(SingleCombinedBehaviour).block
@@ -886,8 +888,8 @@ context ExceptionalBehaviour
        let initial = self.block.behaviour->first(),
          targetComponent = Set{}
          ->includingAll(initial->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component)
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance)
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance)
          ->includingAll(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).effectiveComponent())
          -> includingAll(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).effectiveComponent())
          in
          self.block.behaviour->select(oclIsKindOf(OptionalBehaviour)).oclAsType(OptionalBehaviour)->forAll(op | op.block.behaviour->asSequence()
              ->first().oclAsType(Interaction).sourceGate.component->forAll(c | targetComponent->includes(c)))
@@ -905,7 +907,7 @@ context PeriodicBehaviour
  -- Period for each tester in locally ordered test descriptions
  inv PeriodForParticipatingComponents ('If the \'PeriodicBehaviour\' is contained in a locally ordered \'TestDescription\' then a period shall be specified for every \'ComponentInstance\' that has the role \'Tester\' and for which there is a behaviour in the contained \'Block\'. ' + self.toString()):
        self.block.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole::SUT)
              ->forAll(c | self.period->exists(ex | ex.componentInstance = c))
              ->forAll(c | self.period->exists(ex | ex.effectiveComponent() = c))
          or not self.getParentTestDescription().isLocallyOrdered
  

@@ -986,21 +988,21 @@ context Message
  -- Use of variables in the 'argument' specification
  inv MessageArgumentVariableUse ('The use of \'Variable\'s in the \'DataUse\' specification shall be restricted to \'Variable\'s of \'ComponentInstance\'s that participate in this \'Message\' via the provided \'GateReference\'s.' + self.toString()):
        (not self.argument.oclIsKindOf(VariableUse)
          or (self.sourceGate.component = self.argument.oclAsType(VariableUse).componentInstance
          or (self.sourceGate.component = self.argument.oclAsType(VariableUse).effectiveComponent()
          or self.target->exists(t | 
              t.targetGate.component = self.argument.oclAsType(VariableUse).componentInstance)))
              t.targetGate.component = self.argument.oclAsType(VariableUse).effectiveComponent())))
      
      and self.argument.argument->forAll(a |
              not a.dataUse.oclIsKindOf(VariableUse)
              or (self.sourceGate.component = a.dataUse.oclAsType(VariableUse).componentInstance
              or (self.sourceGate.component = a.dataUse.oclAsType(VariableUse).effectiveComponent()
              or self.target->exists(t | 
                  t.targetGate.component = a.dataUse.oclAsType(VariableUse).componentInstance)))
                  t.targetGate.component = a.dataUse.oclAsType(VariableUse).effectiveComponent())))
      
      and self.argument.argument->closure(a | a.dataUse.argument)->forAll(a |
              not a.dataUse.oclIsKindOf(VariableUse)
              or (self.sourceGate.component = a.dataUse.oclAsType(VariableUse).componentInstance
              or (self.sourceGate.component = a.dataUse.oclAsType(VariableUse).effectiveComponent()
              or self.target->exists(t | 
                  t.targetGate.component = a.dataUse.oclAsType(VariableUse).componentInstance)))
                  t.targetGate.component = a.dataUse.oclAsType(VariableUse).effectiveComponent())))
  

  -- Conforming data type for 'argument' and 'variable'
@@ -1044,7 +1046,7 @@ context ProcedureCall
        let source = self.sourceGate.component,
          affectingBehaviours = self.container().oclAsType(Block).behaviour
             ->reject(b | b.oclIsKindOf(ActionBehaviour)
                  and b.oclAsType(ActionBehaviour).componentInstance <> source)
                  and b.oclAsType(ActionBehaviour).effectiveComponent() <> source)
              ->reject(b | b.oclIsKindOf(Interaction)
                 and b.oclAsType(Interaction).sourceGate.component <> source
                 and b.oclAsType(Interaction).target->forAll(t | t.targetGate.component <> source))
@@ -1089,7 +1091,7 @@ context ProcedureCall
              ->closure(pb | pb.dataUse.argument)->union(self.argument)->collect(pb | pb.dataUse)
              ->select(du | du.oclIsKindOf(VariableUse))
              ->forAll(du | self.getParticipatingComponents()->includes(
                  du.oclAsType(VariableUse).componentInstance))
                  du.oclAsType(VariableUse).effectiveComponent()))
  

  -- Reply not starting event of exceptional behaviour
@@ -1192,12 +1194,12 @@ context ComponentInstanceBinding
context ActionBehaviour
  -- 'ActionBehaviour' on 'Tester' components only
  inv ActionBehaviourComponentRole ('The \'ComponentInstance\' that an \'ActionBehaviour\' refers to shall be of role \'Tester\'.' + self.toString()):
        self.componentInstance.oclIsUndefined() or self.componentInstance.role = ComponentInstanceRole::Tester
        self.effectiveComponent().oclIsUndefined() or self.effectiveComponent().role = ComponentInstanceRole::Tester
  

  -- Known 'componentInstance' with locally-ordered behaviour 
  inv ActionBehaviourComponentInstance ('The \'ComponentInstance\' that an \'ActionBehaviour\' refers to shall be specified if the \'ActionBehaviour\' is used within a locally-ordered \'TestDescription\'.' + self.toString()):
        not self.componentInstance.oclIsUndefined() or not self.getParentTestDescription().isLocallyOrdered
        not self.effectiveComponent().oclIsUndefined() or not self.getParentTestDescription().isLocallyOrdered
  


+44 −10

File changed.

Preview size limit exceeded, changes collapsed.

+26 −10
Original line number Diff line number Diff line
@@ -598,12 +598,19 @@ FormalParameterUse returns tdl::FormalParameterUse:
;

VariableUse returns tdl::VariableUse:
    componentInstance=[tdl::ComponentInstance|Identifier]
    '::' variable=[tdl::Variable|Identifier]
    componentInstance=[tdl::ComponentInstance|Identifier] '::' 
    variable=[tdl::Variable|Identifier]
    ParameterBindingFragment?
    // ReductionFragment now handled by PostfixExpression
;

//TODO: towards scoped components
VariableUseAssignment returns tdl::VariableUse:
    (componentInstance=[tdl::ComponentInstance|Identifier] '::')? 
    variable=[tdl::Variable|Identifier]
    ParameterBindingFragment?
;

PredefinedFunctionCall returns tdl::PredefinedFunctionCall:
    PredefinedFunctionCallSize
    | PredefinedFunctionCallNot
@@ -747,7 +754,7 @@ TimeOperation returns tdl::TimeOperation:
Wait returns tdl::Wait: 
    AtomicPrefixFragment
    'wait' 'for' period=DataUse
    ( 'on' componentInstance=[tdl::ComponentInstance|Identifier])
    ( 'on' componentInstance=[tdl::ComponentInstance|Identifier])?
;

Quiescence returns tdl::Quiescence: 
@@ -767,21 +774,27 @@ TimerOperation returns tdl::TimerOperation:

TimerStart returns tdl::TimerStart:
    AtomicPrefixFragment
    'start' componentInstance=[tdl::ComponentInstance|Identifier]
    '::' timer=[tdl::Timer|DeclName]
    //TODO: towards scoped components
    'start' 
    (componentInstance=[tdl::ComponentInstance|Identifier] '::')? 
    timer=[tdl::Timer|DeclName]
    'for' period=DataUse
;

TimerStop returns tdl::TimerStop:
    AtomicPrefixFragment
    'stop' componentInstance=[tdl::ComponentInstance|Identifier]
    '::' timer=[tdl::Timer|DeclName]
    //TODO: towards scoped components
    'stop' 
    (componentInstance=[tdl::ComponentInstance|Identifier] '::')? 
    timer=[tdl::Timer|DeclName]
;

TimeOut returns tdl::TimeOut:
    AtomicPrefixFragment
    'timeout' 'on' componentInstance=[tdl::ComponentInstance|Identifier]
    '::' timer=[tdl::Timer|DeclName]
    //TODO: towards scoped components
    'timeout' 'on' 
    (componentInstance=[tdl::ComponentInstance|Identifier] '::')? 
    timer=[tdl::Timer|DeclName]
;

//# Test Configuration
@@ -913,6 +926,7 @@ Block returns tdl::Block:
		->AnnotationFragment?
    	guard+=LocalExpression ( ',' guard+=LocalExpression)*
	']')?
	('on' defaultTester=[tdl::ComponentInstance|Identifier] ':')? 
    BEGIN
        behaviour+=Behaviour+
    END
@@ -921,6 +935,7 @@ Block returns tdl::Block:
// Block without guard support — used in contexts where '[' would be  ambiguous with CollectionItemFragment
NoGuardBlock returns tdl::Block:
    //NOTE: No annotations or comments
	('on' defaultTester=[tdl::ComponentInstance|Identifier] ':')? 
    BEGIN
        behaviour+=Behaviour+
    END
@@ -1212,7 +1227,8 @@ InlineAction returns tdl::InlineAction:

Assignment returns tdl::Assignment:
    AtomicPrefixFragment
    variable=VariableUse
    //TODO: towards scoped components -> collides with receive
    variable=VariableUseAssignment
    '=' expression=DataUse
;