| -- @atlcompiler emftvm |
| -- @path ATL=/org.eclipse.m2m.atl.common/model/ATL.ecore |
| -- @path Problem=/org.eclipse.m2m.atl.common/model/Problem.ecore |
| module ATLWFR; |
| create OUT : Problem from IN : ATL; |
| |
| ------------------------------------------------------------------------------- |
| -- HELPERS -------------------------------------------------------------------- |
| ------------------------------------------------------------------------------- |
| |
| -- This helper provides a set containing the name of the IteratorExp elements |
| -- that accepts a single Iterator. |
| -- CONTEXT: thisModule |
| -- RETURN: Set(String) |
| helper def: singleIteratorExps : Set(String) = |
| Set{ |
| 'isUnique', 'any', 'one', 'collect', 'select', |
| 'reject', 'collectNested', 'sortedBy' |
| }; |
| |
| -- This helper provides a set containing the name of the IteratorExp elements |
| -- for which several Iterators may be declared according to the OCL spec. |
| -- CONTEXT: thisModule |
| -- RETURN: Set(String) |
| helper def: multiIteratorExps : Set(String) = Set{'exists', 'forAll'}; |
| |
| |
| -- This helper computes the set of existing CollectionType elements within the |
| -- input ATL Unit. |
| -- CONTEXT: thisModule |
| -- RETURN: Set(ATL!CollectionType) |
| helper def: collectionTypes : Set(ATL!CollectionType) = |
| ATL!CollectionType.allInstances(); |
| |
| |
| -- This helper computes a sequence containing all the OclModel elements that |
| -- are used in the input ATL Unit. |
| -- CONTEXT: thisModule |
| -- RETURN: Sequence(ATL!OclModel) |
| helper def: allModels : Set(ATL!OclModel) = |
| let atlModules : Sequence(ATL!Module) = |
| ATL!Module.allInstances() |
| in |
| if atlModules->notEmpty() then |
| atlModules->iterate(m; acc : Set(ATL!OclModel) = Set{} | |
| acc->union(m.inModels->asSet())->union(m.outModels->asSet())) |
| else |
| Set{} |
| endif; |
| |
| -- This helper computes the Query element that corresponds to the input ATL |
| -- Unit. If the input ATL Unit corresponds to a Module (eg a transformation), |
| -- the computed value is OclUndefined. |
| -- CONTEXT: thisModule |
| -- RETURN: ATL!Query |
| helper def: queryElt : ATL!Query = |
| let atlQueries : Sequence(ATL!Query) = ATL!Query.allInstances() in |
| if atlQueries->isEmpty() then OclUndefined else atlQueries->first() endif; |
| |
| |
| -- This helper computes a sequence containing all the Binding elements that |
| -- are defined in the input ATL Unit. |
| -- CONTEXT: thisModule |
| -- RETURN: Sequence(ATL!Binding) |
| helper def: allBindings : Sequence(ATL!Binding) = |
| ATL!Binding.allInstances()->asSequence(); |
| |
| |
| -- This helper computes a sequence containing all the Pattern elements that |
| -- are defined in the input ATL Unit. |
| -- CONTEXT: thisModule |
| -- RETURN: Sequence(ATL!InPattern) |
| helper def: allInPatterns : Sequence(ATL!InPattern) = |
| ATL!InPattern.allInstances()->asSequence(); |
| |
| |
| -- This helper computes a sequence containing all the InPatternElement elements |
| -- that are defined in the input ATL Unit. |
| -- CONTEXT: thisModule |
| -- RETURN: Sequence(ATL!InPatternElement) |
| helper def: allInPatternElts : Sequence(ATL!InPatternElement) = |
| ATL!InPatternElement.allInstances()->asSequence(); |
| |
| |
| -- This helper computes a sequence containing all the OutPatternElement |
| -- elements that are defined in the input ATL Unit. |
| -- CONTEXT: thisModule |
| -- RETURN: Sequence(ATL!OutPatternElement) |
| helper def: allOutPatternElts : Sequence(ATL!OutPatternElement) = |
| ATL!OutPatternElement.allInstances()->asSequence(); |
| |
| |
| -- This helper computes a sequence containing all the Rule elements that are |
| -- defined in the input ATL Unit. If the input Unit is a query, the computed |
| -- sequence is empty. |
| -- CONTEXT: thisModule |
| -- RETURN: Sequence(ATL!Rule) |
| helper def: allRules : Sequence(ATL!Rule) = |
| ATL!Rule.allInstances()->asSequence(); |
| |
| |
| -- This helper computes a sequence containing all the Helper elements that are |
| -- defined in the input ATL Unit. |
| -- CONTEXT: thisModule |
| -- RETURN: Sequence(ATL!Helper) |
| helper def: allHelpers : Sequence(ATL!Helper) = |
| ATL!Helper.allInstances()->asSequence(); |
| |
| |
| -- This helper computes a sequence containing all the LoopExp elements that are |
| -- defined in the input ATL Unit. |
| -- CONTEXT: thisModule |
| -- RETURN: Sequence(ATL!LoopExp) |
| helper def: allLoopExps : Sequence(ATL!LoopExp) = |
| ATL!LoopExp.allInstances()->asSequence(); |
| |
| |
| -- This helper computes a sequence containing all the IterateExp elements that |
| -- are defined in the input ATL Unit. |
| -- CONTEXT: thisModule |
| -- RETURN: Sequence(ATL!IterateExp) |
| helper def: allIterateExps : Sequence(ATL!IterateExp) = |
| ATL!IterateExp.allInstances()->asSequence(); |
| |
| |
| -- This helper computes a sequence containing all the VariableDeclaration |
| -- elements that are associated with the contextual Rule. These declarations |
| -- can be of 3 different kinds: |
| -- * the variables declared for the rule; |
| -- * the OutPatternElements of the rule; |
| -- * the InPatternElements of the rule if this last is a MatchedRule. |
| -- CONTEXT: ATL!Rule |
| -- RETURN: Sequence(ATL!VariableDeclaration) |
| helper context ATL!Rule |
| def: namedElements : Sequence(ATL!VariableDeclaration) = |
| Sequence{ |
| if self.oclIsTypeOf(ATL!MatchedRule) |
| then |
| if not self.inPattern.oclIsUndefined() then |
| self.inPattern.elements->asSequence() |
| else |
| Sequence{} |
| endif |
| else |
| Sequence{} |
| endif, |
| self.variables->asSequence(), |
| if not self.outPattern.oclIsUndefined() then |
| self.outPattern.elements->asSequence() |
| else |
| Sequence{} |
| endif |
| }->flatten(); |
| |
| |
| -- This helper computes the Rule element in which the contextual PatterElement |
| -- is declared. This is achieved by returning the Rule referred by the "rule" |
| -- reference of the Pattern that conatins the contexual PatternElement. This |
| -- last one is accessed through the "outPattern" reference if the contextual |
| -- PatternElement is an OutPatternElement, throught the "inPattern" if it is |
| -- an InPatternElement. |
| -- CONTEXT: ATL!PatternElement |
| -- RETURN: ATL!Rule |
| helper context ATL!PatternElement def: "rule" : ATL!Rule = |
| if self.oclIsKindOf(ATL!OutPatternElement) |
| then |
| self.outPattern."rule" |
| else |
| self.inPattern."rule" |
| endif; |
| |
| -- This helper computes a sequence containing the VariableDeclarations that |
| -- precede the contextual VariableDeclaration in its namespace. |
| -- If the contextual VariableDeclaration is a PatternElement, the helper only |
| -- returns this VD. |
| -- Otherwise, it computes the container of the contextual VD. If the container |
| -- is a LetExp, it returns a Sequence composed of the VD, and the results of |
| -- the calls of the getUpD helper on the calculated container. |
| -- If the container is an IteratorExp, the helper returns a Sequence composed |
| -- of the VD and the results of the call of getUpD on the computed container. |
| -- If the container is an IterateExp, the helper a Sequence containing the same |
| -- elements that the one computed for an IteratorExp. |
| -- Otherwise, the helper returns the only contextual VD as default value. |
| -- CONTEXT: ATL!VariableDeclaration |
| -- RETURN: Sequence(ATL!VariableDeclaration) |
| helper context ATL!VariableDeclaration |
| def: getDeclarations() : Sequence(ATL!VariableDeclaration) = |
| if self.oclIsKindOf(ATL!PatternElement) |
| then |
| Sequence{self} |
| else |
| let container : OclAny = self.refImmediateComposite() in |
| if container.oclIsTypeOf(ATL!LetExp) |
| then |
| Sequence{ |
| self, |
| container.getUpD() |
| }->flatten() |
| else |
| if container.oclIsTypeOf(ATL!IteratorExp) |
| then |
| Sequence{ |
| self, |
| container.getUpD() |
| }->flatten() |
| else |
| if container.oclIsTypeOf(ATL!IterateExp) |
| then |
| Sequence{ |
| self, |
| container.getUpD() |
| }->flatten() |
| else |
| Sequence{ |
| self |
| }->flatten() |
| endif |
| endif |
| endif |
| endif; |
| |
| |
| -- This helper computes a sequence containing the VariableDeclarations that are |
| -- defined higher than the contextual OclExpression in its namespace tree. |
| -- The helper first computes the container of the contextual OclExp. If this |
| -- container is undefined, it retuns an empty sequence. |
| -- Otherwise, if this container is not an OclExpression: |
| -- * If the container is a RuleVariableDeclaration, the helper returns a |
| -- sequence containing all the named elements of the rule that contains this |
| -- InPattern. |
| -- * If the container is a Binding, the helper returns a sequence containing |
| -- all the named elements of the rule that contains this Binding. |
| -- Otherwise, if the computed container is an OclExpression: |
| -- * If the container is a LetExp, the helper returns a sequence composed of |
| -- the LetExp variable and the result of its recursive call on the LetExp. |
| -- * If the container is an IfExp, the helper returns a sequence composed of |
| -- the result of its recursive call on the IfExp. |
| -- * If the container is an IteratorExp, if the contextual OclExp is the |
| -- source of the IteratorExp then the helper returns the result of its |
| -- recursive call on the IteratorExp, else it returns this result with the |
| -- "iterators" elements of the IteratorExp. |
| -- * If the container is an IterateExp, the helper returns the same sequences |
| -- that for an IteratorExp, with the additional "result" element in case the |
| -- contextual OclExp is not the source of the IterateExp. |
| -- Otherwise, the helper returns an empty sequence as default value. |
| -- CONTEXT: ATL!OclExpression |
| -- RETURN: Sequence(ATL!VariableDeclaration) |
| helper context ATL!OclExpression |
| def: getUpD() : Sequence(ATL!VariableDeclaration) = |
| let container : ATL!Element = self.refImmediateComposite() in |
| if container.oclIsUndefined() then |
| Sequence{} |
| else if not container.oclIsKindOf(ATL!OclExpression) then |
| if container.oclIsTypeOf(ATL!RuleVariableDeclaration) |
| then |
| Sequence{ |
| container."rule".namedElements |
| }->flatten() |
| else |
| if container.oclIsTypeOf(ATL!Binding) |
| then |
| Sequence{ |
| container.outPatternElement."rule".namedElements |
| }->flatten() |
| else |
| Sequence{} |
| endif |
| endif |
| else if container.oclIsTypeOf(ATL!LetExp) then |
| Sequence{ |
| container.variable, |
| container.getUpD() |
| }->flatten() |
| else if container.oclIsTypeOf(ATL!IfExp) then |
| Sequence{ |
| container.getUpD() |
| }->flatten() |
| else if container.oclIsTypeOf(ATL!IteratorExp) then |
| if container.source = self |
| then |
| Sequence{ |
| container.getUpD() |
| }->flatten() |
| else |
| Sequence{ |
| container.iterators, |
| container.getUpD() |
| }->flatten() |
| endif |
| else if container.oclIsTypeOf(ATL!IterateExp) then |
| if container.source = self |
| then |
| Sequence{ |
| container.getUpD() |
| }->flatten() |
| else |
| Sequence{ |
| container.iterators, |
| container.result, |
| container.getUpD() |
| }->flatten() |
| endif |
| else Sequence{} |
| endif endif endif endif endif endif; |
| |
| |
| -- This helper computes a sequence containing the VariableDeclarations that are |
| -- defined lower than the contextual OclExpression in its namespace tree. |
| -- If the contextual OclExpression is a LetExp, the helper returns a sequence |
| -- composed of the LetExp variable and the result of its recursive call on the |
| -- "in_" reference of the LetExp. |
| -- Otherwise, if the contextual OclExpression is a IfExp, the helper returns a |
| -- sequence composed of the results of its recursive calls on the "condition", |
| -- "thenExpression" and "elseExpression" references of the IfExp. |
| -- Otherwise, if the contextual OclExpression is an IteratorExp, the helper |
| -- returns a sequence composed of the IteratorExp iterators along with the |
| -- results of its recursive calls on the "source" and the "body" references |
| -- of the IteratorExp. |
| -- Otherwise, if the contextual OclExpression is an IterateExp, the helper |
| -- returns the sequence returned for an IteratorExp with its additional result |
| -- element. |
| -- Otherwise, the helper returns an empty sequence as default value. |
| -- CONTEXT: ATL!OclExpression |
| -- RETURN: Sequence(ATL!VariableDeclaration) |
| --helper context ATL!OclExpression |
| -- def: getDownD() : Sequence(ATL!VariableDeclaration) = |
| -- if self.oclIsTypeOf(ATL!LetExp) then |
| -- Sequence{ |
| -- self.variable, |
| -- self.in_.getDownD() |
| -- }->flatten() |
| -- else if self.oclIsTypeOf(ATL!IfExp) then |
| -- Sequence{ |
| -- self.condition.getDownD(), |
| -- self.thenExpression.getDownD(), |
| -- self.elseExpression.getDownD() |
| -- }->flatten() |
| -- else if self.oclIsTypeOf(ATL!IteratorExp) then |
| -- Sequence{ |
| -- self.iterators, |
| -- self.source.getDownD(), |
| -- self.body.getDownD() |
| -- }->flatten() |
| -- else if self.oclIsTypeOf(ATL!IterateExp) then |
| -- Sequence{ |
| -- self.iterators, |
| -- self.result, |
| -- self.source.getDownD(), |
| -- self.body.getDownD() |
| -- }->flatten() |
| -- else Sequence{} |
| -- endif endif endif endif; |
| |
| |
| -- This helper returns the root composite (container) of the contextual |
| -- OclExpression. For this purpose, the helper first computes the immediate |
| -- composite of the contextual OclExpression. |
| -- If this container is undefined, the helper returns OclUndefined. |
| -- Otherwise, if it is a kind of OclExpression, the helper returns the value |
| -- provided by its recursive call on the computed container. |
| -- Finally, if this container is not an OclExpression, the root composite has |
| -- been reached (Binding/InPattern/Operation/Query/Attribute) and is returned. |
| -- CONTEXT: ATL!LocatedElement |
| -- RETURN: OclAny |
| helper context ATL!LocatedElement def: getRootComposite() : OclAny = |
| let container : OclAny = self.refImmediateComposite() |
| in |
| if container.oclIsUndefined() |
| then |
| OclUndefined |
| else |
| if container.oclIsKindOf(ATL!OclExpression) or |
| container.oclIsKindOf(ATL!Statement) or |
| container.oclIsKindOf(ATL!VariableDeclaration) |
| then |
| container.getRootComposite() |
| else |
| container |
| endif |
| endif; |
| |
| -- These helpers check for value equality of OclTypes. |
| -- The base case evaluates to "false", and covers the case of |
| -- comparing to OclUndefined. |
| -- CONTEXT: ATL!OclType |
| -- RETURN: Boolean |
| helper context ATL!"OclType" def: equals(o : OclAny) : Boolean = |
| false; |
| |
| helper context ATL!"OclType" def: equals(o : ATL!"OclType") : Boolean = |
| self.name = o.name and self.oclType() = o.oclType(); |
| |
| helper context ATL!OclModelElement def: equals(o : ATL!OclModelElement) : Boolean = |
| super.equals(o) and |
| self.model.equals(o.model); |
| |
| -- These helpers check for value equality of OclModels. |
| -- The base case evaluates to "false", and covers the case of |
| -- comparing to OclUndefined. |
| -- CONTEXT: ATL!OclModel |
| -- RETURN: Boolean |
| helper context ATL!OclModel def: equals(o : OclAny) : Boolean = |
| false; |
| |
| helper context ATL!OclModel def: equals(o : ATL!OclModel) : Boolean = |
| self.name = o.name; |
| |
| --- Returns 'true' if all types in the sequence are equal to the types in 'os'. |
| helper context Sequence(ATL!"OclType") def: allTypesEquals(os : Sequence(ATL!"OclType")) : Boolean = |
| if self->isEmpty() then |
| os->isEmpty() |
| else if os->isEmpty() then |
| self->isEmpty() |
| else |
| let s : ATL!"OclType" = self->first() in |
| let o : ATL!"OclType" = os->first() in |
| s.equals(o) and |
| self->subSequence(2, self->size()).allTypesEquals(os->subSequence(2, os->size())) |
| endif endif; |
| |
| ------------------------------------------------------------------------------- |
| -- RULES ---------------------------------------------------------------------- |
| ------------------------------------------------------------------------------- |
| |
| -- Rule 'FreeVariableIsSelfOrThisModule' |
| -- This rule generates an 'error' Problem for each VariableDeclaration that has |
| -- no composite, and whose name is different from both 'self' and 'thisModule'. |
| -- The VariableExps that have not been previously declared in an ATL file are |
| -- associated with a new VariableDeclaration without any composite in the |
| -- correspoding ATL model. |
| nodefault rule FreeVariableIsSelfOrThisModule { |
| from |
| s : ATL!VariableDeclaration ( |
| s.refImmediateComposite().oclIsUndefined() and |
| s.varName <> 'self' and s.varName <> 'thisModule' |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- |
| if s.variableExp->isEmpty() |
| then |
| s.location |
| else |
| s.variableExp->first().location |
| endif, |
| description <- 'variable \'' + s.varName + '\' undefined' |
| ) |
| } |
| |
| -- Rule 'ModelNameIsUnique' |
| -- This rule generates an 'error' Problem when there exists models that have |
| -- the same name that the checked model. |
| nodefault rule ModelNameIsUnique { |
| from |
| s : ATL!OclModel ( |
| thisModule.allModels->exists(e | e.name = s.name and e <> s) |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- 'model \'' + s.name + '\' already defined' |
| ) |
| } |
| |
| -- Rule 'RuleNameIsUnique' |
| -- This rule generates an 'error' Problem when there exists rules that have |
| -- the same name that the checked rule. |
| nodefault rule RuleNameIsUnique { |
| from |
| s : ATL!Rule ( |
| thisModule.allRules->exists(e | e.name = s.name and e <> s) |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- 'rule \'' + s.name + '\' already defined' |
| ) |
| } |
| |
| -- Rule 'HelperSignatureIsUnique' |
| -- This rule generates an 'error' Problem when there exists helpers that have |
| -- the same signature that the checked helper. |
| -- Note that in current implementation, the helper signature corresponds to the |
| -- name and the context of the helper. |
| nodefault rule HelperSignatureIsUnique { |
| from |
| s : ATL!Helper ( |
| thisModule.allHelpers |
| ->exists(e | e <> s |
| and |
| -- name check |
| s.definition.feature.name = e.definition.feature.name |
| and |
| -- helper type check |
| s.definition.feature.oclType() = e.definition.feature.oclType() |
| and |
| -- context check |
| ( |
| if not s.definition.context_.oclIsUndefined() |
| then |
| if not e.definition.context_.oclIsUndefined() |
| then |
| s.definition.context_.context_.equals(e.definition.context_.context_) |
| and |
| if s.definition.feature.oclIsTypeOf(ATL!Operation) and e.definition.feature.oclIsTypeOf(ATL!Operation) |
| then |
| -- parameters check |
| if not s.definition.feature.parameters.oclIsUndefined() |
| then |
| if not e.definition.feature.parameters.oclIsUndefined() |
| then |
| if s.definition.feature.parameters.size() = e.definition.feature.parameters.size() |
| then |
| s.definition.feature.parameters -> collect(param | param.type) -> allTypesEquals( |
| e.definition.feature.parameters -> collect(param | param.type) |
| ) |
| else |
| false |
| endif |
| else |
| false |
| endif |
| else |
| false |
| endif |
| else |
| true |
| endif |
| else |
| false |
| endif |
| else |
| e.definition.context_.oclIsUndefined() |
| endif |
| ) |
| |
| ) |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- 'helper \'' + s.definition.feature.name |
| + '\' already defined' |
| ) |
| } |
| |
| -- DISABLED |
| ---- Rule 'BindingNameIsUniqueInPattern' |
| ---- This rule generates an 'error' Problem when there exists, in a same pattern, |
| ---- bindings that have the same name that the checked binding. |
| --rule BindingNameIsUniqueInPattern { |
| -- from |
| -- s : ATL!Binding ( |
| -- s.outPatternElement.bindings |
| -- ->exists(e | e.propertyName = s.propertyName and e <> s) |
| -- ) |
| -- to |
| -- t : Problem!Problem ( |
| -- severity <- #error, |
| -- location <- s.location, |
| -- description <- |
| -- 'binding \'' + s.propertyName + '\' already defined in pattern' |
| -- ) |
| --} |
| |
| -- Rule 'PatternNameIsUniqueInRule' |
| -- This rule generates an 'error' Problem when there exists, in a same rule, |
| -- some named elements (InPatternElement/OutPatternElement/ |
| -- RuleVariableDeclaration) that have the same name that the checked pattern. |
| nodefault rule PatternNameIsUniqueInRule { |
| from |
| s : ATL!PatternElement ( |
| s."rule".namedElements |
| ->exists(e | e.varName = s.varName and e <> s) |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- |
| 'pattern or variable named \'' |
| + s.varName + '\' already defined in rule' |
| ) |
| } |
| |
| -- Rule 'VariableNameIsUniqueInRule' |
| -- This rule generates an 'error' Problem when there exists, in a same rule, |
| -- some named elements (InPatternElement/OutPatternElement/ |
| -- RuleVariableDeclaration) that have the same name that the checked rule |
| -- variable declaration. |
| nodefault rule VariableNameIsUniqueInRule { |
| from |
| s : ATL!RuleVariableDeclaration ( |
| s."rule".namedElements |
| ->exists(e | e.varName = s.varName and e <> s) |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- |
| 'pattern or variable named \'' + s.varName |
| + '\' already defined in rule' |
| ) |
| } |
| |
| -- Rule 'NoSelfOrThisModuleVariableDeclaration' |
| -- This rule generates an 'error' Problem for each declaration of a variable |
| -- named 'self' or 'thisModule' in the ATL program. |
| -- Considered variable declarations must have a non-undefined immediate |
| -- composite since the input ATL model may already include a 'self' and a |
| -- 'thisModule' VD without any immediate composite that correspond to the |
| -- global declarations of the 'self' and 'thisModule' variables. |
| nodefault rule NoSelfOrThisModuleVariableDeclaration { |
| from |
| s : ATL!VariableDeclaration ( |
| not s.refImmediateComposite().oclIsUndefined() and |
| (s.varName = 'self' or s.varName = 'thisModule') |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- |
| 'helper \'' + s.varName + '\' is not valid variable name' |
| ) |
| } |
| |
| -- Rule 'NoSelfVariableInRule' |
| -- This rule generates an 'error' Problem for each 'self' variable expression |
| -- that is contained by a rule element. |
| nodefault rule NoSelfVariableInRule { |
| from |
| s : ATL!VariableExp ( |
| if s.referredVariable.oclIsUndefined() |
| then |
| false |
| else |
| s.referredVariable.varName = 'self' and |
| ( |
| let rComp : OclAny = s.getRootComposite() in |
| rComp.oclIsTypeOf(ATL!Binding) or |
| rComp.oclIsTypeOf(ATL!InPattern) or |
| rComp.oclIsTypeOf(ATL!ActionBlock) |
| ) |
| endif |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- |
| 'rule \'' + s.referredVariable.varName |
| + '\': use of the \'self\' variable prohibited in rules' |
| ) |
| } |
| |
| -- Rule 'NoSelfVariableInRule' |
| -- This rule generates an 'error' Problem for each 'self' variable expression |
| -- that is contained by a helper without context declaration. |
| nodefault rule NoSelfVariableInContextlessHelper { |
| from |
| s : ATL!VariableExp ( |
| if s.referredVariable.oclIsUndefined() |
| then |
| false |
| else |
| s.referredVariable.varName = 'self' and |
| ( |
| let rComp : OclAny = s.getRootComposite() in |
| rComp.oclIsKindOf(ATL!OclFeature) and |
| rComp.definition.context_.oclIsUndefined() |
| ) |
| endif |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- |
| 'Use of the \'self\' variable prohibited in helpers without context declaration' |
| ) |
| } |
| |
| -- Rule 'NoResolveTempInSourcePattern' |
| -- This rule generates an 'error' Problem for each call of the |
| -- 'thisModule.resolveTemp()' operation within a source pattern of a rule. |
| nodefault rule NoResolveTempInSourcePattern { |
| from |
| s : ATL!OperationCallExp ( |
| s.operationName = 'resolveTemp' and |
| ( |
| if s.source.oclIsTypeOf(ATL!VariableExp) |
| then |
| if s.source.referredVariable.oclIsUndefined() |
| then |
| false |
| else |
| s.source.referredVariable.varName = 'thisModule' |
| endif |
| else |
| false |
| endif |
| ) and |
| s.getRootComposite().oclIsTypeOf(ATL!InPattern) |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- |
| 'rule \'' + s.getRootComposite()."rule".name |
| + '\': use of \'thisModule.resolveTemp()\' function ' |
| + 'is prohibited in source patterns' |
| ) |
| } |
| |
| -- Rule 'ProhibitedMultiIteratorCollectionOperation' |
| -- This rule generates an 'error' Problem for each IteratorExp of the |
| -- singleIteratorExps set that is associated with several Iterators. |
| nodefault rule ProhibitedMultiIteratorCollectionOperation { |
| from |
| s : ATL!IteratorExp ( |
| thisModule.singleIteratorExps->exists(e | s.name = e) and |
| s.iterators->size() > 1 |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- |
| 'iterator \'' + s.name |
| + '\' may have at most one iterator variable' |
| ) |
| } |
| |
| ---- Rule 'UnsupportedMultiIteratorCollectionOperation' |
| ---- This rule generates an 'error' Problem for each IteratorExp of the |
| ---- multiIteratorExps set that is associated with several Iterators. |
| ---- Note that this problem is due to limitations of the current implementation. |
| --nodefault rule UnsupportedMultiIteratorCollectionOperation { |
| -- from |
| -- s : ATL!IteratorExp ( |
| -- thisModule.multiIteratorExps->exists(e | s.name = e) and |
| -- s.iterators->size() > 1 |
| -- ) |
| -- to |
| -- t : Problem!Problem ( |
| -- severity <- #error, |
| -- location <- s.location, |
| -- description <- |
| -- 'with current implementation, iterator \'' + s.name |
| -- + '\' may have at most one iterator variable' |
| -- ) |
| --} |
| |
| -- Rule 'ParameterNameIsUniqueInOperation' |
| -- This rule generates an 'error' Problem for each parameter for which there |
| -- exists another parameter of the same name in the operation declaration. |
| nodefault rule ParameterNameIsUniqueInOperation { |
| from |
| s : ATL!Parameter ( |
| if not s.operation.oclIsUndefined() then |
| (s.operation.parameters |
| ->exists(e | s.varName = e.varName and s <> e)) and not( |
| s.refImmediateComposite().oclIsUndefined() and |
| s.varName <> 'self' and s.varName <> 'thisModule' |
| ) |
| else false endif |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- |
| 'a parameter named \'' + s.varName |
| + '\' is already declared in this operation' |
| ) |
| } |
| |
| -- Rule 'IteratorNameIsUniqueInLoop' |
| -- This rule generates an 'error' Problem for each Iterator declaration for |
| -- which there exists either another Iterator or a result variable declaration |
| -- (for Iterate loop only) of the same name within the same loop definition. |
| nodefault rule VariableNameIsUniqueInLoop { |
| from |
| s : ATL!Iterator ( |
| if not s.loopExpr.oclIsUndefined() then |
| s.loopExpr.iterators |
| ->exists(e | s.varName = e.varName and s <> e) |
| or |
| if s.loopExpr.oclIsTypeOf(ATL!IterateExp) |
| then |
| s.loopExpr.result.varName = s.varName |
| else |
| false |
| endif |
| else false endif |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- |
| 'a variable named \'' + s.varName |
| + '\' is already declared in this loop' |
| ) |
| } |
| |
| -- Rule 'ResultNameIsUniqueInIterate' |
| -- This rule generates an 'error' Problem for each 'result' variable |
| -- declaration of an IterateExp for which there exists an Iterator variable of |
| -- the same name in the Iterate loop definition. |
| nodefault rule ResultNameIsUniqueInIterate { |
| from |
| s : ATL!VariableDeclaration ( |
| if s.baseExp.oclIsUndefined() |
| then |
| false |
| else |
| s.baseExp.iterators |
| ->exists(e | s.varName = e.varName and s <> e) |
| endif |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- |
| 'a variable named \'' + s.varName |
| + '\' is already declared in this loop' |
| ) |
| } |
| |
| -- Rule 'VariableNameIsUniqueInContainer' |
| -- This rule generates a 'warning' Problem for each declaration of a variable |
| -- for which there exists another variable declaration of the same name in the |
| -- same namespace (except multiple intances of an Iterator name in a same loop |
| -- which handle 'error' Problems). |
| nodefault rule VariableNameIsUniqueInContainer { |
| from |
| s : ATL!VariableDeclaration ( |
| s.getDeclarations()->exists(e | s.varName = e.varName and s <> e) |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #warning, |
| location <- s.location, |
| description <- |
| 'a variable named \'' + s.varName |
| + '\' is already declared in this container' |
| ) |
| } |
| |
| nodefault rule NoSuperOutsideHelper { |
| from s : ATL!SuperExp ( |
| not s.getRootComposite().oclIsKindOf(ATL!OclFeature) |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- 'Cannot access "super" outside operations or attributes' |
| ) |
| } |
| |
| nodefault rule NoSuperInContextlessHelper { |
| from s : ATL!SuperExp ( |
| let rComp : OclAny = s.getRootComposite() in |
| rComp.oclIsKindOf(ATL!OclFeature) and |
| rComp.definition.context_.oclIsUndefined() |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- 'Cannot access "super" from a helper without context declaration' |
| ) |
| } |
| |
| nodefault rule OutputElementUsesOutputMetamodel { |
| from s : ATL!OutPatternElement ( |
| not s.outPattern."rule"."module".outModels |
| ->exists(m|s.type.model.name = m.metamodel.name) |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- 'Cannot instantiate metaclasses that are not related to an output model' |
| ) |
| } |
| |
| nodefault rule BindingStatAssignsToNavigationOrAttributeCallExpOrVariable { |
| from s : ATL!BindingStat ( |
| ( |
| not s.source.oclIsKindOf(ATL!NavigationOrAttributeCallExp) |
| ) and ( |
| not s.source.oclIsKindOf(ATL!VariableExp) or |
| s.source.referredVariable.varName = 'self' or |
| s.source.referredVariable.varName = 'thisModule' |
| ) |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- 'Can only assign to model element features, helper attributes, or local variables' |
| ) |
| } |
| |
| nodefault rule RefiningRuleInRegularMode { |
| from |
| s : ATL!MatchedRule ( |
| s.isRefining and |
| not s."module".isRefining |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- 'Refining rules are only allowed in refining mode' |
| ) |
| } |
| |
| nodefault rule NoOutPatternElementReferenceInInPattern { |
| from |
| s : ATL!VariableExp ( |
| s.referredVariable.oclIsKindOf(ATL!OutPatternElement) and |
| s.getRootComposite().oclIsKindOf(ATL!InPattern) |
| ) |
| to |
| t : Problem!Problem ( |
| severity <- #error, |
| location <- s.location, |
| description <- 'Cannot refer to target element \'' + s.referredVariable.varName + '\' in a \'from\' clause' |
| ) |
| } |