| 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 | |
| } | |
| } | |
| } |