blob: a017848b5b572761d686292e79131912eb5adecc [file] [log] [blame]
-- @atlcompiler emftvm
-- @nsURI EMFTVM=http://www.eclipse.org/m2m/atl/2011/EMFTVM
-- Inlines nested code blocks
-- $Id: InlineCodeblocks.atl,v 1.7 2012/05/20 18:19:40 dwagelaar Exp $
module InlineCodeblocks;
create OUT : EMFTVM refining IN : EMFTVM;
-- ======================================================================
-- helpers begin
-- ======================================================================
-- isEmptyRuleCode
helper context EMFTVM!CodeBlock def : isEmptyRuleCode : Boolean =
self.refImmediateComposite().oclIsKindOf(EMFTVM!Rule) and self.isInlineEmpty;
helper context EMFTVM!CodeBlock def : isInlineEmpty : Boolean =
self.code->forAll(i |
(i.oclIsKindOf(EMFTVM!InvokeCb) and i.codeBlock.isInlineEmpty) or
(i.oclIsKindOf(EMFTVM!InvokeAllCbs) and self.nested->forAll(n|n.isInlineEmpty))
);
-- isInlined
helper context EMFTVM!CodeBlock def : isInlined : Boolean =
self.isEmptyRuleCode or
(let parent : EMFTVM!CodeBlock = self.nestedFor in
if parent.oclIsUndefined() then
false
else
parent.code->exists(i|i.oclIsKindOf(EMFTVM!InvokeAllCbs) or
i.targets(self))
endif);
-- targets
helper context EMFTVM!Instruction def : targets(cb : EMFTVM!CodeBlock) : Boolean =
false;
helper context EMFTVM!InvokeCb def : targets(cb : EMFTVM!CodeBlock) : Boolean =
self.codeBlock = cb;
helper context EMFTVM!And def : targets(cb : EMFTVM!CodeBlock) : Boolean =
self.codeBlock = cb;
helper context EMFTVM!Or def : targets(cb : EMFTVM!CodeBlock) : Boolean =
self.codeBlock = cb;
helper context EMFTVM!Implies def : targets(cb : EMFTVM!CodeBlock) : Boolean =
self.codeBlock = cb;
helper context EMFTVM!Ifte def : targets(cb : EMFTVM!CodeBlock) : Boolean =
self.thenCb = cb or self.elseCb = cb;
-- reTarget
helper context EMFTVM!Instruction def : reTarget : EMFTVM!Instruction =
self;
helper context EMFTVM!InvokeCb def : reTarget : EMFTVM!Instruction =
self.codeBlock.code->first().reTarget;
helper context EMFTVM!InvokeAllCbs def : reTarget : EMFTVM!Instruction =
let nested : Sequence(EMFTVM!CodeBlock) = self.owningBlock.nested in
if nested->notEmpty() then
let nestedTarget : EMFTVM!Instruction =
nested->first().code->first().reTarget
in
if nestedTarget.oclIsUndefined() then
self.reTargetEmpty
else
nestedTarget
endif
else
self.reTargetEmpty
endif;
-- reTargetEmpty
helper context EMFTVM!InvokeAllCbs def : reTargetEmpty : EMFTVM!Instruction =
let cb : EMFTVM!CodeBlock = self.owningBlock in
let index : Integer = cb.code->indexOf(self) in
if index < cb.code->size() then
cb.code->at(index+1)
else
OclUndefined
endif;
-- endRetarget
helper context EMFTVM!Instruction def : endReTarget : EMFTVM!Instruction =
self;
helper context EMFTVM!InvokeCb def : endReTarget : EMFTVM!Instruction =
self.codeBlock.code->last().endReTarget;
helper context EMFTVM!Getcb def : endReTarget : EMFTVM!Instruction =
self;
helper context EMFTVM!CodeBlockInstruction def : endReTarget : EMFTVM!Instruction =
thisModule.resolveTemp(self, 'push');
helper context EMFTVM!Ifte def : endReTarget : EMFTVM!Instruction =
if self.elseCb.isInlineEmpty then
if self.thenCb.isInlineEmpty then
thisModule.resolveTemp(self, 'goto')
else
self.thenCb.code->last().endReTarget
endif
else
self.elseCb.code->last().endReTarget
endif;
helper context EMFTVM!InvokeAllCbs def : endReTarget : EMFTVM!Instruction =
let cb : EMFTVM!CodeBlock = self.owningBlock in
let nested : Sequence(EMFTVM!CodeBlock) = cb.nested in
if nested->notEmpty() then
let nestedTarget : EMFTVM!Instruction =
nested->last().code->last().endReTarget
in
if nestedTarget.oclIsUndefined() then
self.endReTargetEmpty
else
nestedTarget
endif
else
self.endReTargetEmpty
endif;
-- endReTargetEmpty
helper context EMFTVM!InvokeAllCbs def : endReTargetEmpty : EMFTVM!Instruction =
let cb : EMFTVM!CodeBlock = self.owningBlock in
let index : Integer = cb.code->indexOf(self) in
if index > 1 then
cb.code->at(index-1)
else
OclUndefined
endif;
-- inline
helper context EMFTVM!CodeBlock def : inline : Sequence(EMFTVM!Instruction) =
self.inline();
helper context EMFTVM!CodeBlock def : inline() : Sequence(EMFTVM!Instruction) =
self.code->iterate(i; acc : Sequence(EMFTVM!Instruction) = Sequence{} |
if i.oclIsKindOf(EMFTVM!InvokeCb) then
acc->union(i.codeBlock.inline)
else if i.oclIsKindOf(EMFTVM!InvokeAllCbs) then
acc->union(self.nested->collect(n|n.inline)->flatten())
else if i.oclIsKindOf(EMFTVM!And) or i.oclIsKindOf(EMFTVM!Or) or i.oclIsKindOf(EMFTVM!Implies) then
acc->append(i)
->union(i.codeBlock.inline)
->append(thisModule.resolveTemp(i, 'goto'))
->append(thisModule.resolveTemp(i, 'push'))
else if i.oclIsKindOf(EMFTVM!Ifte) then
acc->append(i)
->union(i.thenCb.inline)
->append(thisModule.resolveTemp(i, 'goto'))
->union(i.elseCb.inline)
else
acc->append(i)
endif endif endif endif
);
-- collapseNested
helper context EMFTVM!CodeBlock def : collapseNested : Sequence(EMFTVM!CodeBlock) =
self.nested->iterate(n; acc : Sequence(EMFTVM!CodeBlock) = Sequence{} |
if n.isInlined then
acc->union(n.collapseNested)
else
acc->append(n)
endif
);
-- inlineNested
helper context EMFTVM!CodeBlock def : inlinedNested : Sequence(EMFTVM!CodeBlock) =
self.nested->select(n|n.isInlined)->iterate(c; acc : Sequence(EMFTVM!CodeBlock) = Sequence{} |
acc->append(c)->union(c.inlinedNested)
);
-- hasRemainingInstructions
helper context EMFTVM!LineNumber def : hasRemainingInstructions : Sequence(EMFTVM!Instruction) =
self.instructions
->exists(i|not (i.oclIsKindOf(EMFTVM!InvokeCb) or i.oclIsKindOf(EMFTVM!InvokeAllCbs)));
-- remainingInstructions
helper context EMFTVM!LineNumber def : remainingInstructions : Sequence(EMFTVM!Instruction) =
self.remainingInstructions();
helper context EMFTVM!LineNumber def : remainingInstructions() : Sequence(EMFTVM!Instruction) =
self.instructions
->select(i|not (i.oclIsKindOf(EMFTVM!InvokeCb) or i.oclIsKindOf(EMFTVM!InvokeAllCbs)))
->iterate(i; acc : Sequence(EMFTVM!Instruction) = Sequence{} |
if i.oclIsKindOf(EMFTVM!And) or i.oclIsKindOf(EMFTVM!Or) or i.oclIsKindOf(EMFTVM!Implies) then
acc->append(i)
->append(thisModule.resolveTemp(i, 'goto'))
->append(thisModule.resolveTemp(i, 'push'))
else if i.oclIsKindOf(EMFTVM!Ifte) then
acc->append(i)
->append(thisModule.resolveTemp(i, 'goto'))
else
acc->append(i)
endif endif
);
-- remainingLineNumbers
helper context EMFTVM!CodeBlock def : remainingLineNumbers : Sequence(EMFTVM!LineNumber) =
self.lineNumbers->select(ln|ln.remainingInstructions->notEmpty());
-- ======================================================================
-- helpers end
-- ======================================================================
-- ======================================================================
-- matched rules begin
-- ======================================================================
rule DeleteInvokeCb {
from s : EMFTVM!"emftvm::InvokeCb" in IN
}
rule DeleteInvokeAllCbs {
from s : EMFTVM!"emftvm::InvokeAllCbs" in IN
}
rule CodeBlock {
from s : EMFTVM!CodeBlock in IN (
not s.isInlined)
to t : EMFTVM!CodeBlock (
code <- s.inline,
nested <- s.collapseNested,
lineNumbers <- s.remainingLineNumbers->union(
s.inlinedNested->collect(cb|cb.remainingLineNumbers)->flatten()),
localVariables <- s.localVariables->union(
s.inlinedNested->collect(cb|cb.localVariables)->flatten())
)
}
rule DeleteCodeBlock {
from s : EMFTVM!CodeBlock in IN (
s.isInlined)
}
rule LocalVariable {
from s : EMFTVM!"emftvm::LocalVariable" in IN (
not s.owningBlock.isEmptyRuleCode)
to t : EMFTVM!"emftvm::LocalVariable" (
startInstruction <- s.startInstruction.reTarget,
endInstruction <- s.endInstruction.endReTarget)
}
rule DeleteLocalVariable {
from s : EMFTVM!"emftvm::LocalVariable" in IN (
s.owningBlock.isEmptyRuleCode)
}
rule LineNumber {
from s : EMFTVM!"emftvm::LineNumber" in IN (
s.hasRemainingInstructions)
to t : EMFTVM!"emftvm::LineNumber" (
instructions <- s.remainingInstructions)
}
rule DeleteLineNumber {
from s : EMFTVM!"emftvm::LineNumber" in IN (
not s.hasRemainingInstructions)
}
rule And {
from s : EMFTVM!"emftvm::And" in IN
to t : EMFTVM!"emftvm::Ifn" (target <- goto), -- if first value false, jump over goto
-- Here goes the inlined code
goto : EMFTVM!"emftvm::Goto" (target <- push), -- jump over push
push : EMFTVM!"emftvm::Pushf" -- push false
}
rule Or {
from s : EMFTVM!"emftvm::Or" in IN
to t : EMFTVM!"emftvm::If" (target <- goto), -- if first value true, jump over goto
-- Here goes the inlined code
goto : EMFTVM!"emftvm::Goto" (target <- push), -- jump over push
push : EMFTVM!"emftvm::Pusht" -- push true
}
rule Implies {
from s : EMFTVM!"emftvm::Implies" in IN
to t : EMFTVM!"emftvm::Ifn" (target <- goto), -- if first value false, jump over goto
-- Here goes the inlined code
goto : EMFTVM!"emftvm::Goto" (target <- push), -- jump over push
push : EMFTVM!"emftvm::Pusht" -- push true
}
rule Ifte {
from s : EMFTVM!"emftvm::Ifte" in IN
to t : EMFTVM!"emftvm::Ifn" (target <- goto), -- if first value false, jump over goto
-- Here goes the inlined "then" code
goto : EMFTVM!"emftvm::Goto" (target <- s.endReTarget) -- jump over end
-- Here goes the inlined "else" code
}
rule If {
from s : EMFTVM!"emftvm::If" in IN
to t : EMFTVM!"emftvm::If" (
target <- s.target.endReTarget)
}
rule Ifn {
from s : EMFTVM!"emftvm::Ifn" in IN
to t : EMFTVM!"emftvm::Ifn" (
target <- s.target.endReTarget)
}
rule Goto {
from s : EMFTVM!"emftvm::Goto" in IN
to t : EMFTVM!"emftvm::Goto" (
target <- s.target.endReTarget)
}
rule Iterate {
from s : EMFTVM!"emftvm::Iterate" in IN
to t : EMFTVM!"emftvm::Iterate" (
target <- s.target.endReTarget)
}
rule Enditerate {
from s : EMFTVM!"emftvm::Enditerate" in IN
to t : EMFTVM!"emftvm::Enditerate" (
target <- s.target.endReTarget)
}
rule ReturnToGoto {
from s : EMFTVM!"emftvm::Return" in IN (s.owningBlock.isInlined)
to t : EMFTVM!"emftvm::Goto" (target <- s.owningBlock.code->last().endReTarget)
}
-- ======================================================================
-- matched rules end
-- ======================================================================