blob: e7b04a340e1947a42db19aaa30c812bb22d22d91 [file] [log] [blame]
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
}
}
}