| /******************************************************************************* |
| * 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: |
| * Arnault Lapitre (CEA LIST) arnault.lapitre@cea.fr - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.efm.modeling.codegen.xlia.core; |
| |
| import org.eclipse.efm.modeling.codegen.xlia.util.PrettyPrintWriter; |
| import org.eclipse.efm.modeling.formalml.ReceiveEvent; |
| import org.eclipse.efm.modeling.formalml.TimedTransition; |
| import org.eclipse.efm.modeling.formalml.helpers.StereotypeUtil; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.uml2.uml.Behavior; |
| import org.eclipse.uml2.uml.Constraint; |
| import org.eclipse.uml2.uml.Element; |
| import org.eclipse.uml2.uml.Event; |
| import org.eclipse.uml2.uml.FinalState; |
| import org.eclipse.uml2.uml.OpaqueExpression; |
| import org.eclipse.uml2.uml.Port; |
| import org.eclipse.uml2.uml.Property; |
| import org.eclipse.uml2.uml.Pseudostate; |
| 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.Transition; |
| import org.eclipse.uml2.uml.Trigger; |
| import org.eclipse.uml2.uml.ValueSpecification; |
| import org.eclipse.uml2.uml.Vertex; |
| |
| public class StatemachineCodeGenerator extends AbstractCodeGenerator { |
| |
| /** |
| * Constructor |
| */ |
| public StatemachineCodeGenerator(MainCodeGenerator supervisor) { |
| super(supervisor); |
| } |
| |
| |
| /** |
| * performTransform dispatcher for any element to a writer |
| * @param element |
| * @param writer |
| */ |
| public void performTransformImpl(Element element, PrettyPrintWriter writer) { |
| if( element instanceof StateMachine ) { |
| transformStatemachine((StateMachine)element, writer); |
| } |
| |
| else if( element instanceof Region ) { |
| transformRegion((Region)element, writer); |
| } |
| |
| else if( element instanceof Pseudostate ) { |
| transformPseudostate((Pseudostate)element, writer); |
| } |
| else if( element instanceof FinalState ) { |
| transformFinalState((FinalState)element, writer); |
| } |
| else if( element instanceof State ) { |
| transformState((State)element, writer); |
| } |
| else if( element instanceof Vertex ) { |
| transformVertexContent((Vertex)element, writer); |
| } |
| else if( element instanceof Transition ) { |
| transformTransition((Transition)element, writer); |
| } |
| |
| else { |
| performTransformError(this, element); |
| } |
| } |
| |
| /** |
| * performTransform a StateMachine element to a writer |
| * @param element |
| * @param writer |
| */ |
| public void transformStatemachine( |
| StateMachine element, PrettyPrintWriter writer) { |
| final EList<Region> listOfRegion = element.getRegions(); |
| |
| writer.appendTab("statemachine< ") |
| .append( (listOfRegion.size() > 1) ? "and" : "or" ) |
| .append(" > ") |
| .append(element.getName()) |
| .appendEol(" {"); |
| |
| transformRegion(listOfRegion, writer); |
| |
| writer.appendTab("} // end statemachine ") |
| .appendEol2(element.getName()); |
| } |
| |
| |
| /** |
| * performTransform a Region List element to a writer |
| * @param listOfRegion |
| * @param writer |
| */ |
| public void transformRegion( |
| EList<Region> listOfRegion, PrettyPrintWriter writer) { |
| // A writer indenting with TAB + iTAB -> TAB2 |
| PrettyPrintWriter writer2 = writer.itab2(); |
| |
| int regionCount = listOfRegion.size(); |
| if( regionCount == 1 ) { |
| Region uniqRegion = listOfRegion.get(0); |
| |
| writer.appendTab("@region: // name: ") |
| .appendEol(uniqRegion.getName()); |
| |
| transformRegionBody(uniqRegion, writer2); |
| |
| writer.appendTab("// end @region: ") |
| .appendEol(uniqRegion.getName()); |
| } |
| else if( regionCount >= 2 ) { |
| writer.appendTabEol("@composite:"/*"@region:"*/); |
| |
| // A writer indenting with TAB2 + TAB -> TAB2 |
| PrettyPrintWriter writer3 = writer2.itab2(); |
| |
| for( Region itRegion : listOfRegion ) { |
| writer2.appendTab("state< or > ") |
| .append( itRegion.getName() ) |
| .appendEol(" {"); |
| |
| writer2.appendTabEol("@region:"); |
| transformRegionBody(itRegion, writer3); |
| |
| writer2.appendTab("} // end region ") |
| .appendEol2(itRegion.getName()); |
| } |
| } |
| } |
| |
| |
| /** |
| * performTransform a Region element to a writer |
| * @param element |
| * @param writer |
| */ |
| public void transformRegion(Region element, PrettyPrintWriter writer) { |
| writer.appendTab("region ") |
| .append(element.getName()) |
| .appendEol(" {"); |
| |
| // A writer indenting with TAB + iTAB -> TAB2 |
| transformRegionBody(element, writer.itab2()); |
| |
| writer.appendTab("} // end region ") |
| .appendEol2(element.getName()); |
| } |
| |
| /** |
| * performTransform a Region element to a writer |
| * @param element |
| * @param writer |
| */ |
| public void transformRegionBody(Region element, PrettyPrintWriter writer) { |
| for( Vertex itVertex : element.getSubvertices() ) { |
| if( itVertex instanceof Pseudostate ) { |
| transformPseudostate((Pseudostate)itVertex, writer); |
| } |
| else if( itVertex instanceof FinalState ) { |
| transformFinalState((FinalState)itVertex, writer); |
| } |
| else if( itVertex instanceof State ) { |
| transformState((State)itVertex, writer); |
| } |
| else if( itVertex instanceof Vertex ) { |
| transformVertex(itVertex, writer); |
| } |
| } |
| } |
| |
| /** |
| * performTransform a Pseudostate element to a writer |
| * @param element |
| * @param writer |
| */ |
| public void transformPseudostate( |
| Pseudostate element, PrettyPrintWriter writer) { |
| writer.appendTab("state< ") |
| .append(element.getKind().toString()) |
| .append(" > ") |
| .append(element.getName()) |
| .appendEol(" {"); |
| |
| transformVertexContent(element, writer); |
| |
| writer.appendTab("} // end pseudo-state ") |
| .appendEol2(element.getName()); |
| } |
| |
| /** |
| * performTransform a FinalState element to a writer |
| * @param element |
| * @param writer |
| */ |
| public void transformFinalState( |
| FinalState element, PrettyPrintWriter writer) { |
| writer.appendTab("state< final > ") |
| .append(element.getName()) |
| .appendEol(" {"); |
| |
| transformVertexContent(element, writer); |
| |
| writer.appendTab("} // end final-state ") |
| .appendEol2(element.getName()); |
| } |
| |
| /** |
| * performTransform a State element to a writer |
| * @param element |
| * @param writer |
| */ |
| public void transformState(State element, PrettyPrintWriter writer) { |
| writer.appendTab("state"); |
| if( element.isOrthogonal() ) { |
| writer.append("< and >"); |
| } |
| else if( element.isComposite() ) { |
| writer.append("< or >"); |
| } |
| writer.append(' ') |
| .append(element.getName()) |
| .appendEol(" {"); |
| |
| transformStateActivity(element, writer); |
| |
| transformVertexContent(element, writer); |
| |
| transformConnectionPoint(element, writer); |
| |
| transformRegion(element.getRegions(), writer); |
| |
| writer.appendTab("} // end state ") |
| .appendEol2(element.getName()); |
| } |
| |
| |
| public void transformConnectionPoint(State element, PrettyPrintWriter writer) { |
| // A writer indenting with TAB + iTAB -> TAB2 |
| PrettyPrintWriter writer2 = writer.itab2(); |
| |
| for( Pseudostate itPoint : element.getConnectionPoints() ) { |
| transformPseudostate(itPoint, writer2); |
| } |
| } |
| |
| |
| /** |
| * performTransform a Vertex Content element to a writer |
| * @param element |
| * @param writer |
| */ |
| public void transformStateActivity( |
| State element, PrettyPrintWriter writer) { |
| |
| // A writer indenting with TAB + iTAB -> TAB2 |
| PrettyPrintWriter writer2 = writer.itab2(); |
| |
| transformStateActivityBody("enable", element.getEntry(), writer2); |
| |
| transformStateActivityBody("irun", element.getDoActivity(), writer2); |
| |
| transformStateActivityBody("disable", element.getExit(), writer2); |
| } |
| |
| public void transformStateActivityBody( |
| String name, Behavior activity, PrettyPrintWriter writer) { |
| if( activity != null ) { |
| writer.appendTab("@") |
| .append(name) |
| .appendEol("{"); |
| |
| fSupervisor.transformBehaviorBody(activity, writer.itab2()); |
| |
| writer.appendTab("} // end ") |
| .appendEol(name); |
| } |
| } |
| |
| /** |
| * performTransform a Vertex element to a writer |
| * @param element |
| * @param writer |
| */ |
| public void transformVertex(Vertex element, PrettyPrintWriter writer) { |
| writer.appendTab("vertex ") |
| .append(element.getName()) |
| .appendEol(" {"); |
| |
| transformVertexContent(element, writer); |
| |
| writer.appendTab("} // end vertex ") |
| .appendEol2(element.getName()); |
| } |
| |
| /** |
| * performTransform a Vertex Content element to a writer |
| * @param element |
| * @param writer |
| */ |
| public void transformVertexContent( |
| Vertex element, PrettyPrintWriter writer) { |
| // A writer indenting with TAB + iTAB -> TAB2 |
| PrettyPrintWriter writer2 = writer.itab2(); |
| |
| for( Transition itTransition : element.getOutgoings() ) { |
| transformTransition(itTransition, writer2); |
| // Si ce n'est pas la dernière transition sortante, |
| // Ajout d'un saut de ligne supplémentaire |
| if( element.getOutgoings().indexOf(itTransition) != |
| (element.getOutgoings().size() - 1) ) { |
| writer.appendEol(); |
| } |
| } |
| } |
| |
| /** |
| * performTransform a Transition element to a writer |
| * @param element |
| * @param writer |
| */ |
| public void transformTransition(Transition element, PrettyPrintWriter writer) { |
| TimedTransition timedTransition = |
| StereotypeUtil.getTimedTransition(element); |
| |
| boolean isElseGuard = |
| fSupervisor.isConstraintSymbol(element.getGuard(), "else"); |
| |
| boolean isElseTransition = isElseGuard && (timedTransition == null); |
| |
| writer.appendTab("transition"); |
| if( isElseTransition ) { |
| writer.append("< else >"); |
| } |
| |
| if( element.getName() != null ) { |
| writer.append(' ') |
| .append(element.getName()); |
| } |
| writer.appendEol(" {"); |
| |
| // Triggers |
| // |
| if( fSupervisor.showTransitionSection ) { |
| writer.appendTabEol("@trigger:"); |
| } |
| for( Trigger itTrigger : element.getTriggers() ) { |
| transformTrigger(itTrigger, writer); |
| } |
| |
| // Guard |
| // |
| if( ! isElseGuard ) { |
| if( fSupervisor.showTransitionSection ) { |
| writer.appendTabEol("@guard:"); |
| } |
| Constraint guard = element.getGuard(); |
| if( guard != null ) { |
| ValueSpecification vsGuard = guard.getSpecification(); |
| if( vsGuard instanceof OpaqueExpression ) { |
| OpaqueExpression exprGuard = (OpaqueExpression) vsGuard; |
| for( String body : exprGuard.getBodies() ) { |
| if( fSupervisor.showTransitionSection ) { |
| writer.appendTab2Eol( body ); |
| } |
| else { |
| writer.appendTab2Eol("guard( " + body + " );"); |
| } |
| } |
| } |
| else { |
| writer.appendTab2(); |
| fSupervisor.transformValueSpecification(vsGuard, writer); |
| writer.appendEol(); |
| } |
| } |
| } |
| |
| // Timed Guard |
| // |
| if( fSupervisor.showTransitionSection ) { |
| writer.appendTabEol("@tguard:"); |
| } |
| if( timedTransition != null ) { |
| Constraint constraint = timedTransition.getTguard(); |
| if( constraint != null ) { |
| ValueSpecification vsTGuard = constraint.getSpecification(); |
| if( vsTGuard instanceof OpaqueExpression ) { |
| OpaqueExpression exprTGuard = (OpaqueExpression) vsTGuard; |
| for( String body : exprTGuard.getBodies() ) { |
| if( fSupervisor.showTransitionSection ) { |
| writer.appendTab2Eol( body ); |
| } |
| else { |
| writer.appendTab2Eol("tguard( " + body + " );"); |
| } |
| } |
| } |
| else { |
| writer.appendTab2(); |
| fSupervisor.transformValueSpecification(vsTGuard, writer); |
| writer.appendEol(); |
| } |
| } |
| } |
| |
| // Behavior |
| // |
| if( fSupervisor.showTransitionSection ) { |
| writer.appendTabEol("@effect:"); |
| } |
| |
| fSupervisor.transformBehaviorBody( |
| element.getEffect(), writer.itab2()); |
| |
| writer.appendTab("} --> ") |
| .append(element.getTarget().getName()) |
| .appendEol(";"); |
| } |
| |
| |
| /** |
| * performTransform a Trigger element to a writer |
| * @param trigger |
| * @param writer |
| */ |
| public void transformTrigger(Trigger trigger, PrettyPrintWriter writer) { |
| |
| writer.appendTab2("input "); |
| |
| int portCount = trigger.getPorts().size(); |
| |
| if( portCount == 1 ) { |
| writer.append( trigger.getPorts().get(0).getName() ); |
| } |
| else if( portCount > 1 ) { |
| writer.append("["); |
| boolean isnotFirst = false; |
| for( Port port : trigger.getPorts() ) { |
| if( isnotFirst ) { |
| writer.append( " , " ); |
| } |
| else { |
| isnotFirst = true; |
| } |
| writer.append( port.getName() ); |
| } |
| writer.append("]"); |
| } |
| |
| final Event event = trigger.getEvent(); |
| if( event != null ) { |
| // writer.append("/* event: ").append(event.getName()).append(" */"); |
| if( event instanceof SignalEvent ) { |
| if( portCount > 0 ) { |
| writer.append(' '); |
| } |
| writer.append(((SignalEvent) event).getSignal().getName()); |
| } |
| |
| ReceiveEvent inputEvent = StereotypeUtil.getReceiveEvent(event); |
| if( (inputEvent!=null) && (! inputEvent.getParameters().isEmpty()) ) { |
| writer.append('('); |
| boolean isnotFirst = false; |
| for( Property param : inputEvent.getParameters() ) { |
| if( isnotFirst ) { |
| writer.append(", "); |
| } |
| else { |
| isnotFirst = true; |
| } |
| writer.append(param.getName()); |
| } |
| writer.append(")"); |
| } |
| } |
| |
| writer.appendEol(";"); |
| } |
| |
| } |