| -- @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 |
| -- ====================================================================== |