acg QVTR startsWith RelationalTransformation { attribute EObject::location = self.__xmiID__; attribute EObject::_debug = true; --***************************************************************************************** function EObject::pattern() = if self isa Pattern then self else let container = self.eContainer() in if container.oclIsUndefined() then OclUndefined else container.pattern() endif endif ; function EObject::relation() = if self isa Relation then self else let container = self.eContainer() in if container.oclIsUndefined() then OclUndefined else container.relation() endif endif ; function EObject::domain() = if self isa Domain then self else let container = self.eContainer() in if container.oclIsUndefined() then OclUndefined else container.domain() endif endif ; function EObject::context_provider() = let container = self.eContainer() in if container isa Predicate then self else if container isa TemplateExp or container isa PropertyTemplateItem or container isa Function or container isa RelationDomainAssignment then container else if container.oclIsUndefined() then OclUndefined else container.context_provider() endif endif endif ; ObjectTemplateExp mode class { push self.bindsTo.eType.name push self.pattern().eContainer().typedModel.name+'MM' findme } CollectionTemplateExp mode class { push 'OclParametrizedType' push '#native' new dup push self.referedCollectionType.name call 'J.setName(S):V' dup push 'OclSimpleType' push '#native' new dup push 'OclAny' call 'J.setName(S):V' call 'J.setElementType(J):V' } asm RelationalTransformation name self.name { field 'relationCalls' : 'Nmap;' field 'relationResults' : 'Nmap;' operation context 'A' name 'main' { param 'enforce' : 'S' getasm push 'Map' push '#native' new foreach (r in self.rule->select(r | r.isTopLevel)) { push r.name pushf call 'NMap;.including(SJ):Nmap;' } set 'relationCalls' getasm push 'Map' push '#native' new set 'relationResults' load 'enforce' push 'true' call 'J.=(J):B' variable self named 'enforce' { pusht foreach (r in self.rule->select(r | r.isTopLevel)) { getasm load self call 'A.'+r.name+'(B):B' call 'B.and(B):B' } } push 'Transformation result is' call 'J.debug(S):J' } foreach (r in self.rule) { analyze r } foreach (o in self.eOperations) { analyze o } } function Relation::source_patterns() = if self.when.oclIsUndefined() then Sequence{} else Sequence{self.when} endif.union( self.domain.asSequence().excluding(self.direction_domain()) ->select(d | not d.pattern.oclIsUndefined()) ->collect(d | d.pattern) ) ; function Relation::target_patterns() = self.direction_domain().pattern.asSequence().including( if self.where.oclIsUndefined() then Sequence{} else Sequence{self.where} endif ) ; Function { operation context 'A' name self.name { foreach (p in self.eParameters) { param p.name : 'J' } analyze self mode pre_binding variable self named 'context' { analyze self.queryExpression } } } Function mode pre_binding { push 'Map' push '#native' new foreach (p in self.eParameters) { push p.name load p.name call 'NMap;.including(SJ):NMap;' } } Relation { operation context 'A' name self.name { param 'enforce' : 'B' if (not self.isTopLevel) { foreach (d in self.domain) { param d.rootVariable.name : 'J' } if (self._debug) { push '' foreach (d in self.domain.asSequence()) { load d.rootVariable.name call 'J.toString():S' call 'S.concat(S):S' if ( d <> self.domain.asSequence().last() ) { push ', ' call 'S.concat(S):S' } } push self.name + ' called with arguments' call 'J.debug(S):J' pop } } if (self.isTopLevel) { getasm get 'relationCalls' push self.name call 'NMap;.get(S):J' if skip_execution getasm getasm get 'relationCalls' push self.name pusht call 'NMap;.including(SJ):NMap;' set 'relationCalls' } pusht variable self named self.name+'_result'{ analyze self mode pre_binding --NMap foreach (sp in self.source_patterns()) { analyze sp --ENMap iterate --NMap [ dup --NMap,NMap foreach(tp in self.target_patterns()) { analyze tp --NMap,ENMap dup --NMap,ENMap,ENMap call 'J.isEmpty():B' --NMap,ENMap,B if warn_or_enforce --NMap,ENMap iterate --NMap,NMap [ analyze self mode register goto end_target ] enditerate } warn_or_enforce: --NMap,ENMap pop --NMap variable self.direction_domain().pattern named 'target_context' { foreach (rda in self.direction_domain().defaultAssignment){ load self.direction_domain().pattern variable rda named 'defaultAssignmentContext' { load rda push rda.variable.name analyze rda.valueExp if (self._debug){ --S,J swap --J,S dup_x1 --S,J,S push ' default value ' call 'S.concat(S):S' call 'J.debug(S):J' } call 'NMap;.including(SJ):NMap;' store self.direction_domain().pattern } } analyze self.direction_domain().pattern.templateExpression mode warn_or_enforce } end_target: ] enditerate } if (self.isTopLevel) { getasm getasm get 'relationResults' push self.name load self call 'NMap;.including(SJ):NMap;' set 'relationResults' skip_execution: getasm get 'relationResults' push self.name call 'NMap;.get(S):J' goto end } load self if (self._debug) { push '-----------'+self.name + ' result' call 'J.debug(S):J' } end: } } } ObjectTemplateExp mode warn_or_enforce { -- load 'enforce' if enforce load self.pattern() push 'Missing an instance of '+self.referredClass.name + ' compliant with' call 'J.debug(S):J' pop goto end enforce: analyze self mode force_bind_element load self.pattern() analyze self.relation() mode register if (not self.relation().where.oclIsUndefined()) { pusht --B foreach (p in self.relation().where.predicate) { load self.pattern() --B,NMap variable p.conditionExpression named 'context' { --B analyze p.conditionExpression mode post_unify --B,B call 'B.and(B):B' --B load p.conditionExpression --B,NMap store self.pattern() --B } } if update load self.pattern() push 'failed enforcement of '+ self.bindsTo.name call 'J.debug(S):J' pop goto end update: analyze self mode update -- } else { analyze self mode update -- } end: } ObjectTemplateExp mode update { foreach (pti in self.part) { analyze pti mode update } } PropertyTemplateItem mode update { analyze self.objContainer load self.pattern() variable self named 'context' { analyze self.value } if (self._debug){ --J1,J2 swap --J2,J1 dup_x1 --J1,J2,J1 call 'J.toString():S' --J1,J2,S push '.'+self.referredProperty.name+' set to' call 'S.concat(S):S' call 'J.debug(S):J' } set self.referredProperty.name if (self.value isa TemplateExp) { analyze self.value mode update } } CollectionTemplateExp mode update { load self.pattern() push self.bindsTo.name push self.referredCollectionType.name push '#native' new foreach (m in self.member) { analyze m call 'CJ.including(J):CJ' } load self.pattern() push self.rest.name call 'NMap;.get(S):J' call 'CJ.union(CJ):CJ' call 'NMap;.including(SJ):NMap;' store self.pattern() } TemplateExp { load self.pattern() --only called by update mode ? push self.bindsTo.name call 'NMap;.get(S):J' } function Relation::objectTemplateExp() = self.domain ->collect(d | d.pattern) ->collect(p | p.templateExpression).flatten() ->select(t | t isa ObjectTemplateExp) ->collect(ote | ote.objectTemplateExp()).flatten() ; function ObjectTemplateExp::objectTemplateExp() = Sequence{self}.union(self.part->select(pti | pti.value isa ObjectTemplateExp)->collect(pti | pti.value.objectTemplateExp()).flatten()) ; Relation mode register { --NMap variable self.direction_domain() named self.name+'_register_context' { push 'T'+self.name push 'Traceability' new push 'Trace created for '+self.name call 'J.debug(S):J' foreach (ote in self.objectTemplateExp()) { --J dup --J,J load self.direction_domain() --J,J,NMap push ote.bindsTo.name --J,J,NMap,S call 'NMap;.get(S):J' --J,J,J set ote.bindsTo.name --J -- if (self._debug){ -- dup --J,J -- get ote.bindsTo.name --J,J -- push 'T'+self.name+'.'+ote.bindsTo.name+' set to' -- call 'J.debug(S):J' -- pop -- } } pop } } CollectionTemplateExp mode get_target_candidates { load self.pattern() --NMap push self.bindsTo.name --NMap,S call 'NMap;.get(S):J' --J call 'J.oclIsUndefined()' --B call 'B.not():B' --B if found -- load self.pattern() --NMap push self.bindsTo.name --NMap,S push self.referredCollectionType.name --NMap,S,S push '#native' --NMap,S,S,S new --NMap,S,CJ call 'NMap;.including(SJ):NMap;' --NMap store self.pattern() -- found: -- } ObjectTemplateExp mode force_bind_element { load self.pattern() --NMap push self.bindsTo.name --NMap,S call 'NMap;.get(S):J' --J if (self._debug) { push 'pre binding for ' + self.bindsTo.name call 'J.debug(S):J' } call 'J.oclIsUndefined()' --B call 'B.not():B' --B if found -- if (self.parts_cover_key()){ push 'OclUndefined' push '#native' new --J variable self.bindsTo named self.bindsTo.name + 'key_match' { analyze self mode class push self.domain().typedModel.name call 'MMOF!Classifier;.allInstancesFrom(S):QJ' --QJ if (self._debug) { push self.referredClass.name+ ' instances candidates for update' call 'J.debug(S):S' } iterate --J variable self named self.bindsTo.name +'current_inspected' { -- analyze self mode bind_key --B call 'B.not():B' if skip_elt load self store self.bindsTo skip_elt: } enditerate load self.bindsTo if (self._debug) { push 'element conforming to key found for '+self.bindsTo.name call 'J.debug(S):J' } call 'J.oclIsUndefined():B' if create if (self._debug){ load self.bindsTo push 'element selected by key' call 'J.debug(S):J' pop } load self.pattern() push self.bindsTo.name load self.bindsTo call 'NMap;.including(SJ):NMap;' store self.pattern() goto found } } create: load self.pattern() push self.bindsTo.name push self.referredClass.name push self.pattern().eContainer().typedModel.name+'MM' new if (self.parts_cover_key()){ foreach (pti in self.key_part()) { if (pti.isContainerOf(self)){ dup load self.pattern() push pti.objContainer.bindsTo.name call 'NMap;.get(S):J' swap if (self._debug){ --J1,J2 swap --J2,J1 dup_x1 --J1,J2,J1 call 'J.toString():S' --J1,J2,S push '.'+pti.referredProperty.name+' key container property set to' call 'S.concat(S):S' call 'J.debug(S):J' } set pti.referredProperty.name --pti.referredProperty.eOpposite.name } else { dup load self.pattern() variable pti named 'context' { analyze pti.value } -- if (self._debug){ --J1,J2 -- swap --J2,J1 -- dup_x1 --J1,J2,J1 -- call 'J.toString():S' --J1,J2,S -- push '.'+pti.referredProperty.name+' key property set to' -- call 'S.concat(S):S' -- call 'J.debug(S):J' -- } set pti.referredProperty.name } } } if (self._debug){ push self.referredClass.name+' created' call 'J.debug(S):J' } -- analyze self mode class -- push self.domain().name -- call 'MMOF!Classifier;.newInstanceIn(S):J' call 'NMap;.including(SJ):NMap;' store self.pattern() found: -- load self.pattern() foreach (pti in self.part->select(pti | pti.value isa TemplateExp)) { analyze pti.value mode force_bind_element --NMap } } ObjectTemplateExp mode bind_key { pusht --B foreach (pti in self.key_part()) { if (pti.isContainerOf(self)) { load self.pattern() --B,NMap push pti.objContainer.bindsTo.name --B,NMap,S call 'NMap;.get(S):J' --B,J get pti.referredProperty.name --B,J load self --B,J,J if (pti.referredProperty.many) { call 'CJ.includes(J):B' } else { call 'J.=(J):B' } --B,B call 'B.and(B):B' --B } else { load self --B,J get pti.referredProperty.name --B,J load self.pattern() variable pti named 'context' { analyze pti.value --B,J,J } call 'J.=(J):B' --B,B call 'B.and(B):B' --B } } } function ObjectTemplateExp::parts_cover_key() = self.matching_keys().size() > 0 ; function ObjectTemplateExp::matching_keys() = self.keys_on_type() ->select(k | k.part.asSet().intersection( self.part->collect(p | p.referredProperty).union(self.containerPropertySingleton()) ).size() = k.part.size() ) ; function ObjectTemplateExp::containerPropertySingleton() = if self.eContainer() isa PropertyTemplateItem then if not self.eContainer().referredProperty.eOpposite.oclIsUndefined() then Sequence{self.eContainer().referredProperty.eOpposite} else Sequence{} endif else Sequence{} endif ; function ObjectTemplateExp::keys_on_type() = self.relation().transformation.ownedKey->select(k |k.identifies.isSuperTypeOf(self.referredClass)) ; function PropertyTemplateItem::isContainerOf(ote) = self.value = ote ; function ObjectTemplateExp::key_part() = self.part->select(pti | self.matching_keys().first().part.includes(pti.referredProperty)) .union( if self.eContainer() isa PropertyTemplateItem then if self.eContainer().referredProperty.eOpposite.oclIsUndefined() then Sequence{} else Sequence{self.eContainer()}->select(p | self.matching_keys().first().part.includes(p.referredProperty.eOpposite) ) endif else Sequence{} endif ) ; Relation mode pre_binding { push 'Map' push '#native' new if (not self.isTopLevel) { foreach (d in self.domain) { push d.rootVariable.name load d.rootVariable.name call 'NMap;.including(SJ):NMap;' } } } Pattern { --NMap push 'Set' push '#native' new --NMap,EJ swap --EJ,NMap call 'EJ.including(J):EJ' --EJ variable self named 'contexts' { -- foreach (exp in self.predicate->collect(p | p.conditionExpression)) { analyze exp mode match } load self } if (self._debug) { push '' push self.__xmiID__+' pattern bindings' call 'J.debug(S):J' pop dup iterate push ' ' call 'J.debug(S):J' pop enditerate } } DomainPattern { --NMap variable self named 'context' { -- push 'Set' push '#native' new --EJ load self --EJ,NMap push self.templateExpression.bindsTo.name --EJ,NMap,S call 'NMap;.get(S):J' --EJ,J call 'J.oclIsUndefined():B' --EJ,B call 'B.not():B' --EJ,B if skip_search --EJ analyze self.templateExpression mode class --EJ,J push self.eContainer().typedModel.name --EJ,J,S call 'MMOF!Classifier;.allInstancesFrom(S):EJ' --EJ,EJ iterate --EJ,J variable self.templateExpression named 'object' { --EJ load self --EJ,NMap push self.templateExpression.bindsTo.name --EJ,NMap,S load self.templateExpression --EJ,NMap,S,J call 'NMap;.including(SJ):NMap;' --EJ,NMap call 'EJ.including(J):EJ' --EJ } enditerate goto end skip_search: --EJ load self --EJ,NMap call 'EJ.including(J):EJ' --EJ end: } variable self named 'contexts' { -- analyze self.templateExpression mode match load self } if (self._debug) { push '' push self.__xmiID__+' pattern bindings' call 'J.debug(S):J' pop dup iterate push ' ' call 'J.debug(S):J' pop enditerate } } --***************************************************************************************** RelationCallExp mode match | self.referredRelation.isTopLevel { getasm get 'relationCalls' push self.referredRelation.name call 'NMap;.get(S):J' if skip_call getasm load 'enforce' call 'A.'+self.referredRelation.name+'(B):' pop skip_call: push 'Set' push '#native' new --ENMap load self.pattern() --ENMap,ENMap iterate --ENMap,NMap variable self named 'context' { --ENMap push 'T'+self.referredRelation.name push 'Traceability' findme push 'traces' call 'MMOF!Classifier;.allInstancesFrom(S):EJ' --ENMap,EJ iterate --ENMap,J analyze self mode unify --ENMap,B call 'B.not():B' --ENMap,B if skip_add --ENMap load self --ENMap,NMap call 'EJ.including(J):EJ' --ENMap skip_add: --ENMap enditerate } enditerate store self.pattern() -- } RelationCallExp mode match { push 'Set' push '#native' new load self.pattern() iterate variable self named 'context' { analyze self --no need to call unify since in a non top level relation call, all arguments have to be bound call 'B.not():B' if skip_add load self call 'EJ.including(J):EJ' skip_add: } enditerate store self.pattern() } function RelationCallExp::getRootVariableCorrespondingTo(a) = self.referredRelation.domain.asSequence().at( self.argument.indexOf(a) ).rootVariable ; RelationCallExp mode unify | self.referredRelation.isTopLevel { --J pusht --J,B swap --B,J foreach (a in self.argument) { dup_x1 --J,B,J get self.getRootVariableCorrespondingTo(a).name --J,B,J analyze a mode unify --J,B,B if (self._debug) { load self push 'new context' call 'J.debug(S):J' pop } call 'B.and(B):B' --J,B swap --B,J } pop --B } RelationCallExp mode unify { analyze self } RelationCallExp mode post_unify { analyze self } RelationCallExp { getasm load 'enforce' foreach (a in self.argument) { analyze a } call 'A.'+self.referredRelation.name+'(B'+self.argument->collect(a | 'J').prepend('').sum()+'):B' } VariableExp { load self.context_provider() --NMap push self.referredVariable.name --NMap,S call 'NMap;.get(S):J' --J } VariableExp mode unify { --J variable self named self.referredVariable.name { analyze self dup --J,J call 'J.oclIsUndefined():B' --J,B if bind --J load self --J,J call 'J.=(J):B' --B goto end bind: --J pop -- load self.context_provider() --NMap push self.referredVariable.name --NMap,S load self --NMap,S,J call 'NMap;.including(SJ):NMap;' --NMap store self.context_provider() -- pusht --B end: } } VariableExp mode post_unify { --J variable self named self.referredVariable.name { analyze self dup --J,J call 'J.oclIsUndefined():B' --J,B if bind --J load self --J,J call 'J.=(J):B' --B goto end bind: --J pop -- load self.context_provider() --NMap push self.referredVariable.name --NMap,S load self --NMap,S,J call 'NMap;.including(SJ):NMap;' --NMap store self.context_provider() -- pusht --B end: } } OCLExpression mode match { push 'Set' push '#native' new load self.pattern() iterate variable self named 'context' { pusht analyze self mode unify call 'B.not():B' if skip load self call 'EJ.including(J):B' skip: } enditerate } StringLiteralExp { push self.stringSymbol } OCLExpression mode unify { --J analyze self --J,J call 'J.=(J):B' --B } OCLExpression mode post_unify { --J analyze self --J,J call 'J.=(J):B' --B } function OperationCallExp::conformsToRestriction()= if self.referredOperation.name = '=' then self.argument.first() isa VariableExp else false endif ; function OperationCallExp::conformsToRestrictionInverted()= if self.referredOperation.name = '=' then self.source isa VariableExp and not (self.argument.first() isa VariableExp) else false endif ; OperationCallExp mode match | self.conformsToRestriction() or self.conformsToRestrictionInverted() { push 'Set' push '#native' new --ENMap load self.pattern() --ENMap,ENMap iterate --ENMap,NMap variable self named 'context' { --ENMap analyze self mode unify --ENMap,B call 'B.not():B' --ENMap,B if skip_add --ENMap load self --ENMap,NMap call 'EJ.including(J):EJ' --ENMap skip_add: } enditerate } OperationCallExp { if (self.source.oclIsUndefined()) { getasm } else { analyze self.source } foreach (a in self.argument) { analyze a } call 'J.'+self.referredOperation.name+'('+self.argument->collect(a | 'J').prepend('').sum()+'):J' } OperationCallExp mode unify | self.conformsToRestriction() { analyze self.source --J analyze self.argument.first() mode unify --B } OperationCallExp mode post_unify | self.conformsToRestriction() { analyze self.source --J analyze self.argument.first() mode post_unify --B } OperationCallExp mode unify | self.conformsToRestrictionInverted() { analyze self.argument.first() --J analyze self.source mode unify --B } OperationCallExp mode post_unify | self.conformsToRestrictionInverted() { analyze self.argument.first() --J analyze self.source mode post_unify --B } OperationCallExp mode unify { --J analyze self call 'J.=(J):B' } OperationCallExp mode post_unify { --J analyze self call 'J.=(J):B' } OperationCallExp mode match { push 'Set' push '#native' new --ENMap load self.pattern() --ENMap,ENMap iterate --ENMap,NMap variable self named 'context' { --ENMap analyze self call 'B.not():B' --ENMap,B if skip_add --ENMap load self --ENMap,NMap call 'EJ.including(J):EJ' --ENMap skip_add: } enditerate } ObjectTemplateExp mode match { push 'Set' push '#native' new --ENMap load self.pattern() --ENMap,ENMap iterate --ENMap,NMap variable self named 'context' { --ENMap load self --ENMap,NMap push self.bindsTo.name --ENMap,NMap,S call 'NMap;.get(S):J' --ENMap,J variable self.bindsTo named 'object' { --ENMap load self.bindsTo --ENMap,J call 'J.oclIsUndefined():B' --ENMap,B call 'B.not():B' --ENMap,B load self.bindsTo --ENMap,B,J analyze self mode class --ENMap,B,J,J call 'J.oclIsKindOf(J):B' --ENMap,B,B call 'B.and(B):B' --ENMap,B call 'B.not():B' --ENMap,B if skip_inclusion --ENMap load self --ENMap,NMap call 'EJ.including(J):EJ' --ENMap skip_inclusion: } } enditerate store self.pattern() -- foreach (p in self.part) { analyze p mode match } } --Special case multiple bindings can be added at once PropertyTemplateItem mode match | self.value isa ObjectTemplateExp and self.referredProperty.many { push 'Set' push '#native' new --ENMap load self.pattern() --ENMap,ENMap iterate --ENMap,NMap variable self named 'context' { --ENMap load self --ENMap,NMap push self.objContainer.bindsTo.name --ENMap,NMap,S call 'NMap;.get(S):J' --ENMap,J get self.referredProperty.name --ENMap,CJ load self --ENMap,CJ,NMap push self.value.bindsTo.name --ENMap,CJ,NMap,S call 'NMap;.get(S):J' --ENMap,CJ,J dup --ENMap,CJ,J,J call 'J.oclIsUndefined():B' --ENMap,CJ,J,B if add_candidates --ENMap,CJ,J call 'CJ.includes(J):B' --ENMap,B call 'B.not():B' --ENMap,B if skip_add --ENMap load self --ENMap,NMap call 'EJ.including(J):EJ' --ENMap skip_add: --ENMap goto end_context add_candidates: --ENMap,CJ,J pop --ENMap,CJ iterate --ENMap,J variable self.value.bindsTo named 'object' { --ENMap load self --ENMap,NMap push self.value.bindsTo.name --ENMap,NMap,S load self.value.bindsTo --ENMap,NMap,S,J call 'NMap;.including(SJ):NMap;' --ENMap,NMap call 'EJ.including(J):EJ' --ENMap } enditerate end_context: } --ENMap enditerate store self.pattern() analyze self.value mode match } PropertyTemplateItem mode match { push 'Set' push '#native' new --ENMap load self.pattern() --ENMap,ENMap iterate --ENMap,NMap variable self named 'context' { --ENMap load self --ENMap,NMap push self.objContainer.bindsTo.name --ENMap,NMap,S call 'NMap;.get(S):J' --ENMap,J get self.referredProperty.name --ENMap,J if (self.value isa CollectionTemplateExp and not self.referredProperty.many) { call 'J.as'+self.value.referredCollectionType.name+'():CJ' --ENMap,CJ } analyze self.value mode unify --ENMap,B call 'B.not():B' --ENMap,B if skip_add --ENMap load self --ENMap,NMap call 'EJ.including(J):EJ' --ENMap skip_add: } enditerate store self.pattern() if (self.value isa TemplateExp) { analyze self.value mode match } } ObjectTemplateExp mode unify { --J load self.context_provider() --J,NMap push self.bindsTo.name --J,NMap,S call 'NMap;.get(S):J' --J,J dup --J,J,J call 'J.oclIsUndefined():B' --J,J,B if bind --J,J call 'J.=(J):B' --B call 'B.not():B' --B goto end bind: --J,J pop --J variable self named 'object' { -- load self.context_provider() --NMap push self.bindsTo.name --NMap,S load self --NMap,S,J call 'NMap;.including(SJ):NMap;' --NMap store self.context_provider() pusht --B } end: } function EStructuralFeature::hasSequenceType() = self.many and self.ordered and not self.unique ; function CollectionTemplateExp::mustCheckUnicity() = if self.eContainer() isa PropertyTemplateItem then self.eContainer().referredProperty.hasSequenceType() and not self.referredCollectionType isa "Sequence" else false endif ; CollectionTemplateExp mode unify { --CJ variable self named 'object' { -- load self.context_provider() --NMap push self.bindsTo.name --NMap,S call 'NMap;.get(S):J' --CJ dup --CJ,CJ call 'J.oclIsUndefined():B' --CJ,B if bind --CJ if (self.mustCheckUnicity()) { load self --CJ,CJ call 'CJ.size():I' --CJ,I load self --CJ,I,CJ call 'CJ.asSet():I' --CJ,I,EJ call 'CJ.size():I' --CJ,I,I call 'J.=(J):J' --CJ,B if same_size --CJ pushf --B goto end same_size: --CJ } load self --CJ,CJ call 'J.as'+self.referredCollectionType.name+'():CJ' --CJ,CJ call 'CJ.=(CJ):B' --B goto end bind: --CJ pop -- load self.context_provider() --NMap push self.bindsTo.name --NMap,S load self --NMap,S,CJ call 'NMap;.including(SJ):NMap;' --NMap store self.context_provider() -- pusht --B end: --B } } --*************************************************************************** --* 8.3 The Expressions Package from OCL formal/06-05-01 * --*************************************************************************** TypeExp { push self.referredType.name if (self.referredType.package.name='ecore') { --TODO find more general solution push '%EMF' } else { push self.referredType.package.name } findme } IfExp { analyze self.condition if thn analyze self.elseExpression goto end thn: analyze self.thenExpression end: } PropertyCallExp { --TODO move check to operation analyze self.source get self.referredProperty.name } OperationCallExp | if not(self.source.oclIsUndefined()) then self.source.eType isa CollectionType and self.eType isa PrimitiveType and self.eType.name = 'Integer' else false endif { analyze self.source analyze self.argument pushi 0 --TODO? call self.eType.encodeType() +'.including(J):'+ self.eType.encodeType() call self.referredOperation.encodeType() } --*************************************************************************** --* 8.3.5 Literal Expressions from OCL formal/06-05-01 * --*************************************************************************** BooleanLiteralExp | self.booleanSymbol { pusht } BooleanLiteralExp { pushf } IntegerLiteralExp { pushi self.integerSymbol } RealLiteralExp { pushd self.realSymbol } StringLiteralExp { push self.stringSymbol } NullLiteralExp { push 'OclUndefined' push '#native' new } CollectionLiteralExp { push self.kind.toString() push '#native' new foreach (part in self.part) { analyze part if (part isa CollectionItem) { call 'CJ.including(J):CJ' --FIXME } else { if (part isa CollectionItem) { call 'CJ.union(CJ):CJ'--FIXME } else { report error 'CollectionLiteralExp can only contain CollectionItem or CollectionRange' } } } } CollectionItem { analyze self.item } CollectionRange { --TODO push 'Sequence' push '#native' new analyze self.last analyze self.first call 'QJ.including(J):QJ'--FIXME } --*************************************************************************** --* 11.9 Mapping Rules for Predefined Iterator Expressions --* from OCL formal/06-05-01 --*************************************************************************** IterateExp | self.name = 'iterate' { if (self.result isa CollectionType) { push self.eType.getTypeName() push '#native' new } else { push 'OclUndefined' push '#native' new } variable self.result named self.result.name { analyze self.result mode initit analyze self.source foreach (i in self.iterator) { if (i<>self.iterator.last()) { dup } } foreach (i in self.iterator) { push 'OclUndefined' push '#native' new variable i named i.name {[ foreach (j in self.iterator) { iterate store j --we cant use variable here, so we store explicitly [ analyze self.body mode withResult analyze self.result mode storeit ] } ]} enditerate } } } IteratorExp | self.name = 'collect' or self.name = 'collectNested' { if (self.iterator.size() <> 1) { report error 'Iterator expression '+ self.name +' must have at most one iterator' } let colType = self.eType.getTypeName() { if (colType='Set') { push 'Bag' } else { push colType } } push '#native' new analyze self.source let i = self.iterator.first() { iterate variable i named i.name { analyze self.body mode withResult call 'CJ.including(J):CJ' } enditerate } } IteratorExp | self.name = 'select' { if (self.iterator.size() <> 1) { report error 'Iterator expression '+ self.name +' must have at most one iterator' } push self.eType.getTypeName() push '#native' new analyze self.source let i = self.iterator.first() { iterate variable i named i.name { analyze self.body mode withResult if skip load i call self.eType.encodeType() +'.including(J):'+ self.eType.encodeType() skip: } enditerate } } IteratorExp | self.name = 'reject' and self.source.eType isa SetType { if (self.iterator.size() <> 1) { report error 'Iterator expression '+ self.name +' must have at most one iterator' } push self.eType.getTypeName() push '#native' new analyze self.source let i = self.iterator.first() { iterate variable i named i.name { analyze self.body mode withResult call 'B.not():B' if skip load i call self.eType.encodeType() +'.including(J):'+ self.eType.encodeType() skip: } enditerate } } IteratorExp | self.name = 'exists' { pushf analyze self.source foreach (i in self.iterator) { if (i<>self.iterator.last()) { dup } } foreach (i in self.iterator) { push 'OclUndefined' push '#native' new variable i named i.name {[ foreach (j in self.iterator) { iterate store j --we cant use ACG's variable construct here, so we store explicitly [ dup if found2 --TODO: optimize for other loops? analyze self.body mode withResult call 'B.or(B):B' found2: --shortcut the iteration ] } ]} enditerate } } --TODO iterate IteratorExp IteratorExp | self.name = 'forAll' { pushf analyze self.source foreach (i in self.iterator) { if (i<>self.iterator.last()) { dup } } foreach (i in self.iterator) { push 'OclUndefined' push '#native' new variable i named i.name {[ foreach (j in self.iterator) { iterate store j --we cant use ACG's variable construct here, so we store explicitly [ dup if foundfalse call 'B.not():B' analyze self.body mode withResult call 'B.xor(B):B' foundfalse: ] } ]} enditerate } } IteratorExp | self.name = 'isUnique' { --TODO test if (self.iterator.size() <> 1) { report error 'Iterator expression '+ self.name +' must have at most one iterator' } pusht variable self named 'result' { push 'Set' push '#native' new analyze self.source let i = self.iterator.first() { iterate --SE variable i named i.name { --TODO: optimize by shortcutting loop body dup --SS analyze self.body mode withResult --SSR dup_x1 --SRSR call 'EJ.includes(J):B' --SRB if found call 'EJ.include(J):EJ' goto next found: pop pushf store self next: } enditerate } pop load self } } IteratorExp | self.name = 'any' { --TODO test if (self.iterator.size() <> 1) { report error 'Iterator expression '+ self.name +' must have at most one iterator' } pusht --B analyze self.source --BS let i = self.iterator.first() { iterate --BE swap --EB dup_x1 --BEB if notfound --BE pop --B goto next notfound: variable i named i.name { --B analyze self.body mode withResult --BB call 'B.and(B):B' --B } next: enditerate if none load i goto end none: push 'OclUndefined' push '#native' new end: } } IteratorExp | self.name = 'one' { --TODO test if (self.iterator.size() <> 1) { report error 'Iterator expression '+ self.name +' must have at most one iterator' } pushi 0 analyze self.source --IS let i = self.iterator.first() { iterate --IE variable i named i.name { --I analyze self.body mode withResult --IB call 'B.not():B' --IB if nfound --I pushi 1 call 'I.+(I):I' nfound: } enditerate pushi 1 call 'I.=(I):B' } } IteratorExp | self.name = 'sortedBy' { --TODO test if (self.iterator.size() <> 1) { report error 'Iterator expression '+ self.name +' must have at most one iterator' } let colType = self.eType.getTypeName() { if (colType='Set' or 'OrderedSet') { push 'OrderedSet' } else { --Bag or Sequence push 'Sequence' } } push '#native' new --R analyze self.source --RS let i = self.iterator.first() { iterate --RE dup --REE variable self named 'val' { --RE variable i named i.name { --R pushi 0 variable self.body named 'count' { analyze self.body mode withResult --RV swap --VR dup_x1 --RVR iterate --RVE store i --RV dup --RVV analyze self.body mode withResult --RVVV call 'B.<(B):B' --RVB if nocount --RV load self.body pushi 1 call 'I.+(I):I' store self.body nocount: enditerate --RV pop --R load self --RE load self.body --REI call 'CJ.insertAt(JI):CJ' --R } }} enditerate } } }