| /******************************************************************************* |
| * Copyright (c) 2017, 2021 CEA LIST. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Ansgar Radermacher - Initial API and implementation |
| * Shuai Li (CEA LIST) <shuai.li@cea.fr> - Bug 530251 |
| * Ported from C++ code - Bug 568883 |
| * |
| *******************************************************************************/ |
| |
| package org.eclipse.papyrus.designer.transformation.languages.java.library.statemachine |
| |
| import java.util.ArrayList |
| import java.util.HashMap |
| import java.util.LinkedHashMap |
| import java.util.List |
| import java.util.Map |
| import java.util.concurrent.Semaphore |
| import org.eclipse.emf.ecore.resource.ResourceSet |
| import org.eclipse.papyrus.designer.languages.common.base.ElementUtils |
| import org.eclipse.papyrus.designer.languages.common.base.StdUriConstants |
| import org.eclipse.papyrus.designer.languages.common.profile.Codegen.NoCodeGen |
| import org.eclipse.papyrus.designer.languages.java.library.JavaLibUriConstants |
| import org.eclipse.papyrus.designer.languages.java.profile.JavaProfileResource |
| import org.eclipse.papyrus.designer.languages.java.profile.PapyrusJava.Import |
| import org.eclipse.papyrus.designer.transformation.core.transformations.LazyCopier |
| import org.eclipse.papyrus.designer.transformation.core.transformations.TransformationContext |
| import org.eclipse.papyrus.designer.transformation.profile.Transformation.DerivedElement |
| import org.eclipse.papyrus.designer.transformation.vsl.ParseVSL |
| import org.eclipse.papyrus.uml.tools.utils.PackageUtil |
| import org.eclipse.uml2.uml.AnyReceiveEvent |
| import org.eclipse.uml2.uml.Behavior |
| import org.eclipse.uml2.uml.CallEvent |
| import org.eclipse.uml2.uml.ChangeEvent |
| import org.eclipse.uml2.uml.Class |
| import org.eclipse.uml2.uml.Enumeration |
| import org.eclipse.uml2.uml.Event |
| import org.eclipse.uml2.uml.FinalState |
| import org.eclipse.uml2.uml.Interface |
| import org.eclipse.uml2.uml.LiteralInteger |
| import org.eclipse.uml2.uml.OpaqueBehavior |
| import org.eclipse.uml2.uml.OpaqueExpression |
| import org.eclipse.uml2.uml.Operation |
| import org.eclipse.uml2.uml.Package |
| import org.eclipse.uml2.uml.ParameterDirectionKind |
| import org.eclipse.uml2.uml.Profile |
| import org.eclipse.uml2.uml.Property |
| import org.eclipse.uml2.uml.Pseudostate |
| import org.eclipse.uml2.uml.PseudostateKind |
| import org.eclipse.uml2.uml.Region |
| import org.eclipse.uml2.uml.SignalEvent |
| import org.eclipse.uml2.uml.State |
| import org.eclipse.uml2.uml.StateMachine |
| import org.eclipse.uml2.uml.TimeEvent |
| import org.eclipse.uml2.uml.Transition |
| import org.eclipse.uml2.uml.Trigger |
| import org.eclipse.uml2.uml.Type |
| import org.eclipse.uml2.uml.UMLPackage |
| import org.eclipse.uml2.uml.Vertex |
| import org.eclipse.uml2.uml.profile.standard.Create |
| import org.eclipse.uml2.uml.util.UMLUtil |
| |
| import static org.eclipse.papyrus.designer.transformation.library.statemachine.SMCodeGeneratorConstants.* |
| |
| import static extension org.eclipse.papyrus.designer.transformation.library.statemachine.TransformationUtil.* |
| import static extension org.eclipse.papyrus.designer.transformation.library.statemachine.SMCommon.* |
| import static extension org.eclipse.papyrus.designer.transformation.library.xtend.BehaviorUtil.* |
| import static extension org.eclipse.papyrus.uml.tools.utils.StereotypeUtil.* |
| import static org.eclipse.papyrus.designer.transformation.languages.java.library.statemachine.SMJavaCodeGeneratorConstants.* |
| import org.eclipse.papyrus.designer.transformation.library.statemachine.TransformationUtil |
| import org.eclipse.papyrus.designer.languages.java.profile.PapyrusJava.External |
| import org.eclipse.uml2.uml.NamedElement |
| import org.eclipse.papyrus.designer.languages.common.base.StringConstants |
| |
| /** |
| * Java variant of main SM transformation |
| */ |
| class SM2ClassesTransformationCore { |
| protected extension CDefinitions cdefs; |
| public int MAX_NUMBER_ORTHOGONAL_REGIONS = 1 |
| StateMachine sm |
| public Type boolType |
| public Type threadFuncEnum; |
| Type state_t; |
| public Class superContext |
| List<Transition> transitions = new ArrayList |
| List<OpaqueBehavior> actions = new ArrayList |
| public Region topRegion |
| public List<State> states = new ArrayList |
| List<Vertex> vertexes = new ArrayList |
| public LazyCopier copier |
| String langID = "JAVA" |
| |
| public Semaphore sema = new Semaphore(1); |
| |
| public boolean generateActionLog = false |
| boolean createDoActivity = true |
| public Type voidType |
| Enumeration stateIdEnum |
| public Type intType |
| public Type charType |
| public Type stringType |
| Enumeration eventIdEnum |
| |
| public Type sockAddrInType; |
| public static Package umlPrimitiveLibrary |
| public static Package javaLibrary |
| |
| public List<TimeEvent> timeEvents = new ArrayList |
| public List<ChangeEvent> changeEvents = new ArrayList |
| public List<CallEvent> callEvents = new ArrayList |
| List<SignalEvent> signalEvents = new ArrayList |
| List<AnyReceiveEvent> anyEvents = new ArrayList |
| List<Pseudostate> junctions = new ArrayList |
| public ConcurrencyGenerator concurrency |
| public EventTransformation eventTransform |
| public PseudostateGenerator pseudostateGenerator |
| public MonitoringTransformation monitoringTransformation; |
| |
| public List<Behavior> doActivityList = new ArrayList |
| public Package smPack |
| List<Region> regions = new ArrayList |
| public List<Transition> parallelTransitions = new ArrayList |
| public Map<State, List<TimeEvent>> states2TimeEvents = new HashMap |
| Type threadStructType |
| Type event_t |
| |
| new(LazyCopier copier, StateMachine sm, Class tmClass) { |
| this.copier = copier |
| this.superContext = tmClass |
| |
| // perClassPackage = copier.target.createNestedPackage("PerClass_" + mContainerClass.name) |
| // perClassPackage = copier.target |
| this.sm = sm |
| |
| val ResourceSet resourceSet = targetPacket.eResource.resourceSet |
| |
| this.cdefs = new CDefinitions(superContext) |
| |
| umlPrimitiveLibrary = ElementUtils.loadPackage(StdUriConstants.UML_PRIM_TYPES_URI, resourceSet) |
| javaLibrary = ElementUtils.loadPackage(JavaLibUriConstants.LIBRARY_PATH_URI, resourceSet) |
| boolType = umlPrimitiveLibrary.getOwnedType("Boolean") |
| voidType = umlPrimitiveLibrary.getOwnedType("Object") |
| intType = umlPrimitiveLibrary.getOwnedType("Integer") |
| stringType = umlPrimitiveLibrary.getOwnedType("String") |
| |
| charType = javaLibrary.getOwnedType("char") |
| } |
| |
| def setSmPack(Package smPack) { |
| this.smPack = smPack |
| } |
| |
| def getThreadStructType() { |
| return threadStructType |
| } |
| |
| def setThreadStructType(Type threadStructType) { |
| this.threadStructType = threadStructType; |
| } |
| |
| def setState_t(Type state_t) { |
| this.state_t = state_t; |
| } |
| |
| def setEvent_t(Type event_t) { |
| this.event_t = event_t; |
| } |
| |
| def getRoot() { |
| TransformationContext.current.copier.source |
| } |
| |
| def getTargetPacket() { |
| copier.target; |
| } |
| |
| def getExternalPackage(Package parentPack) { |
| if (parentPack.getNestedPackage("external") === null) { |
| var createdPack = parentPack.createNestedPackage("external") |
| createdPack.apply(NoCodeGen) |
| } |
| return parentPack.getNestedPackage("external") |
| } |
| |
| def createIntConstant(String name, int defaultValue) { |
| val constant = superContext.createOwnedAttribute(name, intType) |
| constant.isStatic = true |
| constant.isLeaf = true |
| val defaultValueUML = constant.createDefaultValue(null, null, |
| UMLPackage.eINSTANCE.literalInteger) as LiteralInteger |
| defaultValueUML.value = defaultValue; |
| } |
| |
| // each state class has a super context and ancestor context |
| def transform() { |
| val targetPack = getTargetPacket; |
| // copier = new SM2ClassCopier(mContainerClass.model, targetPack, false, true, mContainerClass, superContext, sm) |
| val ResourceSet resourceSet = targetPack.eResource.resourceSet |
| |
| // PackageUtil.loadPackage(CppUriConstants.ANSIC_LIB, resourceSet) |
| val Package profile = ElementUtils.loadPackage(StdUriConstants.UML_STD_PROFILE_URI, resourceSet) |
| if (profile instanceof Profile) { |
| PackageUtil.applyProfile(targetPack, profile as Profile, true) |
| } |
| val Package javaProfile = PackageUtil.loadPackage(JavaProfileResource.PROFILE_PATH_URI, resourceSet) |
| if (javaProfile instanceof Profile) { |
| PackageUtil.applyProfile(targetPack, javaProfile as Profile, true) |
| } |
| |
| topRegion = sm.regions.head |
| concurrency = new ConcurrencyGenerator(this) |
| eventTransform = new EventTransformation(this) |
| pseudostateGenerator = new PseudostateGenerator(this) |
| monitoringTransformation = new MonitoringTransformation(this); |
| |
| var eventMap = topRegion.allEvents |
| eventMap.forEach [ e, k | |
| if (e instanceof TimeEvent) { |
| timeEvents.add(e) |
| } else if (e instanceof CallEvent) { |
| callEvents.add(e) |
| } else if (e instanceof SignalEvent) { |
| signalEvents.add(e) |
| } else if (e instanceof ChangeEvent) { |
| changeEvents.add(e) |
| } else if (e instanceof AnyReceiveEvent) { |
| anyEvents.add(e) |
| } |
| ] |
| // create state-id enumg |
| eventIdEnum = superContext.createNestedClassifier(EVENT_ID, UMLPackage.Literals.ENUMERATION) as Enumeration |
| |
| // don't use class enumerations (rely on conversion to int) |
| createIntConstant(TIME_EVENT_LOWER_BOUND, 0); |
| |
| timeEvents.forEach [ |
| eventIdEnum.createOwnedLiteral(it.eventID) |
| ] |
| changeEvents.forEach [ |
| eventIdEnum.createOwnedLiteral(it.eventID) |
| ] |
| |
| createIntConstant(CHANGE_EVENT_LOWER_BOUND, timeEvents.size) |
| |
| var teIndex = superContext.createOwnedOperation(TE_INDEX, null, null) |
| teIndex.isStatic = true |
| teIndex.isLeaf = true |
| teIndex.createOwnedParameter('id', intType) |
| superContext.createOpaqueBehavior(teIndex, '''return id - «TIME_EVENT_LOWER_BOUND»;''') |
| val retType = teIndex.createOwnedParameter('ret', intType) |
| retType.direction = ParameterDirectionKind.RETURN_LITERAL |
| |
| superContext.createOwnedAttribute("currentEvent", event_t) |
| |
| appendImport(''' |
| import statemachineJava.EventPriority_t; |
| import statemachineJava.EventType_t; |
| ''') |
| // SM Monitoring |
| // monitoringTransformation.appendInclude |
| signalEvents.forEach [ |
| eventIdEnum.createOwnedLiteral(it.eventID) |
| ] |
| callEvents.forEach [ |
| eventIdEnum.createOwnedLiteral(it.eventID) |
| ] |
| anyEvents.forEach [ |
| eventIdEnum.createOwnedLiteral(it.eventID) |
| ] |
| |
| eventIdEnum.createOwnedLiteral(COMPLETION_EVENT.toUpperCase + "_ID") |
| |
| topRegion.allActionsTransitionsStates |
| states.filter[it.orthogonal].forEach [ |
| if (it.regions.size > MAX_NUMBER_ORTHOGONAL_REGIONS) { |
| MAX_NUMBER_ORTHOGONAL_REGIONS = it.regions.size |
| } |
| ] |
| |
| states.forEach [ |
| val triggers = new ArrayList<Trigger> |
| it.outgoings.forEach [ |
| triggers.addAll(it.triggers) |
| ] |
| val events = triggers.map[it.event] |
| val timeEvents = events.filter(TimeEvent).toList |
| states2TimeEvents.put(it, timeEvents) |
| ] |
| |
| vertexes.filter(Pseudostate).forEach [ |
| if (it.kind == PseudostateKind.JUNCTION_LITERAL) { |
| junctions.add(it) |
| } |
| ] |
| |
| // for each junction, create a class variable |
| junctions.forEach [ |
| superContext.createOwnedAttribute(it.name, intType) |
| ] |
| |
| // create state ID enumeration |
| // val stateIdEnum = targetPack.createOwnedEnumeration("StateIDEnum") as Enumeration |
| stateIdEnum = superContext.createNestedClassifier("StateIDEnum", UMLPackage.Literals.ENUMERATION) as Enumeration |
| // TODO |
| // stateStruct.createDependency(stateIdEnum) |
| // don't use class enumerations (rely on conversion to unsigned int) |
| // val stateIdEnumStyle = StereotypeUtil.applyApp(stateIdEnum, EnumStyle) |
| // stateIdEnumStyle.classEnum = false; |
| // SM Monitoring |
| monitoringTransformation.createMonitorAttributes |
| |
| // create state struct |
| createStateStruct() |
| // var stateArrayAttr = superContext.createOwnedAttribute(STATE_ARRAY_ATTRIBUTE, state_t) |
| // StereotypeUtil.apply(stateArrayAttr, Array) |
| // StereotypeUtil.apply(stateArrayAttr, Ptr) |
| // UMLUtil.getStereotypeApplication(stateArrayAttr, Array).definition = '''[«states.size»]''' |
| // create root active state ID |
| // TODO |
| superContext.createOwnedAttribute(ACTIVE_ROOT_STATE_ID, stateIdEnum) |
| superContext.createOwnedAttribute("dispatchStruct", threadStructType) |
| // TODO: the State_t class has an SM attribute typed with an external class that needs to be adapted to the current class. |
| // This could/should be avoided in the future |
| val smAttr = (threadStructType as Class).getOwnedAttribute("sm", null) |
| val smType = smAttr.type |
| smType.setName(superContext.getName()) |
| val extSM = UMLUtil.getStereotypeApplication(smType, External) |
| extSM.name = superContext.qualifiedName.replace(NamedElement.SEPARATOR, StringConstants.DOT); |
| |
| val teGetter = superContext.createOwnedOperation("getTEIndex", null, null); |
| teGetter.createOwnedParameter("id", intType); |
| teGetter.createOwnedParameter("ret", intType).setDirection(ParameterDirectionKind.RETURN_LITERAL) |
| teGetter.set(langID, '''return «superContext.name.toUpperCase»_TE_INDEX(id);''') |
| |
| val smMax = superContext.createOwnedOperation("getStateMax", null, null); |
| smMax.createOwnedParameter("ret", intType).setDirection(ParameterDirectionKind.RETURN_LITERAL) |
| smMax.set(langID, "return StateIDEnum.STATE_MAX.ordinal();") |
| |
| var state = superContext.createOwnedAttribute("states", state_t) |
| state.upper = states.size |
| createOpaqueExpressionDefaultValue(state, "state", "new State_t[StateIDEnum.STATE_MAX.ordinal()];") |
| |
| var threadStructs = superContext.createOwnedAttribute("threadStructs", threadStructType) |
| threadStructs.upper = states.size |
| createOpaqueExpressionDefaultValue(threadStructs, "threadStructs", |
| "new StructForThread_t[StateIDEnum.STATE_MAX.ordinal()];") |
| |
| var flags = superContext.createOwnedAttribute("flags", boolType) |
| flags.upper = states.size |
| createOpaqueExpressionDefaultValue(flags, "flags", "new boolean[StateIDEnum.STATE_MAX.ordinal()];") |
| |
| var timeEventFlags = superContext.createOwnedAttribute("timeEventFlags", boolType) |
| timeEventFlags.upper = states.size |
| createOpaqueExpressionDefaultValue(timeEventFlags, "timeEventFlags", |
| "new boolean[StateIDEnum.STATE_MAX.ordinal()];") |
| |
| var timeEventThreadStructs = superContext.createOwnedAttribute("timeEventThreadStructs", threadStructType) |
| timeEventThreadStructs.upper = states.size |
| createOpaqueExpressionDefaultValue(timeEventThreadStructs, "timeEventThreadStructs", |
| "new StructForThread_t[2];") |
| |
| var semaphore = ElementUtils.getQualifiedElementFromRS(superContext, SEMAPHORE_QNAME) as Type |
| var sem = superContext.createOwnedAttribute("sem", semaphore) |
| createOpaqueExpressionDefaultValue(sem, "sem", "new Semaphore(1);") |
| |
| var queue = ElementUtils.getQualifiedElementFromRS(superContext, |
| "statemachineJava::extern::PriorityBlockingQueue<Event_t>") as Type |
| var eventQueue = superContext.createOwnedAttribute("eventQueue", queue) |
| createOpaqueExpressionDefaultValue(eventQueue, "eventQueue", "new PriorityBlockingQueue<Event_t>();") |
| |
| createRegionMethods |
| |
| val startCode = '''startBehavior();''' |
| if (LifeCycleUtil.supportsLifeCycle(superContext)) { |
| // class implements life-cycle interface => add "startBehavior" call to activation function |
| LifeCycleUtil.addUnimplemented(superContext) |
| var activateOp = superContext.getOperation(LifeCycleUtil.M_ACTIVATE, null, null) |
| activateOp.appendBody(startCode) |
| } else { |
| // add startBehavior to all constructor |
| val constructors = superContext.ownedOperations.filter [ |
| it.isApplied(Create) && it.name == superContext.name |
| ] |
| if (constructors.empty) { |
| // create constructor |
| var ctor = superContext.createOwnedOperation(superContext.name, null, null) |
| ctor.apply(Create) |
| superContext.createOpaqueBehavior(ctor, ''' |
| «FOR s : states» |
| «IF s.entry.isBehaviorExist» |
| «s.name + "_" + ENTRY_NAME»= new «s.name + "_" + ENTRY_NAME»(); |
| «ENDIF» |
| «IF s.exit.isBehaviorExist» |
| «s.name + "_" + EXIT_NAME»= new «s.name + "_" + EXIT_NAME»(); |
| «ENDIF» |
| «IF s.doActivity.isBehaviorExist» |
| «s.name + "_" + DO_ACTIVITY_NAME»= new «s.name + "_" + DO_ACTIVITY_NAME»(); |
| «ENDIF» |
| |
| «ENDFOR» |
| entry_dft = new Entry_dft(); |
| doActivity_dft = new DoActivity_dft(); |
| exit_dft = new Exit_dft(); |
| startBehavior(); |
| ''') |
| } else { |
| constructors.forEach [ |
| it.appendBody(startCode) |
| ] |
| } |
| } |
| |
| monitoringTransformation.createConstructor |
| monitoringTransformation.createDestructor |
| |
| var startBehavior = superContext.createOwnedOperation("startBehavior", null, null) |
| superContext.createOpaqueBehavior(startBehavior, ''' |
| «SYSTEM_STATE_ATTR» = statemachineJava.SystemStateEnum_t.IDLE; |
| |
| // initialize all threads, the threads wait until the associated flag is set |
| for (int i = 0; i < (int) StateIDEnum.STATE_MAX.ordinal(); i++) { |
| states[i] = new State_t(this); |
| } |
| «FOR s : states» |
| «IF s.entry.isBehaviorExist» |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.name.toUpperCase»_ID.ordinal()].«ENTRY_NAME» = «s.name + "_" + ENTRY_NAME»; |
| «ENDIF» |
| «IF s.exit.isBehaviorExist» |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.name.toUpperCase»_ID.ordinal()].«EXIT_NAME» = «s.name + "_" + EXIT_NAME»; |
| «ENDIF» |
| «IF s.doActivity.isBehaviorExist» |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.name.toUpperCase»_ID.ordinal()].«DO_ACTIVITY_NAME» = «s.name + "_" + DO_ACTIVITY_NAME»; |
| «ENDIF» |
| «ENDFOR» |
| |
| for(int i = 0; i < (int) StateIDEnum.«STATE_MAX».ordinal(); i++) { |
| if («STATE_ARRAY_ATTRIBUTE»[i].«DO_ACTIVITY_NAME» != doActivity_dft) { |
| |
| StructForThread_t threadstructs = new StructForThread_t(this, ThreadFunctions.TF_DO_ACTIVITY, i,sem); |
| threadStructs[i] = threadstructs; |
| threadStructs[i].start(); |
| } |
| } |
| |
| «IF timeEvents.size > 0» |
| |
| for(int i = «TIME_EVENT_LOWER_BOUND»; i < «timeEvents.size»; i++) { |
| timeEventThreadStructs[i] = new StructForThread_t(this, ThreadFunctions.TF_TIME_EVENT,i,sem ); |
| } |
| «FOR e:timeEvents» |
| «var duration = ParseVSL.getMsDurationFromVSL((e.when.expr as OpaqueExpression).bodies.get(0))» |
| «THREAD_STRUCTS_FOR_TIMEEVENT»[«TE_INDEX»(EventId_t.«e.eventID».ordinal())].duration = «duration»; |
| «ENDFOR» |
| for(int i = «TIME_EVENT_LOWER_BOUND»; i < «timeEvents.size»; i++) { |
| timeEventThreadStructs[i].start(); |
| while (timeEventFlags[«TE_INDEX»(i)]) { |
| } |
| } |
| dispatchStruct = new StructForThread_t(this, 0, ThreadFunctions.TF_STATE_MACHINE_TYPE); |
| dispatchStruct.start(); |
| «ENDIF» |
| |
| «IF !orthogonalRegions.empty» |
| «FOR r:orthogonalRegions» |
| «REGION_TABLE»[«r.regionMacroId»] = &«superContext.name»::«r.regionMethodName»; |
| «REGION_TABLE_EXIT»[«r.regionMacroId»] = &«superContext.name»::«r.regionMethodExitName»; |
| «ENDFOR» |
| «ENDIF» |
| «IF !parallelTransitions.empty» |
| «FOR t:parallelTransitions» |
| «PARALLEL_TRANSITION_TABLE»[«concurrency.parallelTransitionId(t)»] = &«superContext.name»::«concurrency.parallelTransitionMethodName(t)»; |
| «ENDFOR» |
| «ENDIF» |
| |
| «IF changeEvents.size > 0» |
| // threads for changeEvent |
| for(int i = «CHANGE_EVENT_LOWER_BOUND»; i < «CHANGE_EVENT_LOWER_BOUND» + «changeEvents.size»; i++) { |
| «THREAD_STRUCTS_FOR_CHANGEEVENT»[«CHE_INDEX»(i)].id = i; |
| «THREAD_STRUCTS_FOR_CHANGEEVENT»[«CHE_INDEX»(i)].ptr = this; |
| «THREAD_STRUCTS_FOR_CHANGEEVENT»[«CHE_INDEX»(i)].func_type = «THREAD_FUNC_CHANGEEVENT_TYPE»; |
| «FORK_NAME»(&«THREADS_CHANGE_EVENT»[«CHE_INDEX»(i)], NULL, &«superContext.name»::«THREAD_FUNC_WRAPPER», &«THREAD_STRUCTS_FOR_CHANGEEVENT»[«CHE_INDEX»(i)]); |
| } |
| «ENDIF» |
| |
| // initialize root active state |
| // execute initial effect |
| «getRegionMethodName(topRegion)»(«topRegion.initialMacroName»); |
| ''') |
| |
| var stopBehavior = superContext.createOwnedOperation("stop", null, null) |
| superContext.createOpaqueBehavior(stopBehavior, ''' |
| «SYSTEM_STATE_ATTR» = statemachineJava.SystemStateEnum_t.IDLE; |
| dispatchStruct.interrupt(); |
| for (int i = «TIME_EVENT_LOWER_BOUND»; i < «timeEvents.size»; i++) { |
| timeEventThreadStructs[i].interrupt(); |
| } |
| for (int i = 0; i < (int) StateIDEnum.«STATE_MAX».ordinal(); i++) { |
| if («STATE_ARRAY_ATTRIBUTE»[i].«DO_ACTIVITY_NAME» != doActivity_dft) { |
| threadStructs[i].interrupt(); |
| } |
| } |
| ''') |
| |
| superContext.createOwnedAttribute("dispatchFlag", boolType) |
| |
| eventMap.forEach [ e, trans | |
| eventTransform.createEventMethod(e, trans) |
| ] |
| |
| val autoTrans = new ArrayList<Transition> |
| transitions.forEach [ |
| if (it.source instanceof State && it.triggers.map[it.event].size == 0) { |
| autoTrans.add(it) |
| } |
| ] |
| |
| eventTransform.createEventMethod(COMPLETION_EVENT, autoTrans) |
| |
| // create entry/exit/doactivity of each state |
| states.forEach [ |
| stateIdEnum.createOwnedLiteral(it.name.toUpperCase + "_ID") |
| val runnable = ElementUtils.getQualifiedElementFromRS(superContext, |
| RUNNABLE_QNAME) as Interface |
| if (it.entry.isBehaviorExist) { |
| val entry = superContext.createNestedClassifier(it.name + "_" + ENTRY_NAME, |
| UMLPackage.eINSTANCE.getClass_) as Class |
| entry.createInterfaceRealization(null, runnable) |
| |
| val entry_run = entry.createOwnedOperation("run", null, null) |
| var opaque = entry.createOpaqueBehavior(entry_run, (it.entry as OpaqueBehavior).bodies.head) |
| opaque.languages.add(langID) |
| |
| superContext.createOwnedAttribute(it.name + "_" + ENTRY_NAME, entry) |
| } |
| if (it.exit.isBehaviorExist) { |
| val exit = superContext.createNestedClassifier(it.name + "_" + EXIT_NAME, |
| UMLPackage.eINSTANCE.getClass_) as Class |
| exit.createInterfaceRealization(null, runnable) |
| |
| val exit_run = exit.createOwnedOperation("run", null, null) |
| var opaque = exit.createOpaqueBehavior(exit_run, (it.exit as OpaqueBehavior).bodies.head) |
| opaque.languages.add(langID) |
| |
| superContext.createOwnedAttribute(it.name + "_" + EXIT_NAME, exit) |
| } |
| if (it.doActivity.isBehaviorExist) { |
| doActivityList.add(it.doActivity) |
| val doActivity = superContext.createNestedClassifier(it.name + "_" + DO_ACTIVITY_NAME, |
| UMLPackage.eINSTANCE.getClass_) as Class |
| doActivity.createInterfaceRealization(null, runnable) |
| |
| val doActivity_run = doActivity.createOwnedOperation("run", null, null) |
| var opaque = doActivity.createOpaqueBehavior(doActivity_run, |
| (it.doActivity as OpaqueBehavior).bodies.head) |
| opaque.languages.add(langID) |
| |
| superContext.createOwnedAttribute(it.name + "_" + DO_ACTIVITY_NAME, doActivity) |
| } else { |
| // var doActivity = superContext.createOwnedOperation(it.name + "_" + DO_ACTIVITY_NAME, null, null) |
| // var callCompletionEvent = '''''' |
| // if (!it.composite) { |
| // //callCompletionEvent = '''process«COMPLETION_EVENT»();''' |
| // } |
| // var opaque = superContext.createOpaqueBehavior(doActivity, callCompletionEvent) |
| // opaque.languages.add(langID) |
| } |
| ] |
| stateIdEnum.createOwnedLiteral(STATE_MAX) |
| concurrency.createThreadBasedParallelism |
| |
| smPack.getOwnedType("Event_t") |
| |
| // StereotypeUtil.apply(superContext.createOwnedAttribute("currentEvent", eventClass),); |
| var eventDispatch = superContext.createOwnedOperation(EVENT_DISPATCH, null, null) |
| superContext.createOpaqueBehavior(eventDispatch, ''' |
| boolean popDeferred = false; |
| while (!Thread.currentThread().isInterrupted()) { |
| // run-to-completion: need to have a mutex here |
| try { |
| currentEvent = «EVENT_QUEUE».take(); |
| } catch (InterruptedException e) { |
| // interruption, exit loop |
| break; |
| } |
| |
| dispatchFlag = true; |
| if (currentEvent != null) { |
| int eventID = currentEvent.getEventID(); |
| |
| «FOR e : eventMap.keySet.filter[!(it instanceof CallEvent)]» |
| if (eventID == EventId_t.«e.eventID».ordinal()) { |
| «IF e instanceof SignalEvent && (e as SignalEvent).signal !== null» |
| if (currentEvent != NULL) { |
| ««« TODO no memcpy on Java |
| memcpy(&sig_«e.eventID», currentEvent->data, sizeof(); |
| process«e.eventName»(sig_«e.eventID»); |
| } |
| «ELSE» |
| process«e.eventName»(); |
| «ENDIF» |
| |
| } |
| «ENDFOR» |
| if (eventID == EventId_t.COMPLETIONEVENT_ID.ordinal()) { |
| processCompletionEvent(); |
| } |
| } |
| if («SYSTEM_STATE_ATTR» == SystemStateEnum_t.EVENT_DEFERRED) { |
| // «EVENT_QUEUE».saveDeferred(*currentEvent); |
| } |
| popDeferred = («SYSTEM_STATE_ATTR» != SystemStateEnum_t.EVENT_DEFERRED); |
| // «SYSTEM_STATE_ATTR» = SystemStateEnum_t.IDLE; |
| } |
| ''') |
| |
| concurrency.createConcurrencyForTransitions |
| /*superContext.createOwnedAttribute("dispatchThread", ptTypes.pthread) |
| * superContext.createOwnedAttribute("dispatchStruct", concurrency.threadStructType) |
| |
| * superContext.createOwnedAttribute(RUN_TO_COMPLETION_MUTEX, ptTypes.pthreadMutex) |
| * superContext.createOwnedAttribute(RUN_TO_COMPLETION_COND, ptTypes.pthreadCond) |
| */ |
| createChangeEvents |
| } |
| |
| def appendImport(String appended) { |
| val import = superContext.applyApp(Import) |
| import.manualImports = ''' |
| «import.manualImports» |
| «appended»''' |
| } |
| |
| private def createChangeEvents() { |
| new ChangeEventTransformation(this).createChangeEvents |
| } |
| |
| def String generateChangeState(State s) { |
| if (s.container == topRegion) { |
| return '''«ACTIVE_ROOT_STATE_ID» = StateIDEnum.«s.name.toUpperCase»_ID;''' |
| } |
| var rIndex = s.container.state.regions.indexOf(s.container) |
| return '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.container.state.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«rIndex»] = «s.name.toUpperCase»_ID;''' |
| } |
| |
| def String generateExitingSubStates(State parent, boolean exitParent) { |
| var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]''' |
| return ''' |
| «IF parent.orthogonal» |
| //exiting concurrent state «parent.name» |
| «FOR r:parent.regions» |
| «concurrency.generateForkCall(r, false, "0")» |
| «ENDFOR» |
| «FOR r:parent.regions» |
| «concurrency.generateJoinCall(r, false)» |
| «ENDFOR» |
| «ELSEIF parent.composite» |
| «parent.regions.head.regionMethodExitName»(); |
| «ELSE» |
| «ENDIF» |
| «IF exitParent» |
| «IF parent.doActivity.isBehaviorExist» |
| //signal to exit the doActivity of «parent.name» |
| «SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», false); |
| «ENDIF» |
| «parent.generateActivateTimeEvent("false")» |
| «IF parent.exit.isBehaviorExist» |
| //exit action of «parent.name» |
| «getFptrCall(pAttr, EXIT_NAME)»; |
| «ENDIF» |
| «ENDIF»''' |
| } |
| |
| def generateActivateTimeEvent(State s, String trueOrFalse) ''' |
| «IF states2TimeEvents.get(s) !== null» |
| «FOR te : states2TimeEvents.get(s)» |
| «SET_FLAG»(«TE_INDEX»(EventId_t.«te.eventID».ordinal()), «THREAD_FUNC_TIMEEVENT_TYPE», «trueOrFalse»); |
| «ENDFOR» |
| «ENDIF» |
| ''' |
| |
| @Deprecated |
| def String generateExitingSubStatesWithTransition(State parent, boolean exitParent, Transition t) { |
| var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]''' |
| return ''' |
| «IF parent.orthogonal» |
| «FOR r:parent.regions» |
| «FOR s:r.subvertices.filter(State).filter[!(it instanceof FinalState) && it.composite] SEPARATOR ' else '» |
| if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] == &«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.name.toUpperCase»_ID.ordinal()]) { |
| «generateExitingSubStates(s, true)» |
| } |
| «ENDFOR» |
| if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] != NULL) { |
| «FOR sub:r.subvertices.filter(State).filter[!(it instanceof FinalState)] SEPARATOR ' else '» |
| if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] == &«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«sub.name.toUpperCase»_ID.ordinal()]) { |
| «SET_FLAG»(StateIdEnum.«sub.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», false); |
| } |
| «ENDFOR» |
| «getFptrCall(STATE_ARRAY_ATTRIBUTE+"[StateIDEnum."+parent.name.toUpperCase+"_ID.ordinal()]."+ACTIVE_SUB_STATES+"["+parent.regions.indexOf(r)+"]", EXIT_NAME)»; |
| } |
| «STATE_ARRAY_ATTRIBUTE»[StateIdEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] = NULL; |
| «ENDFOR» |
| «ELSEIF parent.composite» |
| «FOR s:parent.regions.head.subvertices.filter(State).filter[!(it instanceof FinalState) && it.composite] SEPARATOR ' else '» |
| if («STATE_ARRAY_ATTRIBUTE»[StateIdEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] == «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.name.toUpperCase»_ID.ordinal()]) { |
| «generateExitingSubStates(s, true)» |
| } |
| «ENDFOR» |
| if («STATE_ARRAY_ATTRIBUTE»[StateIdEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] != NULL) { |
| «FOR sub:parent.regions.head.subvertices.filter(State).filter[!(it instanceof FinalState)] SEPARATOR ' else '» |
| if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] == «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«sub.name.toUpperCase»_ID.ordinal()]) { |
| «SET_FLAG»(StateIDEnum.«sub.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», false); |
| } |
| «ENDFOR» |
| «getFptrCall(STATE_ARRAY_ATTRIBUTE+"[StateIDEnum"+parent.name.toUpperCase+"_ID.ordinal()]."+ACTIVE_SUB_STATES+"[0]", EXIT_NAME)»; |
| } |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] = NULL; |
| «ELSE» |
| «ENDIF» |
| «IF exitParent» |
| «SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», false); |
| «getFptrCall(pAttr, EXIT_NAME)»; |
| «ENDIF» |
| «TransformationUtil.getTransitionEffect(t)»''' |
| } |
| |
| @Deprecated |
| def String generateEnteringSubStates(State parent, boolean enterParent) { |
| var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]''' |
| return ''' |
| «IF enterParent» |
| «generateChangeState(parent)» |
| «getFptrCall(pAttr, ENTRY_NAME)»; |
| // start activity of «parent.name» by calling setFlag |
| «SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true); |
| «ENDIF» |
| «IF parent.orthogonal» |
| «FOR r:parent.regions» |
| «IF TransformationUtil.findInitialState(r) !== null» |
| «TransformationUtil.getInitialEffect(r)» |
| «generateEnteringSubStates(TransformationUtil.findInitialState(r), true)» |
| «ENDIF» |
| «ENDFOR» |
| «ELSEIF parent.composite» |
| «IF TransformationUtil.findInitialState(parent.regions.head) !== null» |
| «TransformationUtil.getInitialEffect(parent.regions.head)» |
| «generateEnteringSubStates(TransformationUtil.findInitialState(parent.regions.head), true)» |
| «ENDIF» |
| «ELSE» |
| «ENDIF»''' |
| } |
| |
| @Deprecated |
| def String generateEnteringSubStates(State parent, State child, boolean enterParent, boolean gotoSubstate) { |
| var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]''' |
| return ''' |
| «IF enterParent» |
| «generateChangeState(parent)» |
| «getFptrCall(pAttr, ENTRY_NAME)»; |
| // start activity of «parent.name» by calling setFlag |
| «SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true); |
| «ENDIF» |
| «IF parent.orthogonal» |
| «FOR r:parent.regions» |
| «IF child.container == r» |
| «IF gotoSubstate» |
| «generateEnteringSubStates(child, true)» |
| «ENDIF» |
| «ELSEIF TransformationUtil.findInitialState(r) !== null» |
| «TransformationUtil.getInitialEffect(r)» |
| «generateEnteringSubStates(TransformationUtil.findInitialState(r), true)» |
| «ENDIF» |
| «ENDFOR» |
| «ELSEIF parent.composite» |
| //«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] = &«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«child.name.toUpperCase»_ID.ordinal()]; |
| «generateEnteringSubStates(child, true)» |
| «ELSE» |
| «ENDIF»''' |
| } |
| |
| @Deprecated |
| def String generateEnteringTransitiveSubStates(State parent, State child) { |
| var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]''' |
| return ''' |
| «generateChangeState(parent)» |
| «getFptrCall(pAttr, ENTRY_NAME)»; |
| // start activity of «parent.name» by calling setFlag |
| «SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true); |
| «IF parent.orthogonal» |
| «FOR r:parent.regions» |
| «IF child.container == r» |
| «generateEnteringSubStates(child, true)» |
| «ELSEIF TransformationUtil.transitiveSubStates(r).contains(child)» |
| «var nextParent = r.subvertices.filter(State).filter[TransformationUtil.transitiveSubStates(it).contains(child)].head» |
| «generateEnteringTransitiveSubStates(nextParent, child)» |
| «ELSEIF TransformationUtil.findInitialState(r) !== null» |
| «TransformationUtil.getInitialEffect(r)» |
| «generateEnteringSubStates(TransformationUtil.findInitialState(r), true)» |
| «ENDIF» |
| «ENDFOR» |
| «ELSEIF parent.composite» |
| «IF child.container.state == parent» |
| «generateEnteringSubStates(parent, child, false, false)» |
| «ELSE» |
| «var nextParent = parent.regions.head.subvertices.filter(State).filter[TransformationUtil.transitiveSubStates(it).contains(child)].head» |
| «generateEnteringTransitiveSubStates(nextParent, child)» |
| «ENDIF» |
| «ELSE» |
| «ENDIF»''' |
| } |
| |
| @Deprecated |
| def String generateEnteringTransitiveSubStates(State parent, State child, boolean enterParent, boolean gotoChild) { |
| var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]''' |
| return ''' |
| «IF enterParent» |
| «generateChangeState(parent)» |
| «getFptrCall(pAttr, ENTRY_NAME)»; |
| // start activity of «parent.name» by calling setFlag |
| «SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true); |
| «ENDIF» |
| «IF parent.orthogonal» |
| «FOR r:parent.regions» |
| «IF child.container == r» |
| «IF gotoChild» |
| «generateEnteringSubStates(child, true)» |
| «ENDIF» |
| «ELSEIF TransformationUtil.transitiveSubStates(r).contains(child)» |
| «var nextParent = r.subvertices.filter(State).filter[TransformationUtil.transitiveSubStates(it).contains(child)].head» |
| «generateEnteringTransitiveSubStates(nextParent, child)» |
| «ELSEIF TransformationUtil.findInitialState(r) !== null» |
| «TransformationUtil.getInitialEffect(r)» |
| «generateEnteringSubStates(TransformationUtil.findInitialState(r), true)» |
| «ENDIF» |
| «ENDFOR» |
| «ELSEIF parent.composite» |
| «IF child.container.state == parent» |
| «IF gotoChild» |
| «generateEnteringSubStates(parent, child, enterParent, false)» |
| «ENDIF» |
| «ELSE» |
| «var nextParent = parent.regions.head.subvertices.filter(State).filter[TransformationUtil.transitiveSubStates(it).contains(child)].head» |
| «generateEnteringTransitiveSubStates(nextParent, child)» |
| «ENDIF» |
| «ELSE» |
| «ENDIF»''' |
| } |
| |
| private def transitiveSubStates(Region r) { |
| return TransformationUtil.transitiveSubStates(r) |
| } |
| |
| private def transitiveSubStates(State s) { |
| return TransformationUtil.transitiveSubStates(s) |
| } |
| |
| @Deprecated |
| def String generateEnteringSpecial(State parent, Pseudostate child) { |
| var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(),]''' |
| return ''' |
| «generateChangeState(parent)» |
| «getFptrCall(pAttr, ENTRY_NAME)»; |
| // start activity of «parent.name» by calling setFlag |
| «SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true); |
| «IF parent.orthogonal» |
| «FOR r:parent.regions» |
| «IF child.container == r» |
| «pseudostateGenerator.generatePseudo(child)» |
| «ELSEIF r.transitiveSubStates.contains(child)» |
| «var nextParent = r.subvertices.filter(State).filter[it.transitiveSubStates.contains(child)].head» |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(),].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] = «nextParent.name.toUpperCase»_ID; |
| «generateEnteringSpecial(nextParent, child)» |
| «ELSEIF TransformationUtil.findInitialState(r) !== null» |
| «TransformationUtil.getInitialEffect(r)» |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] = «TransformationUtil.findInitialState(r).name.toUpperCase»_ID; |
| «generateEnteringSubStates(TransformationUtil.findInitialState(r), true)» |
| «ENDIF» |
| «ENDFOR» |
| «ELSEIF parent.composite» |
| «IF child.container.state == parent» |
| «pseudostateGenerator.generatePseudo(child)» |
| «ELSE» |
| «var nextParent = parent.regions.head.subvertices.filter(State).filter[it.transitiveSubStates.contains(child)].head» |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] = «nextParent.name.toUpperCase»_ID; |
| «generateEnteringSpecial(nextParent, child)» |
| «ENDIF» |
| «ELSE» |
| «ENDIF»''' |
| } |
| |
| @Deprecated |
| def String generateEnteringSpecial(State parent, Pseudostate child, Transition t) { |
| var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]''' |
| return ''' |
| «generateChangeState(parent)» |
| «TransformationUtil.getTransitionEffect(t)» |
| «getFptrCall(pAttr, ENTRY_NAME)»; |
| // start activity of «parent.name» by calling setFlag |
| «SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true); |
| |
| «IF parent.orthogonal» |
| «FOR r:parent.regions» |
| «IF child.container == r» |
| «pseudostateGenerator.generatePseudo(child)» |
| «ELSEIF r.transitiveSubStates.contains(child)» |
| «var nextParent = r.subvertices.filter(State).filter[it.transitiveSubStates.contains(child)].head» |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] = «nextParent.name.toUpperCase»_ID; |
| «generateEnteringSpecial(nextParent, child)» |
| «ELSEIF TransformationUtil.findInitialState(r) !== null» |
| «TransformationUtil.getInitialEffect(r)» |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] = «TransformationUtil.findInitialState(r).name.toUpperCase»_ID; |
| «generateEnteringSubStates(TransformationUtil.findInitialState(r), true)» |
| «ENDIF» |
| «ENDFOR» |
| «ELSEIF parent.composite» |
| «IF child.container.state == parent» |
| «pseudostateGenerator.generatePseudo(child)» |
| «ELSE» |
| «var nextParent = parent.regions.head.subvertices.filter(State).filter[it.transitiveSubStates.contains(child)].head» |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] = «nextParent.name.toUpperCase»_ID; |
| «generateEnteringSpecial(nextParent, child)» |
| «ENDIF» |
| «ELSE» |
| «ENDIF»''' |
| } |
| |
| def String generateCompletionCall(State state) { |
| var callCompletionEvent = '''''' |
| var composite = state.container.state |
| if (composite === null) { |
| callCompletionEvent = '''''' |
| } else { |
| callCompletionEvent = ''' |
| if («FOR r : composite.regions SEPARATOR ' && '»(«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«composite.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«composite.regions.indexOf(r)»] == «STATE_MAX»)«ENDFOR») { |
| «EVENT_QUEUE».push(statemachine::EventPriority_t::PRIORITY_1, NULL, COMPLETIONEVENT_ID, statemachine::COMPLETION_EVENT, «composite.name.toUpperCase»_ID); |
| }''' |
| } |
| return callCompletionEvent |
| } |
| |
| def TransitionGraph calculateTransitionGraphs(State s, Transition t) { |
| var ret = new TransitionGraph |
| ret.P.add(t.target as Pseudostate) |
| ret.T.add(t) |
| ret.S.add(s) |
| var target = t.target as Pseudostate |
| if (target.kind == PseudostateKind.JOIN_LITERAL) { |
| var ins = target.incomings.filter[it.source.container.state == s.container.state].toList |
| ret.S.addAll(ins.map[it.source].filter(State)) |
| ret.T.addAll(ins) |
| } |
| var nexts = t.target.findTrans |
| ret.T.addAll(nexts) |
| var H = nexts.map[t.target].filter(Pseudostate).filter [ |
| it.kind == PseudostateKind.DEEP_HISTORY_LITERAL || it.kind == PseudostateKind.SHALLOW_HISTORY_LITERAL |
| ] |
| ret.P.addAll(H) |
| ret.P.addAll(nexts.map[it.source].filter(Pseudostate)) |
| ret.L.addAll(nexts.map[it.target].filter(State)) |
| return ret |
| } |
| |
| private def createOpaqueExpressionDefaultValue(Property container, String name) { |
| var opaque = container.defaultValue as OpaqueExpression |
| if (opaque === null) { |
| opaque = container.createDefaultValue(name, null, UMLPackage.Literals.OPAQUE_EXPRESSION) as OpaqueExpression |
| opaque.languages.add(langID) |
| } |
| return opaque |
| } |
| |
| def createOpaqueExpressionDefaultValue(Property container, String name, String body) { |
| var opaque = container.createOpaqueExpressionDefaultValue(name) |
| if (opaque.bodies.size > 0) { |
| opaque.bodies.set(0, body) |
| } else { |
| opaque.languages.add(langID) |
| opaque.bodies.add(body) |
| } |
| return opaque |
| } |
| |
| // get transitive parent states |
| def List<State> getTransitiveParentStates(Vertex s) { |
| var ret = new ArrayList<State> |
| var parent = s.container.state |
| while (parent !== null) { |
| ret.add(parent) |
| parent = parent.container.state |
| } |
| return ret |
| } |
| |
| /* |
| def generateDelegation(State s, List<Transition> transitions) { |
| return ''' |
| «IF checkTransitiveSubStatesAcceptEvent(s, transitions)» |
| «IF s.orthogonal» |
| «ELSE» |
| |
| «ENDIF» |
| «ENDIF»''' |
| } |
| */ |
| |
| // create State_t struct |
| def createStateStruct() { |
| |
| val runnable = ElementUtils.getQualifiedElementFromRS(superContext, |
| RUNNABLE_QNAME) as Interface |
| |
| val entry_dft = superContext.createNestedClassifier("Entry_dft", UMLPackage.eINSTANCE.getClass_) as Class |
| entry_dft.createInterfaceRealization(null, runnable) |
| val entry_run = entry_dft.createOwnedOperation("run", null, null) |
| entry_dft.createOpaqueBehavior(entry_run, '') |
| |
| val doActivity_dft = superContext.createNestedClassifier("DoActivity_dft", |
| UMLPackage.eINSTANCE.getClass_) as Class |
| doActivity_dft.createInterfaceRealization(null, runnable) |
| val doActivity_run = doActivity_dft.createOwnedOperation("run", null, null) |
| doActivity_dft.createOpaqueBehavior(doActivity_run, '') |
| |
| val exit_dft = superContext.createNestedClassifier("Exit_dft", UMLPackage.eINSTANCE.getClass_) as Class |
| exit_dft.createInterfaceRealization(null, runnable) |
| val exit_run = exit_dft.createOwnedOperation("run", null, null) |
| exit_dft.createOpaqueBehavior(exit_run, '') |
| |
| superContext.createOwnedAttribute("entry_dft", entry_dft) |
| superContext.createOwnedAttribute("doActivity_dft", doActivity_dft) |
| superContext.createOwnedAttribute("exit_dft", exit_dft) |
| } |
| |
| def getFptrCall(String attr, String fptrName) { |
| |
| return '''«attr».«fptrName».run()''' |
| } |
| |
| private def Map<Event, List<Transition>> getAllEvents(Region region) { |
| val Map<Event, List<Transition>> ret = new LinkedHashMap |
| var subVertices = region.subvertices |
| var transitions = region.transitions |
| |
| transitions.forEach [ |
| for (trigger : it.triggers) { |
| if (trigger.event !== null) { |
| if (!ret.containsKey(trigger.event)) { |
| ret.put(trigger.event, new ArrayList) |
| } |
| if (!ret.get(trigger.event).contains(it)) { |
| ret.get(trigger.event).add(it) |
| } |
| } |
| } |
| ] |
| |
| subVertices.filter(typeof(State)).forEach [ |
| for (subRe : it.regions) { |
| var m = subRe.allEvents |
| for (e : m.entrySet) { |
| if (!ret.containsKey(e.key)) { |
| ret.put(e.key, e.value) |
| } else { |
| ret.get(e.key).addAll(e.value) |
| } |
| } |
| |
| } |
| ] |
| |
| return ret |
| } |
| |
| private def void getAllActionsTransitionsStates(Region region) { |
| if (!regions.contains(region)) { |
| regions.add(region) |
| } |
| transitions.addAll(region.transitions.filter[it.source !== null && it.target !== null]) |
| |
| transitions.filter[!parallelTransitions.contains(it)].forEach [ |
| if (it.source instanceof Pseudostate) { |
| if ((it.source as Pseudostate).kind == PseudostateKind.FORK_LITERAL && it.effect !== null) { |
| parallelTransitions.add(it) |
| } |
| } |
| |
| if (it.target instanceof Pseudostate) { |
| if ((it.target as Pseudostate).kind == PseudostateKind.JOIN_LITERAL && it.effect !== null) { |
| parallelTransitions.add(it) |
| } |
| } |
| ] |
| |
| for (s : region.subvertices) { |
| vertexes.add(s) |
| if (s instanceof State) { |
| if (!(s instanceof FinalState)) { |
| states.add(s) |
| } |
| |
| if (s.entry !== null && s.entry instanceof OpaqueBehavior) { |
| actions.add(s.entry as OpaqueBehavior) |
| } |
| |
| if (s.exit !== null && s.exit instanceof OpaqueBehavior) { |
| actions.add(s.exit as OpaqueBehavior) |
| } |
| |
| if (createDoActivity && s.doActivity !== null && s.doActivity instanceof OpaqueBehavior) { |
| actions.add(s.doActivity as OpaqueBehavior) |
| } |
| |
| s.regions.forEach [ |
| it.getAllActionsTransitionsStates |
| ] |
| } |
| |
| } |
| } |
| |
| public List<Region> orthogonalRegions = new ArrayList |
| |
| /** |
| * create methods for regions |
| */ |
| private def createRegionMethods() { |
| // regions.remove(topRegion) |
| for (var i = 0; i < regions.size; i++) { |
| createIntConstant(regions.get(i).regionMacroName, i) |
| |
| regions.get(i).createRegionMethod |
| createRegionMethodExit(regions.get(i)) |
| |
| if (regions.get(i).state !== null && regions.get(i).state.orthogonal) { |
| orthogonalRegions.add(regions.get(i)) |
| } |
| } |
| |
| for (var i = 0; i < orthogonalRegions.size; i++) { |
| createIntConstant(orthogonalRegions.get(i).regionMacroId, i) |
| } |
| } |
| |
| def getRegionMacroId(Region r) { |
| return '''REGION_ID_«r.state.name.toUpperCase»_«r.name.toUpperCase»''' |
| } |
| |
| def getRegionMethodName(Region r) { |
| if (r == topRegion) { |
| return '''«r.stateMachine.name»_«r.name»_Enter''' |
| } |
| return '''«r.state.name»_«r.name»_Enter''' |
| } |
| |
| def getRegionMacroName(Region r) { |
| if (r == topRegion) { |
| return '''«r.stateMachine.name.toUpperCase»_«r.name.toUpperCase»''' |
| } |
| return '''«r.state.name.toUpperCase»_«r.name.toUpperCase»''' |
| } |
| |
| def getVertexMacroName(Vertex v) { |
| if (v.container == topRegion) { |
| return '''«topRegion.stateMachine.name.toUpperCase»_«v.container.name.toUpperCase»_«v.name.toUpperCase»''' |
| } |
| return '''«v.container.state.name.toUpperCase»_«v.container.name.toUpperCase»_«v.name.toUpperCase»''' |
| } |
| |
| def getInitialMacroName(Region r) { |
| if (r == topRegion) { |
| return '''«r.stateMachine.name.toUpperCase»_«r.name.toUpperCase»_DEFAULT''' |
| } |
| return '''«r.state.name.toUpperCase»_«r.name.toUpperCase»_DEFAULT''' |
| } |
| |
| private def getSubVertexes(State state) { |
| val ret = new ArrayList<Vertex> |
| state.regions.forEach [ |
| ret.addAll(it.subvertices) |
| ] |
| return ret |
| } |
| |
| private def void createRegionMethod(Region r) { |
| var endVertexs = new ArrayList<Vertex> |
| |
| // state2TransSubVertices maps from a sub-state sub of r to its sub-vertices (of sub) which |
| // have incoming transitions outgoing from a vertex which is not a transitive sub-vertex of r |
| var Map<State, List<Vertex>> state2TransSubVertices = new HashMap |
| // looking for vertexes having transitions incoming from vertexes which are not direct or indirect sub-vertex of r |
| for (v : r.subvertices) { |
| val incomings = v.incomings.filter [ |
| it.container != v.container || |
| (it.source instanceof State && (it.source as State).subVertexes.contains(it.target)) |
| ] |
| val sources = incomings.map[it.source] |
| if (sources.size > 0) { |
| if (!endVertexs.contains(v)) { |
| endVertexs.add(v) |
| } |
| } |
| |
| // looking for vertex |
| if (v instanceof State) { |
| val subvertices = new ArrayList<Vertex> |
| v.regions.forEach[subvertices.addAll(it.allSubVertexes)] |
| for (subV : subvertices) { |
| var sourcesOfIncomings = subV.incomings.map[it.source] |
| |
| // sourcesOutSideOfR is a list of vertices having transitions targeting subV |
| var sourcesOutSideOfR = sourcesOfIncomings.filter[!subvertices.contains(it)] |
| if (sourcesOutSideOfR.size > 0) { |
| if (!state2TransSubVertices.containsKey(v)) { |
| state2TransSubVertices.put(v, new ArrayList) |
| } |
| state2TransSubVertices.get(v).add(subV) |
| } |
| } |
| } |
| } |
| var switchBody = '''''' |
| var body = '''''' |
| var macros = '''''' |
| // create macros for vertexes which are used to differentiate ways entering the region/state |
| if (TransformationUtil.firstPseudoState(r, PseudostateKind.INITIAL_LITERAL) !== null) { |
| var initialP = TransformationUtil.firstPseudoState(r, PseudostateKind.INITIAL_LITERAL) |
| var initialState = initialP.outgoings.head.target as State |
| var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«initialState.name.toUpperCase»_ID.ordinal()]''' |
| createIntConstant(r.initialMacroName, 0) |
| body += ''' |
| case «r.initialMacroName»: |
| «TransformationUtil.getTransitionEffect(initialP.outgoings.head)» |
| «generateChangeState(initialState)» |
| |
| «IF initialState.entry.isBehaviorExist» |
| «getFptrCall(pAttr, ENTRY_NAME)»; |
| // starting the counters for time events |
| «ENDIF» |
| «initialState.generateActivateTimeEvent("true")» |
| |
| «IF initialState.doActivity.isBehaviorExist || initialState.hasTriggerlessTransition» |
| // start activity of «initialState.name» by calling setFlag |
| «SET_FLAG»(StateIDEnum.«initialState.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true); |
| «ENDIF» |
| «IF initialState.composite» |
| «IF initialState.orthogonal» |
| //TODO: fork region funtions |
| «FOR subRegion: initialState.regions» |
| //«subRegion.regionMethodName»(«subRegion.initialMacroName»); |
| «concurrency.generateForkCall(subRegion, true, subRegion.initialMacroName)» |
| «ENDFOR» |
| //TODO: join region functions |
| «FOR subRegion: initialState.regions» |
| //«subRegion.regionMethodName»(«subRegion.initialMacroName»); |
| «concurrency.generateJoinCall(subRegion, true)» |
| «ENDFOR» |
| «ELSE» |
| «initialState.regions.head.regionMethodName»(«initialState.regions.head.initialMacroName»); |
| «ENDIF» |
| «ENDIF» |
| //TODO: set systemState to EVENT_CONSUMED |
| break;''' |
| } |
| for (var i = 0; i < endVertexs.size; i++) { |
| createIntConstant(endVertexs.get(i).vertexMacroName, i+1) |
| } |
| if (!superContext.isApplied(Import)) { |
| superContext.apply(Import) |
| } |
| |
| /* |
| * var header = UMLUtil.getStereotypeApplication(superContext, Include).header |
| * UMLUtil.getStereotypeApplication(superContext, Include).header = ''' |
| * «header» |
| «macros»''' */ |
| var regionMethod = superContext.createOwnedOperation(r.regionMethodName, null, null) |
| regionMethod.createOwnedParameter(ENTER_MODE_PARAM, intType) |
| for (v : endVertexs) { |
| if (v instanceof State) { |
| var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«v.name.toUpperCase»_ID.ordinal()]''' |
| body = ''' |
| «body» |
| case «v.vertexMacroName»: |
| «generateChangeState(v)» |
| «IF v.entry.isBehaviorExist» |
| «getFptrCall(pAttr, ENTRY_NAME)»; |
| «ENDIF» |
| //starting the counters for time events |
| «v.generateActivateTimeEvent("true")» |
| «IF v.doActivity.isBehaviorExist || v.hasTriggerlessTransition» |
| // start activity of «v.name» by calling setFlag |
| «SET_FLAG»(StateIDEnum.«v.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true); |
| «ENDIF» |
| «IF v.composite» |
| «IF v.orthogonal» |
| //TODO: fork region funtions |
| «FOR subRegion: v.regions» |
| //«subRegion.regionMethodName»(«subRegion.initialMacroName»); |
| «concurrency.generateForkCall(subRegion, true, subRegion.initialMacroName)» |
| «ENDFOR» |
| //TODO: join region functions |
| «FOR subRegion: v.regions» |
| //«subRegion.regionMethodName»(«subRegion.initialMacroName»); |
| «concurrency.generateJoinCall(subRegion, true)» |
| «ENDFOR» |
| «ELSE» |
| «v.regions.head.regionMethodName»(«v.regions.head.initialMacroName»); |
| «ENDIF» |
| «ENDIF» |
| //TODO: set systemState to EVENT_CONSUMED |
| break;''' |
| } else { |
| body = ''' |
| «body» |
| case «v.vertexMacroName»: |
| «pseudostateGenerator.generatePseudo(v as Pseudostate)» |
| //TODO: set systemState to EVENT_CONSUMED |
| break;''' |
| } |
| } |
| if (r != topRegion) { |
| for (e : state2TransSubVertices.entrySet) { |
| var state = e.key |
| for (transitiveSubVertex : e.value) { |
| body = ''' |
| «body» |
| case «transitiveSubVertex.vertexMacroName»: |
| «generateEnteringOnSubVertex(state, transitiveSubVertex)» |
| break;''' |
| } |
| } |
| } |
| switchBody = ''' |
| switch(«ENTER_MODE_PARAM») { |
| «body» |
| } |
| ''' |
| superContext.createOpaqueBehavior(regionMethod, switchBody) |
| } |
| |
| def generateEnteringOnSubVertex(State parent, Vertex subVertex) { |
| var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]''' |
| return ''' |
| «generateChangeState(parent)» |
| «IF parent.entry.isBehaviorExist» |
| «getFptrCall(pAttr, ENTRY_NAME)»; |
| «ENDIF» |
| //starting the counters for time events |
| «parent.generateActivateTimeEvent("true")» |
| «IF parent.doActivity.isBehaviorExist || parent.hasTriggerlessTransition» |
| // start activity of «parent.name» by calling setFlag |
| «SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true); |
| «ENDIF» |
| «IF parent.composite && parent != subVertex» |
| «IF parent.orthogonal» |
| «var toJoinList = new ArrayList<Region>» |
| «FOR r:parent.regions» |
| «IF subVertex !== null» |
| «IF subVertex.container == r» |
| «toJoinList.add(r)» |
| //«getRegionMethodName(r)»(«subVertex.vertexMacroName»); |
| «concurrency.generateForkCall(r, true, subVertex.vertexMacroName)» |
| «ELSEIF r.allSubVertexes.contains(subVertex)» |
| «toJoinList.add(r)» |
| //«getRegionMethodName(r)»(«subVertex.vertexMacroName»); |
| «concurrency.generateForkCall(r, true, subVertex.vertexMacroName)» |
| «ELSEIF TransformationUtil.findInitialState(r) !== null» |
| «toJoinList.add(r)» |
| //«getRegionMethodName(r)»(«r.initialMacroName»); |
| «concurrency.generateForkCall(r, true, r.initialMacroName)» |
| «ENDIF» |
| «ELSEIF subVertex !== null && subVertex.container === null» |
| «IF subVertex.eContainer == parent» |
| «toJoinList.add(r)» |
| «concurrency.generateForkCall(r, true, subVertex.vertexMacroName)» |
| «ELSE» |
| «toJoinList.add(r)» |
| «concurrency.generateForkCall(r, true, subVertex.vertexMacroName)» |
| «ENDIF» |
| «ELSE» |
| «IF TransformationUtil.findInitialState(r) !== null» |
| «toJoinList.add(r)» |
| //«getRegionMethodName(r)»(«r.initialMacroName»); |
| «concurrency.generateForkCall(r, true, r.initialMacroName)» |
| «ENDIF» |
| «ENDIF» |
| «ENDFOR» |
| «FOR r:toJoinList» |
| «concurrency.generateJoinCall(r, true)» |
| «ENDFOR» |
| «ELSEIF parent.composite» |
| «IF subVertex !== null» |
| «IF subVertex.container === null && subVertex.eContainer instanceof State» |
| «getRegionMethodName(parent.regions.head)»(«subVertex.vertexMacroName»); |
| «ELSEIF subVertex.container.state == parent» |
| «getRegionMethodName(parent.regions.head)»(«subVertex.vertexMacroName»); |
| «ELSE» |
| «var containingRegion = parent.regions.filter[it.allSubVertexes.contains(subVertex)].head» |
| «getRegionMethodName(containingRegion)»(«subVertex.vertexMacroName»); |
| «ENDIF» |
| «ELSE» |
| «getRegionMethodName(parent.regions.head)»(«parent.regions.head.initialMacroName»); |
| «ENDIF» |
| «ELSE» |
| «ENDIF» |
| «ELSEIF parent.composite && parent == subVertex» |
| «IF parent.orthogonal» |
| «var toJoinList = new ArrayList<Region>» |
| «FOR r:parent.regions» |
| «IF TransformationUtil.findInitialState(r) !== null» |
| «toJoinList.add(r)» |
| //«getRegionMethodName(r)»(«r.initialMacroName»); |
| «concurrency.generateForkCall(r, true, r.initialMacroName)» |
| «ENDIF» |
| «ENDFOR» |
| «FOR r:toJoinList» |
| «concurrency.generateJoinCall(r, true)» |
| «ENDFOR» |
| «ELSE» |
| «IF TransformationUtil.findInitialState(parent.regions.head) !== null» |
| «getRegionMethodName(parent.regions.head)»(«parent.regions.head.initialMacroName»); |
| «ENDIF» |
| «ENDIF» |
| «ENDIF»''' |
| } |
| |
| private def createRegionMethodExit(Region r) { |
| if (r.state === null || !r.state.composite) { |
| return |
| } |
| |
| // TODO: save states for history |
| var parent = r.state |
| var body = ''' |
| //exiting region «r.name» |
| «var regionIndex = r.state.regions.indexOf(r)» |
| «FOR s : r.subvertices.filter(State).filter[!(it instanceof FinalState) && it.composite] SEPARATOR ' else '» |
| if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«regionIndex»] == «s.name.toUpperCase»_ID) { |
| «IF s.orthogonal» |
| «FOR subRegion:s.regions» |
| «concurrency.generateForkCall(subRegion, false, "0")» |
| «ENDFOR» |
| «FOR subRegion:s.regions» |
| «concurrency.generateJoinCall(subRegion, false)» |
| «ENDFOR» |
| «ELSE» |
| «getRegionMethodExitName(s.regions.head)»(); |
| «ENDIF» |
| } |
| «ENDFOR» |
| if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«regionIndex»] != «STATE_MAX») { |
| //signal to exit the doActivity of sub-state of «parent.name» |
| «SET_FLAG»(«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0], «THREAD_FUNC_DOACTIVITY_TYPE», false); |
| «FOR sub : r.subvertices.filter(State) SEPARATOR ' else '» |
| «IF states2TimeEvents.get(sub) !== null» |
| if («sub.name.toUpperCase»_ID == «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«regionIndex»]) { |
| «sub.generateActivateTimeEvent("false")» |
| } |
| «ENDIF» |
| «ENDFOR» |
| //exit action of sub-state of «parent.name» |
| (this->*«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«STATE_ARRAY_ATTRIBUTE»[«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0]].«EXIT_NAME»)(); |
| «IF TransformationUtil.isSavehistory(topRegion, r)» |
| //save history region «r.name» of state «parent.name» |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«PREVIOUS_STATES»[«regionIndex»] = «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«regionIndex»]; |
| «ENDIF» |
| //set active sub-state of «parent.name» to «STATE_MAX» meaning NULL |
| «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«regionIndex»] = «STATE_MAX»; |
| }''' |
| var exitOp = superContext.createOwnedOperation(r.regionMethodExitName, null, null) |
| superContext.createOpaqueBehavior(exitOp, body) |
| } |
| |
| private def getRegionMethodExitName(Region r) { |
| if (r == topRegion) { |
| return '''«r.stateMachine.name»_«r.name»_Exit''' |
| } |
| return '''«r.state.name»_«r.name»_Exit''' |
| } |
| |
| def List<Vertex> allSubVertexes(Region r) { |
| val ret = new ArrayList<Vertex> |
| ret.addAll(r.subvertices) |
| r.subvertices.filter(State).forEach [ |
| it.regions.forEach [ |
| ret.addAll(it.allSubVertexes) |
| ] |
| ] |
| return ret |
| } |
| |
| private def createOpaqueBehavior(Class container, Operation op) { |
| var opaque = op.methods.filter(typeof(OpaqueBehavior)).head |
| if (opaque === null) { |
| opaque = container.createClassifierBehavior(op.name, UMLPackage.Literals.OPAQUE_BEHAVIOR) as OpaqueBehavior |
| op.methods.add(opaque) |
| opaque.languages.add(langID) |
| } |
| return opaque |
| } |
| |
| def createOpaqueBehavior(Class container, Operation op, String body) { |
| var opaque = container.createOpaqueBehavior(op) |
| if (opaque.bodies.size > 0) { |
| opaque.bodies.set(0, body) |
| } else { |
| opaque.languages.add(langID) |
| opaque.bodies.add(body) |
| } |
| return opaque |
| } |
| |
| def createDerivedOperation(Class clz, Operation source) { |
| var name = source.name |
| var derivedOp = clz.createOwnedOperation(name, null, null) |
| // OperationUtils.syncOperation(source, derivedOp) |
| derivedOp.name = name |
| derivedOp.apply(DerivedElement) |
| UMLUtil.getStereotypeApplication(derivedOp, DerivedElement).source = source |
| derivedOp.setVirtual |
| derivedOp |
| |
| } |
| |
| def copyParameters(Operation source, Operation target, boolean isCopyReturn) { |
| var name = target.name |
| // OperationUtils.syncOperation(source, target) |
| if (!isCopyReturn) { |
| var ret = target.ownedParameters.filter[it.direction == ParameterDirectionKind.RETURN_LITERAL] |
| target.ownedParameters.removeAll(ret) |
| } |
| for (stt : target.stereotypeApplications) { |
| target.apply(stt.class) |
| } |
| target.name = name |
| } |
| |
| private def setVirtual(Operation op) { |
| // StereotypeUtil.apply(op, Virtual) |
| } |
| |
| def getGuard(Transition t) { |
| return (t.guard.specification as OpaqueExpression).bodies.head |
| } |
| } |