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