| /***************************************************************************** |
| * Copyright (c) 2016 CEA LIST. |
| * |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Van Cam Pham <VanCam.PHAM@cea.fr> |
| * |
| *****************************************************************************/ |
| |
| package org.eclipse.papyrus.designer.languages.c.codegen.lib |
| |
| import java.util.Map |
| import org.eclipse.uml2.uml.StateMachine |
| import java.util.HashMap |
| import org.eclipse.uml2.uml.Class |
| import org.eclipse.uml2.uml.Pseudostate |
| import org.eclipse.uml2.uml.Vertex |
| import org.eclipse.uml2.uml.Region |
| import org.eclipse.uml2.uml.PseudostateKind |
| import java.util.List |
| import org.eclipse.uml2.uml.State |
| import java.util.ArrayList |
| import org.eclipse.uml2.uml.OpaqueBehavior |
| import org.eclipse.uml2.uml.FinalState |
| import org.eclipse.uml2.uml.Event |
| import org.eclipse.uml2.uml.Behavior |
| import org.eclipse.papyrus.designer.languages.common.base.GenUtils |
| |
| class TransformationUtil { |
| |
| static def getStateMachineClass(org.eclipse.uml2.uml.Package pack) { |
| val Map<Class, StateMachine> map = new HashMap |
| |
| pack.ownedElements.filter(typeof(Class)).forEach[ |
| var behavior = it.ownedBehaviors.filter(typeof(StateMachine)).head |
| if (behavior !== null) { |
| map.put(it, behavior) |
| } |
| ] |
| |
| return map |
| } |
| |
| static def Pseudostate firstPseudoState(Region region, PseudostateKind kind) { |
| for (Vertex vertex : region.getSubvertices()) { |
| if (vertex instanceof Pseudostate) { |
| var pseudoState = vertex as Pseudostate |
| if (pseudoState.getKind() == kind) { |
| return pseudoState; |
| } |
| } |
| } |
| return null; |
| } |
| |
| static def List<State> findCompositeStatesInRegion(Vertex des1, Vertex des2) { |
| var ret = new ArrayList<State> |
| val path1 = new ArrayList<State> |
| if (des1 instanceof State) { |
| path1.add(des1) |
| } |
| var owner1 = des1.container.state |
| while(owner1 !== null) { |
| path1.add(owner1) |
| owner1 = owner1.container.state |
| } |
| |
| var owner2 = des2 |
| while(owner2 !== null && ret.empty) { |
| for(s:path1) { |
| if (s.container == owner2.container && owner2 instanceof State) { |
| ret.add(s) |
| ret.add(owner2 as State) |
| } |
| } |
| owner2 = owner2.container.state |
| } |
| |
| return ret |
| } |
| |
| def static State findInitialState(Region r) { |
| var pseudoDefault = TransformationUtil.firstPseudoState(r, PseudostateKind.INITIAL_LITERAL) |
| if (pseudoDefault !== null) { |
| return pseudoDefault.outgoings.head.target as State |
| } |
| return null |
| } |
| |
| def static String getInitialEffect(Region r) { |
| var pseudoDefault = TransformationUtil.firstPseudoState(r, PseudostateKind.INITIAL_LITERAL) |
| if (pseudoDefault !== null) { |
| var t = pseudoDefault.outgoings.head |
| if (t.effect !== null && t.effect instanceof OpaqueBehavior) { |
| return (t.effect as OpaqueBehavior).bodies.head |
| } |
| } |
| return "//no initial effect is defined" |
| } |
| |
| |
| def static List<State> transitiveSubStates(State parent) { |
| val ret = new ArrayList<State> |
| if (parent.composite) { |
| for(r:parent.regions) { |
| ret.addAll(r.subvertices.filter(State)) |
| r.subvertices.filter(State).forEach[ |
| ret.addAll(it.transitiveSubStates) |
| ] |
| } |
| } |
| return ret |
| } |
| |
| def static List<State> transitiveSubStates(Region parent) { |
| val ret = new ArrayList<State> |
| parent.subvertices.filter(State).filter[!(it instanceof FinalState)].forEach[ |
| ret.add(it) |
| ret.addAll(it.transitiveSubStates) |
| ] |
| return ret |
| } |
| |
| /** |
| * Return the name of an event (remove non-ASCII characters) |
| */ |
| def static eventName(Event event) { |
| var name = "" |
| var repeat = false |
| for (c : event.name.toCharArray) { |
| if (Character.isAlphabetic(c) || Character.isDigit(c)) { |
| name += c |
| repeat = false; |
| } |
| else if (!repeat) { |
| name += "_"; |
| repeat = true; |
| } |
| } |
| name |
| } |
| |
| /** |
| * Return the ID of an event |
| */ |
| def static eventID(Event event) { |
| event.eventName.toUpperCase + "_ID" |
| } |
| |
| def static isSavehistory(Region topRegion, Region r) { |
| if (r.subvertices.filter(Pseudostate).filter[it.kind == PseudostateKind.SHALLOW_HISTORY_LITERAL].size > 0) { |
| return true |
| } |
| |
| return topRegion.isSaveDeepHistory(r) |
| } |
| |
| def static isBehaviorExist(Behavior b) { |
| if (b !== null && b instanceof OpaqueBehavior) { |
| return !GenUtils.getBodyFromOB(b as OpaqueBehavior, functionScript.CLANGUAGE).empty |
| } |
| return false |
| } |
| |
| def static hasTriggerlessTransition(State s) { |
| return s.outgoings.filter[it.triggers.map[it.event].empty].size > 0 |
| } |
| |
| def static hasTriggerlessTransition(StateMachine sm) { |
| var states = sm.regions.head.subvertices.filter(State).filter[! (it instanceof FinalState)] |
| for (s: states) { |
| if (s.outgoings.filter[it.triggers.map[it.event].empty].size > 0){ |
| return true |
| } |
| } |
| return false; |
| } |
| |
| |
| def static boolean isSaveDeepHistory(Region topRegion, Region r) { |
| if (r.subvertices.filter(Pseudostate).filter[it.kind == PseudostateKind.DEEP_HISTORY_LITERAL].size > 0) { |
| return true |
| } |
| if (r != topRegion) { |
| var nextRegion = r.state.container |
| return topRegion.isSaveDeepHistory(nextRegion) |
| } |
| return false |
| } |
| } |