-- @name Expand -- @version 1.0 -- @authors Robert Tairas -- @date 2007/04/13 -- @description This transformation is based on "expand" commands that recreate the original clones. module Transform; create OUT : Expand from IN1 : Clones, IN2 : Commands; -- A counter to count the commands helper def : counter : Integer = 1; -- Determine if a box of statements (to represent near exact matches) is defined helper def: boxExists(t: String): Boolean = let x : String = thisModule.getCloneInstanceName(thisModule.counter) in let y : Clones!CloneInstance = Clones!CloneInstance.allInstancesFrom('IN1')->select(e | e.instanceName = x)->first() in if y.boxes.oclIsUndefined() then false else let z : Integer = Clones!CloneInstance.allInstancesFrom('IN1') ->select(e | e.instanceName = x) ->collect(e | e.boxes) ->first() ->select(e | e.boxName = t)->size() in if z = 0 then false else true endif endif; -- Determine if declaration statement is also an initialization statement helper context Clones!DeclarationStat def: isSimple : Boolean = self.initExp.oclIsUndefined(); -- Get the actual variable associated to a placeholder variable helper def: getActualVar(t: OclAny): String = let w : String = thisModule.getCloneInstanceName(thisModule.counter) in let x : String = thisModule.getCloneGroupName(w) in let y : Integer = thisModule.getParameterPos(t, x) in let z : Sequence(OclAny) = thisModule.getInstanceArguments(w) in z ->collect(e | e.varName) ->iterate(e; acc : TupleType(index : Integer, varName : String) = Tuple {index = 1, varName = ''} | if acc.index = y then Tuple { index = acc.index + 1, varName = e } else Tuple { index = acc.index + 1, varName = acc.varName } endif ).varName; -- Get the name of a clone group associated to a clone instance helper def: getCloneGroupName(t: String): String = Clones!CloneInstance.allInstancesFrom('IN1') ->select(e | e.instanceName = t) ->collect(e | e.cloneName.cloneName) ->first(); -- Get the name of a clone instance associated to a clone command helper def: getCloneInstanceName(t: Integer): String = Commands!Root.allInstancesFrom('IN2') ->collect(e | e.cloneCommands) ->first() ->iterate(e; acc : TupleType(index : Integer, name : String) = Tuple {index = 1, name = String} | if acc.index = t then Tuple { index = acc.index + 1, name = e.instanceName } else Tuple { index = acc.index + 1, name = acc.name } endif ).name; -- Get the variable names in the arguments of a clone instance helper def: getInstanceArguments(t: String): Sequence(OclAny) = Clones!CloneInstance.allInstancesFrom('IN1') ->select(e | e.instanceName = t) ->collect(e | e.arguments) ->first(); -- Get the variable names in the parameters of a clone group helper def: getParameters(t: String): Sequence(OclAny) = Clones!CloneGroup.allInstancesFrom('IN1') ->select(e | e.cloneName = t) ->collect(e | e.parameters); -- Get the position of the placeholder variable in the list of parameters of the clone group helper def: getParameterPos(s: String, t: String): Integer = thisModule.getParameters(t) ->first() ->collect(e | e.varName) ->iterate(e; acc : TupleType(index : Integer, found : Boolean) = Tuple {index = 0, found = false} | if e = s then Tuple { index = acc.index + 1, found = true } else if acc.found then Tuple { index = acc.index, found = true } else Tuple { index = acc.index + 1, found = false } endif endif ).index; -- Process the statements that represent near exact matches helper def: processBox(t: String): Sequence(OclAny) = let w : String = thisModule.getCloneInstanceName(thisModule.counter) in Clones!CloneInstance.allInstancesFrom('IN1') ->select(e | e.instanceName = w) ->collect(e | e.boxes) ->first() ->select(e | e.boxName = t) ->collect(e | e.statements) ->first() ->collect(e | if e.oclIsKindOf(Clones!AssignStat) then thisModule.AssignStat(e) else if e.oclIsKindOf(Clones!DeclarationStat) then if e.isSimple then thisModule.DeclarationStat(e) else thisModule.DeclarationAssignStat(e) endif else if e.oclIsKindOf(Clones!ReturnStat) then thisModule.ReturnStat(e) else Sequence{} endif endif endif ); -- Process expressions helper def: processExp(t: Clones!Expression): Clones!Expression = if t.oclIsKindOf(Clones!BinaryOperatorCallExp) then thisModule.BinaryOperatorCallExp(t) else if t.oclIsKindOf(Clones!UnaryOperatorCallExp) then thisModule.UnaryOperatorCallExp(t) else if t.oclIsKindOf(Clones!VariableExp) then thisModule.VariableExp(t) else thisModule.IntegerExp(t) endif endif endif; -- Process both actual and placeholder variables (both to actual variables) helper def: processVar(t: Clones!Variable): Clones!ActualVar = if t.oclIsKindOf(Clones!PlaceHolderVar) then thisModule.PlaceHolderVar2ActualVar(t) else thisModule.ActualVar(t) endif; -- Process all "expand" commmands rule CommandExpand { from s : Commands!Root to t : Expand!Root ( statements <- s.cloneCommands->select(e | e.command = #EXPAND)->collect(e | thisModule.CloneCommand(e)) ) } -- Determine the clone group associated to the command lazy rule CloneCommand { from s : Commands!CloneCommand to t : Expand!Root ( statements <- Clones!CloneGroup.allInstancesFrom('IN1')->select(e | e.cloneName = Clones!CloneInstance.allInstancesFrom('IN1')->select(e | e.instanceName = s.instanceName)->collect(e | e.cloneName.cloneName)->first())->collect(e | thisModule.CloneGroup(e)) ) do { -- Increment counter when a new command is being processed thisModule.counter <- thisModule.counter + 1; } } -- Process the clone group lazy rule CloneGroup { from s : Clones!CloneGroup to t : Expand!Root ( statements <- s.statements->collect(e | if e.oclIsKindOf(Clones!AssignStat) then thisModule.AssignStat(e) else if e.oclIsKindOf(Clones!BoxStat) then if thisModule.boxExists(e.boxName) then thisModule.processBox(e.boxName) else Sequence{} endif else if e.oclIsKindOf(Clones!DeclarationStat) then if e.isSimple then thisModule.DeclarationStat(e) else thisModule.DeclarationAssignStat(e) endif else if e.oclIsKindOf(Clones!FunctionStat) then thisModule.FunctionStat(e) else if e.oclIsKindOf(Clones!ReturnStat) then thisModule.ReturnStat(e) else Sequence{} endif endif endif endif endif ) ) } -- Assignment statement lazy rule AssignStat { from s : Clones!AssignStat to t : Expand!AssignStat ( variable <- thisModule.processVar(s.variable), initExp <- thisModule.processExp(s.initExp) ) } -- Declaration statement lazy rule DeclarationStat { from s : Clones!DeclarationStat ( s.isSimple ) to t : Expand!DeclarationStat ( type <- s.type, variable <- thisModule.processVar(s.variable) ) } -- Declaration statement with initialization lazy rule DeclarationAssignStat { from s : Clones!DeclarationStat ( not s.isSimple ) to t : Expand!DeclarationStat ( type <- s.type, variable <- thisModule.processVar(s.variable), initExp <- thisModule.processExp(s.initExp) ) } -- Function statement lazy rule FunctionStat { from s : Clones!FunctionStat to t : Expand!FunctionStat ( modifier <- s.modifier, returnType <- s.returnType, name <- thisModule.processVar(s.name), parameters <- s.parameters->collect(e | thisModule.Parameter(e)), statements <- s.statements->collect(e | if e.oclIsKindOf(Clones!AssignStat) then thisModule.AssignStat(e) else if e.oclIsKindOf(Clones!DeclarationStat) then if e.isSimple then thisModule.DeclarationStat(e) else thisModule.DeclarationAssignStat(e) endif else if e.oclIsKindOf(Clones!ReturnStat) then thisModule.ReturnStat(e) else if e.oclIsKindOf(Clones!BoxStat) then if thisModule.boxExists(e.boxName) then thisModule.processBox(e.boxName) else Sequence{} endif else Sequence{} endif endif endif endif ) ) } -- Function parameter lazy rule Parameter { from s : Clones!Parameter to t : Expand!Parameter ( type <- s.type, variable <- thisModule.processVar(s.variable) ) } -- Return statement lazy rule ReturnStat { from s : Clones!ReturnStat to t : Expand!ReturnStat ( variable <- thisModule.processVar(s.variable) ) } -- Transform placeholder variables to actual variables lazy rule PlaceHolderVar2ActualVar { from s : Clones!PlaceHolderVar to t : Expand!ActualVar ( varName <- thisModule.getActualVar(s.varName) ) } -- Actual variables lazy rule ActualVar { from s : Clones!ActualVar to t : Expand!ActualVar ( varName <- s.varName ) } -- Integer expression lazy rule IntegerExp { from s : Clones!IntegerExp to t : Expand!IntegerExp ( value <- s.value ) } -- Variable expression lazy rule VariableExp { from s : Clones!VariableExp to t : Expand!VariableExp ( value <- thisModule.processVar(s.value) ) } -- Binary operation call lazy rule BinaryOperatorCallExp { from s : Clones!BinaryOperatorCallExp to t : Expand!BinaryOperatorCallExp ( left <- thisModule.processExp(s.left), right <- thisModule.processExp(s.right), opName <- s.opName ) } -- Unary operation call lazy rule UnaryOperatorCallExp { from s : Clones!UnaryOperatorCallExp to t : Expand!UnaryOperatorCallExp ( operand <- if s.operand.oclIsKindOf(Clones!BinaryOperatorCallExp) then thisModule.BinaryOperatorCallExp(s.operand) else thisModule.UnaryOperatorCallExp(s.operand) endif, opName <- s.opName ) }