blob: 68caa92972bab8ce24823fb5e6c8d4a4665fb206 [file] [log] [blame]
-- @atlcompiler emftvm
-- @nsURI EMFTVM=http://www.eclipse.org/m2m/atl/2011/EMFTVM
-- @path ATL=/org.eclipse.m2m.atl.common/src/org/eclipse/m2m/atl/common/resources/ATL.ecore
-- @path Problem=/org.eclipse.m2m.atl.common/src/org/eclipse/m2m/atl/common/resources/Problem.ecore
-- Transforms ATL modules into EMFTVM modules
-- $Id: ATLtoEMFTVM.atl,v 1.12 2012/04/08 14:34:47 dwagelaar Exp $
module ATLtoEMFTVM;
create OUT : EMFTVM, PBS : Problem from IN : ATL;
uses OCLtoEMFTVM;
-- ======================================================================
-- helpers begin
-- ======================================================================
--- All called rules are considered static. Returns 'true'.
helper context ATL!CalledRule def : isStatic : String =
true;
--- Returns the model in which the output element will be generated.
helper context ATL!OutPatternElement def : outModel : ATL!OclModel =
if self.model.oclIsUndefined() then
let modelName : String = self.type.modelName in
self.outPattern."rule"."module".outModels
->select(m|modelName = m.metamodel.name)
->first()
else
self.model
endif;
--- Returns the default input element for a matched rule (first element).
helper context ATL!MatchedRule def : defaultInElement : ATL!InPatternElement =
self.inPattern.elements->first();
--- Returns the default input element for a rule ('OclUndefined').
helper context ATL!Rule def : defaultInElement : ATL!InPatternElement =
OclUndefined;
--- Returns the EMFTVM local variable element that represents the given ATL variable expression.
helper context ATL!VariableExp def : localVariable() : EMFTVM!LocalVariable =
let var : ATL!VariableDeclaration = self.referredVariable in
if var.isMatchedRuleElement then
let realVar : ATL!VariableDeclaration =
if var.isRefiningElement then
var.actualSourceElement
else
var
endif
in
if self.isInApply then
thisModule.resolveTemp(realVar, 'ov')
else if self.isInPostApply then
thisModule.resolveTemp(realVar, 'pv')
else
thisModule.resolveTemp(realVar, 'lv')
endif endif
else
thisModule.resolveTemp(var, 'lv')
endif;
--- Returns 'true' if self is part of a matched rule.
helper context ATL!VariableDeclaration def : isMatchedRuleElement : Boolean =
if self.oclIsKindOf(ATL!PatternElement) or self.oclIsKindOf(ATL!RuleVariableDeclaration) then
self.parentRule.oclIsKindOf(ATL!MatchedRule)
else false endif;
--- Returns 'true' if self is part of a matched rule.
helper context ATL!RuleVariableDeclaration def : isMatchedRuleField : Boolean =
self.parentRule.oclIsKindOf(ATL!MatchedRule);
--- Returns the containing ATL rule, or self (with error message).
helper context OclAny def : parentRule : ATL!Rule =
let parent : OclAny = self.refImmediateComposite() in
if parent.oclIsKindOf(ATL!Rule) then parent
else if not parent.oclIsUndefined() then parent.parentRule
else self.debug('parent rule not found for')
endif endif;
--- Returns the EMFTVM trace element local variable for the given ATL variable expression.
helper context ATL!VariableExp def : traceVariable() : EMFTVM!LocalVariable =
let var : ATL!VariableDeclaration = self.referredVariable in
if var.oclIsKindOf(ATL!RuleVariableDeclaration) then
let r : ATL!Rule = var."rule" in
if self.isInApply then
thisModule.resolveTemp(r, 'a_trace')
else if self.isInPostApply then
thisModule.resolveTemp(r, 'p_trace')
else
OclUndefined.debug('Cannot access trace local variable from outside apply or post-apply')
endif endif
else
OclUndefined.debug('Trace local variables can only be retrieved for variable expressions referring to rule variables')
endif;
--- Returns 'true' if self is contained in the apply section of a rule.
helper context OclAny def : isInApply : Boolean =
let parent : OclAny = self.refImmediateComposite() in
if parent.oclIsUndefined() then false
else if parent.oclIsKindOf(ATL!Binding) then true
else if parent.oclIsKindOf(ATL!RuleVariableDeclaration) then true
else parent.isInApply
endif endif endif;
--- Returns 'true' if self is contained in the postApply section of a rule.
helper context OclAny def : isInPostApply : Boolean =
let parent : OclAny = self.refImmediateComposite() in
if parent.oclIsUndefined() then false
else if parent.oclIsKindOf(ATL!Statement) then true
else parent.isInPostApply
endif endif;
--- Returns the source code location representing this rule.
helper context ATL!Rule def : postloc : String =
if self.actionBlock.oclIsUndefined() then
self.location
else
self.actionBlock.location
endif;
--- Returns all called rules for this module.
helper context ATL!Module def : calledRules : Sequence(ATL!CalledRule) =
self.elements->select(e|e.oclIsKindOf(ATL!CalledRule));
--- Returns all output pattern elements for this rule.
helper context ATL!Rule def : outPatternElements : Sequence(ATL!OutPatternElement) =
if self.outPattern.oclIsUndefined() then
Sequence{}
else
self.outPattern.elements
endif;
--- Returns the source code location representing the apply section of this rule.
helper context ATL!Rule def : applyLoc : ATL!LocatedElement =
if self.outPattern.oclIsUndefined() then
self
else
self.outPattern
endif;
--- Support for multiple rule inheritance, including rules outside same module
helper context String def : isExtendsAnn : Boolean =
self.substring(3).trim().startsWith('@extends');
--- Returns the '@extends' values for a given annotation string.
helper context String def : extendsAnnValues : Sequence(String) =
if self.isExtendsAnn then
self.split('@extends')
->at(2).trim().split(',')
->collect(s | s.trim())
else
Sequence{}
endif;
--- Returns 'true' if self is an output model that refines an input model in a refining mode module.
helper context ATL!OclModel def : isRefiningModel : Boolean =
let p : OclAny = self.refImmediateComposite() in
p.oclIsKindOf(ATL!Module) and p.isRefining and (
let outModelsSameType : Sequence(ATL!OclModel) =
p.outModels->select(o | o.metamodel.name = self.metamodel.name) in
outModelsSameType->notEmpty() and
outModelsSameType->first() = self and
p.inModels->exists(i | i.metamodel.name = self.metamodel.name)
);
--- Returns 'true' if self is an input model that is refined by an output model in a refining mode module.
helper context ATL!OclModel def : isRefinedModel : Boolean =
let p : OclAny = self.refImmediateComposite() in
p.oclIsKindOf(ATL!Module) and p.isRefining and (
let inModelsSameType : Sequence(ATL!OclModel) =
p.inModels->select(i | i.metamodel.name = self.metamodel.name) in
inModelsSameType->notEmpty() and
inModelsSameType->first() = self and
p.outModels->exists(o | o.metamodel.name = self.metamodel.name)
);
--- Returns the input model that self refines, or self.
helper context ATL!OclModel def : refines : ATL!OclModel =
if self.isRefiningModel then
let p : OclAny = self.refImmediateComposite() in
p.inModels->select(m | m.metamodel.name = self.metamodel.name)->first()
else
self
endif;
--- Returns the output model that self is refined by, or 'OclUndefined'.
helper context ATL!OclModel def : refinedBy : ATL!OclModel =
if self.isRefinedModel then
let p : OclAny = self.refImmediateComposite() in
p.outModels->select(m | m.metamodel.name = self.metamodel.name)->first()
else
OclUndefined
endif;
--- Returns 'false'.
helper context ATL!VariableDeclaration def : isRefiningElement : Boolean =
false;
--- Returns 'true' if self is an output element that represents a refined input element.
helper context ATL!OutPatternElement def : isRefiningElement : Boolean =
self.outModel.isRefiningModel and
self.outPattern."rule".isRefiningRule and
(let sourceElement : ATL!InPatternElement = self.actualSourceElement in
not sourceElement.oclIsUndefined() and sourceElement.type.sameAs(self.type));
--- Returns 'true' if self has an output element that represents a refinement of this input element.
helper context ATL!InPatternElement def : hasRefiningElement : Boolean =
let r : ATL!Rule = self.inPattern."rule" in
r.isRefiningRule and
not r.outPattern.oclIsUndefined() and
r.outPattern.elements->exists(outElement |
outElement.outModel.isRefiningModel and
self = outElement.actualSourceElement and
self.type.sameAs(outElement.type)
);
--- Returns 'OclUndefined'.
helper context ATL!VariableDeclaration def : actualSourceElement : ATL!InPatternElement =
OclUndefined;
--- Returns the actual source element for self, which is either 's.sourceElement', or the single input element in case self is the first output element.
helper context ATL!OutPatternElement def : actualSourceElement : ATL!InPatternElement =
if self.sourceElement.oclIsUndefined() then
if self.outPattern.elements->first() = self then
let rl : ATL!Rule = self.outPattern."rule" in
if rl.oclIsKindOf(ATL!MatchedRule) and rl.inPattern.elements->size() = 1 then
let sourceElement : ATL!InPatternElement = rl.inPattern.elements->first() in
if sourceElement."mapsTo".oclIsUndefined() then
sourceElement
else -- sourceElement already maps to another target element
OclUndefined
endif
else -- input pattern contains less/more than exactly one element
OclUndefined
endif
else -- self is not the first (default) target element
OclUndefined
endif
else
self.sourceElement
endif;
--- Returns the actual target element for self, which is either 's.mapsTo', or the first output element in case self is the only input element.
helper context ATL!InPatternElement def : actualMapsToElement : ATL!OutPatternElement =
if self."mapsTo".oclIsUndefined() then
if self.inPattern.elements->size() = 1 then
let rl : ATL!Rule = self.inPattern."rule" in
if not rl.outPattern.oclIsUndefined() and rl.outPattern.elements->notEmpty() then
rl.outPattern.elements->first()
else -- output pattern is empty
OclUndefined
endif
else -- input pattern contains less/more than exactly one element
OclUndefined
endif
else
self."mapsTo"
endif;
--- Returns the actual source models for self, which is either 's.models', or the all input/inout models that match the metamodel.
helper context ATL!InPatternElement def : actualModels : Sequence(ATL!OclModel) =
if self.models.notEmpty() then
self.models
else
self.inPattern."rule"."module".inModels->select(m|m.metamodel.name = self.type.modelName)
endif;
--- Returns 'true' if this rule generates default traces.
helper context ATL!MatchedRule def : isDefault : Boolean =
not self.isNoDefault;
--- Returns 'true' if this rule generates default traces.
helper context ATL!LazyMatchedRule def : isDefault : Boolean =
false;
--- Returns 'true' if this rule behaves as a refining rule.
helper context ATL!Rule def : isRefiningRule : Boolean =
false;
--- Returns 'true' if this rule behaves as a refining rule.
helper context ATL!MatchedRule def : isRefiningRule : Boolean =
self.isDefault;
--- Returns 'true' if this rule behaves as a refining rule.
helper context ATL!LazyMatchedRule def : isRefiningRule : Boolean =
self.isRefining;
-- ======================================================================
-- helpers end
-- ======================================================================
-- ======================================================================
-- matched rules begin
-- ======================================================================
abstract rule Unit {
from s : ATL!Unit in IN
to t : EMFTVM!Module (
name <:= s.name,
sourceName <:=
let index : Integer = s.name.lastIndexOf('::') in
if index > 0 then
s.name.substring(index + 2, s.name.size()) + '.atl'
else
s.name + '.atl'
endif,
imports <:= s.libraries->collect(l|l.name)),
main : EMFTVM!Operation (
name <:= 'main',
static <:= true,
"context" <:= 'ExecEnv',
contextModel <:= 'EMFTVM',
type <:= 'Object',
typeModel <:= '#native')
}
rule Library extends Unit {
from s : ATL!Library in IN
to t : EMFTVM!Module (
features <- s.helpers->collect(h|h.definition)->append(main)),
main : EMFTVM!Operation (
body <:= body),
body : EMFTVM!CodeBlock
}
rule Query extends Unit {
from s : ATL!Query in IN
to t : EMFTVM!Module (
features <- s.helpers->collect(h|h.definition)->append(main)),
main : EMFTVM!Operation (
body <- s.body)
}
rule Module extends Unit {
from s : ATL!Module in IN
to t : EMFTVM!Module (
inputModels <- s.inModels->reject(m | m.isRefinedModel),
inoutModels <- s.inModels->select(m | m.isRefinedModel),
outputModels <- s.outModels->reject(m | m.isRefiningModel),
features <- s.elements->select(e|e.oclIsKindOf(ATL!Helper))->collect(h|h.definition)
->union(s.elements->select(e|e.oclIsKindOf(ATL!CalledRule)))
->append(main),
rules <- s.elements->select(e|e.oclIsKindOf(ATL!MatchedRule))),
main : EMFTVM!Operation (
body <:= body),
body : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn)
}
rule ModuleWithEntryPoint extends Module {
from s : ATL!Module in IN (
s.calledRules->exists(r|r.isEntrypoint) and
not s.calledRules->exists(r|r.isEndpoint))
using {
entryPointRule : ATL!CalledRule =
s.calledRules->select(r|r.isEntrypoint)->first();
}
to t : EMFTVM!Module,
body : EMFTVM!CodeBlock (
code <:= Sequence{getenvtype_entry, invoke_entry}),
ln : EMFTVM!LineNumber (
instructions <:= Sequence{getenvtype_entry, invoke_entry}),
getenvtype_entry : EMFTVM!Getenvtype, -- [..., ExecEnv]
invoke_entry : EMFTVM!InvokeStatic ( -- [..., result]
opname <- entryPointRule.name,
argcount <- 0),
pb : Problem!Problem (
description <- 'Entrypoint rules are invoked after matched rules in EMFTVM',
location <- entryPointRule.location,
severity <- #warning)
}
rule ModuleWithEndPoint extends Module {
from s : ATL!Module in IN (
not s.calledRules->exists(r|r.isEntrypoint) and
s.calledRules->exists(r|r.isEndpoint))
using {
endPointRule : ATL!CalledRule =
s.calledRules->select(r|r.isEndpoint)->first();
}
to t : EMFTVM!Module,
body : EMFTVM!CodeBlock (
code <:= Sequence{getenvtype_end, invoke_end}),
ln : EMFTVM!LineNumber (
instructions <:= Sequence{getenvtype_end, invoke_end}),
getenvtype_end : EMFTVM!Getenvtype, -- [..., ExecEnv]
invoke_end : EMFTVM!InvokeStatic ( -- [..., result]
opname <- endPointRule.name,
argcount <- 0)
}
rule ModuleWithEntryAndEndPoint extends Module {
from s : ATL!Module in IN (
s.calledRules->exists(r|r.isEntrypoint) and
s.calledRules->exists(r|r.isEndpoint))
using {
entryPointRule : ATL!CalledRule =
s.calledRules->select(r|r.isEntrypoint)->first();
endPointRule : ATL!CalledRule =
s.calledRules->select(r|r.isEndpoint)->first();
}
to t : EMFTVM!Module,
body : EMFTVM!CodeBlock (
code <:= Sequence{getenvtype_entry, invoke_entry, pop, getenvtype_end, invoke_end}),
ln : EMFTVM!LineNumber (
instructions <:= Sequence{getenvtype_entry, invoke_entry, pop, getenvtype_end, invoke_end}),
getenvtype_entry : EMFTVM!Getenvtype, -- [..., ExecEnv]
invoke_entry : EMFTVM!InvokeStatic ( -- [..., result]
opname <- entryPointRule.name,
argcount <- 0),
pop : EMFTVM!Pop, -- [...]
getenvtype_end : EMFTVM!Getenvtype, -- [..., ExecEnv]
invoke_end : EMFTVM!InvokeStatic ( -- [..., result]
opname <- endPointRule.name,
argcount <- 0),
pb : Problem!Problem (
description <- 'Entrypoint rules are invoked after matched rules in EMFTVM',
location <- entryPointRule.location,
severity <- #warning)
}
rule ModelDeclaration {
from s : ATL!OclModel in IN (not s.metamodel.oclIsUndefined() and not s.isRefiningModel)
to t : EMFTVM!ModelDeclaration (
modelName <- s.name,
metaModelName <- s.metamodel.name)
}
rule InPatternElement {
from s : ATL!InPatternElement in IN
to re : EMFTVM!InputRuleElement (
name <- s.varName,
type <- s.type.typeName,
typeModel <- s.type.modelName,
mapsToSelf <- s.hasRefiningElement,
models <- s.models->collect(m|m.name)),
ov : EMFTVM!LocalVariable (
name <- s.varName,
type <- s.type.typeName,
typeModel <- s.type.modelName)
}
rule InPatternElementWithFilter extends InPatternElement {
from s : ATL!InPatternElement in IN (
not s.inPattern.filter.oclIsUndefined())
to re : EMFTVM!InputRuleElement,
lv : EMFTVM!LocalVariable (
name <- s.varName,
type <- s.type.typeName,
typeModel <- s.type.modelName)
}
rule InPatternElementWithAction extends InPatternElement {
from s : ATL!InPatternElement in IN (
not s.inPattern."rule".actionBlock.oclIsUndefined())
to re : EMFTVM!InputRuleElement,
pv : EMFTVM!LocalVariable (
name <- s.varName,
type <- s.type.typeName,
typeModel <- s.type.modelName)
}
-- @extends InPatternElementWithFilter, InPatternElementWithAction
rule InPatternElementWithFilterAndAction {
from s : ATL!InPatternElement in IN
to re : EMFTVM!InputRuleElement
}
rule OutPatternElement {
from s : ATL!OutPatternElement in IN (
let r : ATL!Rule = s.outPattern."rule" in
r.oclIsKindOf(ATL!MatchedRule) and
not ((r.isDefault or r.isRefining) and s.isRefiningElement))
using {
outModel : ATL!OclModel =
if s.outModel.isRefiningModel then
s.outModel.refines
else
s.outModel
endif;
}
to re : EMFTVM!OutputRuleElement (
name <- s.varName,
type <- s.type.typeName,
typeModel <- s.type.modelName,
models <- Sequence{outModel.name}),
ov : EMFTVM!LocalVariable (
name <- s.varName,
type <- s.type.typeName,
typeModel <- s.type.modelName)
}
rule OutPatternElementWithMapsTo extends OutPatternElement {
from s : ATL!OutPatternElement in IN (
not s.sourceElement.oclIsUndefined())
to re : EMFTVM!OutputRuleElement (
"mapsTo" <- Sequence{thisModule.resolveTemp(s.sourceElement, 're')})
}
rule OutPatternElementWithAction extends OutPatternElement {
from s : ATL!OutPatternElement in IN (
not s.outPattern."rule".actionBlock.oclIsUndefined())
to re : EMFTVM!OutputRuleElement,
pv : EMFTVM!LocalVariable (
name <- s.varName,
type <- s.type.typeName,
typeModel <- s.type.modelName)
}
-- @extends OutPatternElementWithAction, OutPatternElementWithMapsTo
rule OutPatternElementWithActionAndMapsTo {
from s : ATL!OutPatternElement in IN
to re : EMFTVM!OutputRuleElement
}
nodefault rule ForEachOutPatternElement {
from s : ATL!ForEachOutPatternElement in IN
to pb : Problem!Problem (
severity <- #error,
location <- s.location,
description <- '"distinct - foreach" output elements not supported in EMFTVM')
}
nodefault rule DropPattern {
from s : ATL!DropPattern in IN
to pb : Problem!Problem (
severity <- #error,
location <- s.location,
description <- '"drop" output patterns not supported in EMFTVM - omit the "to" part instead')
}
rule CalledRuleOutPatternElement {
from s : ATL!OutPatternElement in IN (
s.outPattern."rule".oclIsKindOf(ATL!CalledRule))
using {
outModel : ATL!OclModel =
if s.outModel.isRefiningModel then
s.outModel.refines
else
s.outModel
endif;
}
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
code <:= Sequence{findtype, new, store}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{findtype, new, store}),
lv : EMFTVM!LocalVariable (
name <- s.varName,
type <- s.type.typeName,
typeModel <- s.type.modelName),
findtype : EMFTVM!Findtype ( -- [..., type]
modelname <- s.type.modelName,
typename <- s.type.typeName),
new : EMFTVM!New (modelname <- outModel.name), -- [..., element]
store : EMFTVM!Store (localVariable <- lv) -- [...]
}
rule CalledRuleVariableDeclaration {
from s : ATL!RuleVariableDeclaration in IN (s."rule".oclIsKindOf(ATL!CalledRule))
to lv : EMFTVM!LocalVariable (
name <- s.varName,
type <- s.type.typeName,
typeModel <- s.type.modelName),
cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.initExpression},
code <:= Sequence{invokeCb, store}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{invokeCb, store}),
invokeCb : EMFTVM!InvokeCb (codeBlock <- s.initExpression, argcount <- 0), -- [..., value]
store : EMFTVM!Store (localVariable <- s) -- [...]
}
rule CalledRule { -- Called rules are really operations
from s : ATL!CalledRule in IN
to t : EMFTVM!Operation (
name <- s.name,
static <- true,
"context" <- 'ExecEnv',
contextModel <- 'EMFTVM',
type <- 'java.lang.Object',
typeModel <- '#native',
parameters <- s.parameters,
body <- body),
body : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
localVariables <- s.parameters->collect(p|thisModule.resolveTemp(p, 'lv'))
->union(s.outPatternElements->collect(p|thisModule.resolveTemp(p, 'lv')))
->union(s.variables),
nested <- s.outPatternElements
->union(s.variables->collect(v|thisModule.resolveTemp(v, 'cb')))
->union(s.outPatternElements->collect(e|e.bindings)->flatten())
->union(
if s.actionBlock.oclIsUndefined() then
Sequence{}
else
s.actionBlock.statements
endif),
code <:= Sequence{invokeAllCbs}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{invokeAllCbs}),
invokeAllCbs : EMFTVM!InvokeAllCbs -- [...]
}
rule CalledRuleNamedMain extends CalledRule {
from s : ATL!CalledRule in IN (s.name = 'main')
to t : EMFTVM!Operation,
pb : Problem!Problem (
description <- 'Called rules may not be named "main()"',
location <- s.location,
severity <- #error)
}
rule MatchedRuleVariableDeclaration {
from s : ATL!RuleVariableDeclaration in IN (s."rule".oclIsKindOf(ATL!MatchedRule))
to t : EMFTVM!Field (
name <- s.varName,
"context" <- 'TraceLink',
contextModel <- 'TRACE',
type <- s.type.typeName,
typeModel <- s.type.modelName,
initialiser <- init),
init : EMFTVM!CodeBlock, -- Empty initialiser
cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.initExpression},
code <:= Sequence{load, invokeCb, set}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{load, invokeCb, set}),
load : EMFTVM!Load (localVariable <- thisModule.resolveTemp(s."rule", 'a_trace')), -- [..., trace]
invokeCb : EMFTVM!InvokeCb (codeBlock <- s.initExpression, argcount <- 0), -- [..., trace, value]
set : EMFTVM!"Set" (fieldname <- s.varName) -- [...]
}
rule MatchedRule {
from s : ATL!MatchedRule in IN
using {
deletedSourceElements : Sequence(ATL!InPatternElement) =
s.inPattern.elements->select(e|
(s.isDefault or s.isRefining) and
e.actualModels->forAll(m|m.isRefinedModel) and
(e.actualMapsToElement.oclIsUndefined() or
not e.actualMapsToElement.isRefiningElement));
remappedSourceElements : Sequence(ATL!InPatternElement) =
deletedSourceElements->reject(e|
e.actualMapsToElement.oclIsUndefined());
}
to t : EMFTVM!Rule (
name <- s.name,
"abstract" <- s.isAbstract,
superRules <-
if s.superRule.oclIsUndefined() then
s.commentsBefore->collect(c | c.extendsAnnValues)->flatten()
else
Sequence{s.superRule.name}
endif,
outputElements <-
if s.isDefault or s.isRefining then
s.outPatternElements->reject(e|e.isRefiningElement)
else
s.outPatternElements
endif,
mode <-
if s.oclIsKindOf(ATL!LazyMatchedRule) then
#manual
else
#automaticSingle
endif,
default <- s.isDefault,
"unique" <- (s.oclIsKindOf(ATL!LazyMatchedRule) and s.isUnique) or s.isNoDefault,
distinctElements <- false,
inputElements <- s.inPattern.elements,
fields <- s.variables,
applier <- a),
a : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{aln},
localVariables <- Sequence{a_trace}
->union(s.inPattern.elements->collect(e|thisModule.resolveTemp(e, 'ov')))
->union(s.outPatternElements->reject(e|e.isRefiningElement)->collect(e|thisModule.resolveTemp(e, 'ov'))),
nested <- s.variables->collect(v|thisModule.resolveTemp(v, 'cb'))
->union(s.outPatternElements->collect(e|e.bindings)->flatten())
->union(remappedSourceElements->collect(e|thisModule.RemapInPatternElement(e)))
->union(deletedSourceElements->collect(e|thisModule.DeleteInPatternElement(e)))
->union(
if not s.oclIsKindOf(ATL!LazyMatchedRule) or s.outPatternElements->isEmpty() then
Sequence{}
else
let e : ATL!OutPatternElement = s.outPatternElements->first() in
Sequence{thisModule.LoadPatternElement(
if e.isRefiningElement then
e.actualSourceElement
else
e
endif
)}
endif
),
code <:= Sequence{a_invokeAllCbs}),
aln : EMFTVM!LineNumber (
startLine <- s.applyLoc.startLine,
startColumn <- s.applyLoc.startColumn,
endLine <- s.applyLoc.endLine,
endColumn <- s.applyLoc.endColumn,
instructions <:= Sequence{a_invokeAllCbs}),
a_trace : EMFTVM!LocalVariable (
name <- '__trace__',
type <- 'TraceLink',
typeModel <- 'TRACE'),
a_invokeAllCbs : EMFTVM!InvokeAllCbs -- [...]
}
rule MatchedRuleWithFilter extends MatchedRule {
from s : ATL!MatchedRule in IN (
not s.inPattern.filter.oclIsUndefined())
using {
matchLoc : ATL!LocatedElement = s.inPattern.filter;
}
to t : EMFTVM!Rule (
matcher <- m),
m : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{mln},
localVariables <- s.inPattern.elements->collect(e|thisModule.resolveTemp(e, 'lv')),
nested <- Sequence{s.inPattern.filter},
code <:= Sequence{invokeCb}),
mln : EMFTVM!LineNumber (
startLine <- matchLoc.startLine,
startColumn <- matchLoc.startColumn,
endLine <- matchLoc.endLine,
endColumn <- matchLoc.endColumn,
instructions <:= Sequence{invokeCb}),
invokeCb : EMFTVM!InvokeCb (codeBlock <- s.inPattern.filter)
}
rule MatchedRuleWithAction extends MatchedRule {
from s : ATL!MatchedRule in IN (
not s.actionBlock.oclIsUndefined())
using {
postLoc : ATL!LocatedElement = s.actionBlock;
}
to t : EMFTVM!Rule (
postApply <- p),
p : EMFTVM!CodeBlock (
localVariables <- Sequence{p_trace}
->union(s.inPattern.elements->collect(e|thisModule.resolveTemp(e, 'pv')))
->union(s.outPatternElements->reject(e|e.isRefiningElement)->collect(e|thisModule.resolveTemp(e, 'pv'))),
lineNumbers <:= Sequence{pln},
nested <- s.actionBlock.statements,
code <:= Sequence{p_invokeAllCbs}),
p_trace : EMFTVM!LocalVariable (
name <- '__trace__',
type <- 'TraceLink',
typeModel <- 'TRACE'),
pln : EMFTVM!LineNumber (
startLine <- postLoc.startLine,
startColumn <- postLoc.startColumn,
endLine <- postLoc.endLine,
endColumn <- postLoc.endColumn,
instructions <:= Sequence{p_invokeAllCbs}),
p_invokeAllCbs : EMFTVM!InvokeAllCbs -- [..., value]
}
-- @extends MatchedRuleWithFilter, MatchedRuleWithAction
rule MatchedRuleWithFilterAndAction {
from s : ATL!MatchedRule in IN
to t : EMFTVM!Rule
}
nodefault rule RefiningMatchedRule {
from s : ATL!MatchedRule (s.isRefining and not s.oclIsKindOf(ATL!LazyMatchedRule))
to pb : Problem!Problem (
severity <- #warning,
location <- s.location,
description <- 'all matched rules are "refining" in refining mode')
}
rule Binding {
from s : ATL!Binding in IN
using {
element : ATL!PatternElement =
if s.outPatternElement.isRefiningElement then
s.outPatternElement.actualSourceElement
else
s.outPatternElement
endif;
}
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.value},
code <:= Sequence{load, invokeCb, set}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{load, invokeCb, set}),
load : EMFTVM!Load (
localVariable <- -- [..., lv]
if s.parentRule.oclIsKindOf(ATL!MatchedRule) then
thisModule.resolveTemp(element, 'ov')
else
thisModule.resolveTemp(element, 'lv')
endif),
invokeCb : EMFTVM!InvokeCb (codeBlock <- s.value, argcount <- 0), -- [..., lv, value]
set : EMFTVM!"Set" (fieldname <- s.propertyName) -- [...]
}
rule ResolvingBinding extends Binding {
from s : ATL!Binding in IN (not s.isAssignment)
to cb : EMFTVM!CodeBlock (
code <:= Sequence{load, invokeCb, invoke, set}),
ln : EMFTVM!LineNumber (
instructions <:= Sequence{load, invokeCb, invoke, set}),
load : EMFTVM!Load, -- [..., lv]
invokeCb : EMFTVM!InvokeCb, -- [..., lv, value]
invoke : EMFTVM!Invoke (opname <- 'resolve', argcount <- 0), -- [..., lv, rvalue]
set : EMFTVM!"Set" -- [...]
}
-------------- Statements -----------------
rule ExpressionStat {
from s : ATL!ExpressionStat in IN
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.expression},
code <:= Sequence{invokeCb}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{invokeCb}),
invokeCb : EMFTVM!InvokeCb (codeBlock <- s.expression, argcount <- 0) -- [..., value]
}
rule NonLastExpressionStat extends ExpressionStat {
from s : ATL!ExpressionStat in IN (
not s.refImmediateComposite().oclIsKindOf(ATL!ActionBlock) or
s.refImmediateComposite().statements->last() <> s)
to cb : EMFTVM!CodeBlock (
code <:= Sequence{invokeCb, pop}),
ln : EMFTVM!LineNumber (
instructions <:= Sequence{invokeCb, pop}),
invokeCb : EMFTVM!InvokeCb, -- [..., value]
pop : EMFTVM!Pop -- [...]
}
abstract rule BindingStat {
from s : ATL!BindingStat in IN (
s.source.oclIsKindOf(ATL!NavigationOrAttributeCallExp))
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.source.source, s.value},
code <:= Sequence{invokeCb, invokeCb2, set}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{invokeCb, invokeCb2, set}),
invokeCb : EMFTVM!InvokeCb ( -- [..., source]
codeBlock <- s.source.source, argcount <- 0),
invokeCb2 : EMFTVM!InvokeCb (codeBlock <- s.value, argcount <- 0), -- [..., source, value]
set : EMFTVM!FieldInstruction (fieldname <- s.source.name) -- [...]
}
rule BindingStatAttribute extends BindingStat {
from s : ATL!BindingStat in IN (not s.source.isStatic)
to cb : EMFTVM!CodeBlock,
ln : EMFTVM!LineNumber,
invokeCb : EMFTVM!InvokeCb, -- [..., source]
invokeCb2 : EMFTVM!InvokeCb, -- [..., source, value]
set : EMFTVM!"Set" -- [...]
}
rule ResolvingBindingStatAttribute extends BindingStatAttribute {
from s : ATL!BindingStat in IN (not s.isAssignment)
to cb : EMFTVM!CodeBlock (
code <:= Sequence{invokeCb, invokeCb2, invoke, set}),
ln : EMFTVM!LineNumber (
instructions <:= Sequence{invokeCb, invokeCb2, invoke, set}),
invokeCb : EMFTVM!InvokeCb, -- [..., source]
invokeCb2 : EMFTVM!InvokeCb, -- [..., source, value]
invoke : EMFTVM!Invoke (opname <- 'resolve', argcount <- 0), -- [..., source, rvalue]
set : EMFTVM!"Set" -- [...]
}
rule BindingStatStaticAttribute extends BindingStat {
from s : ATL!BindingStat in IN (s.source.isStatic)
to cb : EMFTVM!CodeBlock,
ln : EMFTVM!LineNumber,
invokeCb : EMFTVM!InvokeCb, -- [..., source]
invokeCb2 : EMFTVM!InvokeCb, -- [..., source, value]
set : EMFTVM!SetStatic -- [...]
}
rule ResolvingBindingStatStaticAttribute extends BindingStatStaticAttribute {
from s : ATL!BindingStat in IN (not s.isAssignment)
to cb : EMFTVM!CodeBlock (
code <:= Sequence{invokeCb, invokeCb2, invoke, set}),
ln : EMFTVM!LineNumber (
instructions <:= Sequence{invokeCb, invokeCb2, invoke, set}),
invokeCb : EMFTVM!InvokeCb, -- [..., source]
invokeCb2 : EMFTVM!InvokeCb, -- [..., source, value]
invoke : EMFTVM!Invoke (opname <- 'resolve', argcount <- 0), -- [..., source, rvalue]
set : EMFTVM!SetStatic -- [...]
}
rule BindingStatVariable {
from s : ATL!BindingStat in IN (
s.source.oclIsKindOf(ATL!VariableExp) and
s.source.referredVariable.varName <> 'thisModule' and
not s.source.referredVariable.isMatchedRuleField)
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.value},
code <:= Sequence{invokeCb, store}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{invokeCb, store}),
invokeCb : EMFTVM!InvokeCb (codeBlock <- s.value, argcount <- 0), -- [..., value]
store : EMFTVM!Store (localVariable <- s.source.referredVariable) -- [...]
}
rule ResolvingBindingStatVariable extends BindingStatVariable {
from s : ATL!BindingStat in IN (not s.isAssignment)
to cb : EMFTVM!CodeBlock (
code <:= Sequence{invokeCb, invoke, store}),
ln : EMFTVM!LineNumber (
instructions <:= Sequence{invokeCb, invoke, store}),
invokeCb : EMFTVM!InvokeCb, -- [..., value]
invoke : EMFTVM!Invoke (opname <- 'resolve', argcount <- 0), -- [..., rvalue]
store : EMFTVM!Store -- [...]
}
rule BindingStatRuleField {
from s : ATL!BindingStat in IN (
s.source.oclIsKindOf(ATL!VariableExp) and
s.source.referredVariable.isMatchedRuleField)
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.value},
code <:= Sequence{load, invokeCb, set}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{load, invokeCb, set}),
load : EMFTVM!Load (localVariable <- s.source.traceVariable()), -- [..., trace]
invokeCb : EMFTVM!InvokeCb (codeBlock <- s.value, argcount <- 0), -- [..., trace, value]
set : EMFTVM!"Set" (fieldname <- s.source.referredVariable.varName) -- [...]
}
rule ResolvingBindingStatRuleField extends BindingStatRuleField {
from s : ATL!BindingStat in IN (not s.isAssignment)
to cb : EMFTVM!CodeBlock (
code <:= Sequence{load, invokeCb, invoke, set}),
ln : EMFTVM!LineNumber (
instructions <:= Sequence{load, invokeCb, invoke, set}),
load : EMFTVM!Load, -- [..., trace]
invokeCb : EMFTVM!InvokeCb, -- [..., trace, value]
invoke : EMFTVM!Invoke (opname <- 'resolve', argcount <- 0), -- [..., trace, rvalue]
set : EMFTVM!"Set" -- [...]
}
abstract rule IfStat {
from s : ATL!IfStat in IN
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn),
invokeCb : EMFTVM!InvokeCb (codeBlock <- s.condition, argcount <- 0) -- [..., cond]
}
rule IfStatWithThenAndElse extends IfStat {
from s : ATL!IfStat in IN (s.thenStatements->notEmpty() and s.elseStatements->notEmpty())
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.condition, thenCb, elseCb},
code <:= Sequence{invokeCb, ifn, invokeThen, goto, invokeElse}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{invokeCb, ifn, invokeThen, goto, invokeElse}),
invokeCb : EMFTVM!InvokeCb, -- [..., cond]
ifn : EMFTVM!Ifn (target <- goto), -- [...]
invokeThen : EMFTVM!InvokeCb (codeBlock <- thenCb, argcount <- 0), -- [..., result]
goto : EMFTVM!Goto (target <- invokeElse), -- [..., result]
invokeElse : EMFTVM!InvokeCb (codeBlock <- elseCb, argcount <- 0), -- [..., result]
thenCb : EMFTVM!CodeBlock (
nested <- s.thenStatements,
code <:= Sequence{invokeAllCbs}),
invokeAllCbs : EMFTVM!InvokeAllCbs (argcount <- 0),
elseCb : EMFTVM!CodeBlock (
nested <- s.elseStatements,
code <:= Sequence{invokeAllCbs2}),
invokeAllCbs2 : EMFTVM!InvokeAllCbs (argcount <- 0)
}
rule IfStatWithThen extends IfStat {
from s : ATL!IfStat in IN (s.thenStatements->notEmpty() and s.elseStatements->isEmpty())
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.condition, thenCb},
code <:= Sequence{invokeCb, ifn, invokeThen}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{invokeCb, ifn, invokeThen}),
invokeCb : EMFTVM!InvokeCb, -- [..., cond]
ifn : EMFTVM!Ifn (target <- invokeThen), -- [...]
invokeThen : EMFTVM!InvokeCb (codeBlock <- thenCb, argcount <- 0), -- [..., result]
thenCb : EMFTVM!CodeBlock (
nested <- s.thenStatements,
code <:= Sequence{invokeAllCbs}),
invokeAllCbs : EMFTVM!InvokeAllCbs (argcount <- 0)
}
rule IfStatWithElse extends IfStat {
from s : ATL!IfStat in IN (s.thenStatements->isEmpty() and s.elseStatements->notEmpty())
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.condition, elseCb},
code <:= Sequence{invokeCb, ift, invokeElse}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{invokeCb, ift, invokeElse}),
invokeCb : EMFTVM!InvokeCb, -- [..., cond]
ift : EMFTVM!If (target <- invokeElse), -- [...]
invokeElse : EMFTVM!InvokeCb (codeBlock <- elseCb, argcount <- 0), -- [..., result]
elseCb : EMFTVM!CodeBlock (
nested <- s.elseStatements,
code <:= Sequence{invokeAllCbs2}),
invokeAllCbs2 : EMFTVM!InvokeAllCbs (argcount <- 0)
}
rule IfStatWithNothing extends IfStat {
from s : ATL!IfStat in IN (s.thenStatements->isEmpty() and s.elseStatements->isEmpty())
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.condition},
code <:= Sequence{invokeCb, pop}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{invokeCb, pop}),
invokeCb : EMFTVM!InvokeCb (codeBlock <- s.condition, argcount <- 0), -- [..., cond]
pop : EMFTVM!Pop -- [...]
}
rule ForStat {
from s : ATL!ForStat in IN
to cb : EMFTVM!CodeBlock (
localVariables <- Sequence{s.iterator},
lineNumbers <:= Sequence{ln},
nested <- Sequence{s.collection, loop},
code <:= Sequence{invokeCb, it, store, invokeCb2, endit}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{invokeCb, it, store, invokeCb2, endit}),
invokeCb : EMFTVM!InvokeCb (codeBlock <- s.collection, argcount <- 0), -- [..., coll]
it : EMFTVM!Iterate (target <- endit), -- [..., it(coll), value]
store : EMFTVM!Store (localVariable <- s.iterator), -- [..., it(coll)]
invokeCb2 : EMFTVM!InvokeCb (codeBlock <- loop), -- [..., it(coll)]
endit : EMFTVM!Enditerate (target <- it), -- [...]
loop : EMFTVM!CodeBlock (
nested <- s.statements,
code <:= Sequence{invokeAllCbs}),
invokeAllCbs : EMFTVM!InvokeAllCbs (argcount <- 0)
}
-- ======================================================================
-- matched rules end
-- ======================================================================
-- ======================================================================
-- lazy rules begin
-- ======================================================================
lazy rule DeleteInPatternElement {
from s : ATL!InPatternElement
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
code <:= Sequence{load, delete}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{load, delete}),
load : EMFTVM!Load ( -- [..., source]
localVariable <- thisModule.resolveTemp(s, 'ov')),
delete : EMFTVM!Delete -- [...]
do {
cb;
}
}
lazy rule RemapInPatternElement {
from s : ATL!InPatternElement
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
code <:= Sequence{load, load2, invoke, pop}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{load, load2, invoke, pop}),
load : EMFTVM!Load ( -- [..., source]
localVariable <- thisModule.resolveTemp(s, 'ov')),
load2 : EMFTVM!Load ( -- [..., source, target]
localVariable <- thisModule.resolveTemp(s.actualMapsToElement, 'ov')),
invoke : EMFTVM!Invoke ( -- [..., target]
opname <- 'remap',
argcount <- 1),
pop : EMFTVM!Pop -- [...]
do {
cb;
}
}
lazy rule LoadPatternElement {
from s : ATL!PatternElement
to cb : EMFTVM!CodeBlock (
lineNumbers <:= Sequence{ln},
code <:= Sequence{load}),
ln : EMFTVM!LineNumber (
startLine <:= s.startLine,
startColumn <:= s.startColumn,
endLine <:= s.endLine,
endColumn <:= s.endColumn,
instructions <:= Sequence{load}),
load : EMFTVM!Load ( -- [..., source]
localVariable <- thisModule.resolveTemp(s, 'ov'))
do {
cb;
}
}
-- ======================================================================
-- lazy rules end
-- ======================================================================