blob: 40ae6f7a8c24c2d2efbd0b2db0b5015d323b9b52 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 protos software gmbh (http://www.protos.de).
* 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:
* Henrik Rentz-Reichert (initial contribution)
*
*******************************************************************************/
package org.eclipse.etrice.generator.generic
import com.google.inject.Inject
import org.eclipse.etrice.core.fsm.fSM.GuardedTransition
import org.eclipse.etrice.core.fsm.fSM.NonInitialTransition
import org.eclipse.etrice.core.fsm.fSM.RefinedState
import org.eclipse.etrice.core.fsm.fSM.State
import org.eclipse.etrice.core.fsm.fSM.TriggeredTransition
import org.eclipse.etrice.core.fsm.util.FSMHelpers
import org.eclipse.etrice.core.genmodel.fsm.TriggerExtensions
import org.eclipse.etrice.core.genmodel.fsm.fsmgen.GraphContainer
import org.eclipse.etrice.core.genmodel.fsm.fsmgen.Link
import org.eclipse.etrice.core.genmodel.fsm.fsmgen.Node
import org.eclipse.etrice.generator.fsm.generic.AbstractStateMachineGenerator
/**
* A target language independent generator of the state machine implementation
*/
class GenericStateMachineGenerator extends AbstractStateMachineGenerator {
@Inject
protected extension TriggerExtensions
@Inject
protected extension FSMHelpers
/**
* generates the code of the whole state machine, consisting of constants + methods
*
* @param xpmc the {@link ExpandedModelComponent}
* @return the generated code
*/
def genStateMachine(GraphContainer gc) '''
«genStateMachineConstants(gc)»
«genStateMachineMethods(gc, true)»
'''
/**
* generates the constants for the state machine
*/
def genStateMachineConstants(GraphContainer gc) '''
/* state IDs */
«gc.genStateIdConstants»
/* transition chains */
«gc.genTransitionChainConstants»
/* triggers */
«gc.genTriggerConstants»
'''
/**
* generates the methods for the state machine codes and state switching
*
* @param xpmc the {@link ExpandedModelComponent}
* @param generateImplemenation or declaration only
* @return the generated code
*/
def genStateMachineMethods(GraphContainer gc, boolean generateImplementation) '''
«genExtra(gc, generateImplementation)»
/* Entry and Exit Codes */
«gc.genEntryAndExitCodes(generateImplementation)»
/* Action Codes */
«gc.genActionCodes(generateImplementation)»
/* State Switch Methods */
«gc.genStateSwitchMethods(generateImplementation)»
'''
/**
* generate a transition guard if applicable
*
* @param tt a {@link TriggeredTransition}
* @param trigger a trigger string
* @param xpmc an expanded actor class
* @return the generated code
*/
override String genTriggeredTransitionGuard(Link tt, String trigger, GraphContainer gc) {
val tr = (tt.transition as TriggeredTransition).triggers.findFirst(trig|trig.isMatching(trigger))
'''
«IF tr.hasGuard()»
if («translator.getTranslatedCode(tr.guard.guard)»)
«ENDIF»
'''
}
override String genGuardedTransitionGuard(Link link, String trigger, GraphContainer gc) {
'''
«translator.getTranslatedCode((link.transition as GuardedTransition).guard)»
'''
}
override String genActionCodeMethod(GraphContainer gc, Link link, boolean generateImplementation) {
var hasArgs = !link.chainHeads.empty && link.chainHeads.forall[transition instanceof NonInitialTransition && !(transition instanceof GuardedTransition)]
val opScope = langExt.operationScope(gc.className, false)
val opScopePriv = if (langExt.usesInheritance) opScope else ""
val ifItemPtr = "InterfaceItemBase"+langExt.pointerLiteral()
val constIfItemPtr = if (langExt.usesPointers)
"const "+ifItemPtr
else
ifItemPtr
if (generateImplementation) {
'''
«langExt.accessLevelProtected»void «opScopePriv»«link.transition.getActionCodeOperationName()»(«langExt.selfPointer(gc.className, hasArgs)»«IF hasArgs»«constIfItemPtr» ifitem«transitionChainGenerator.generateArgumentList(gc, link)»«ENDIF») {
«translator.getTranslatedCode(link.transition.action)»
}
'''
}
else {
'''
«langExt.accessLevelProtected»«langExt.makeOverridable»void «link.transition.getActionCodeOperationName()»(«langExt.selfPointer(gc.className, hasArgs)»«IF hasArgs»«constIfItemPtr» ifitem«transitionChainGenerator.generateArgumentList(gc, link)»«ENDIF»);
'''
}
}
/**
* generate action code method implementations or declarations
*
* @param xpax the {@link ExpandedModelComponent}
* @param state the {@link State}
* @param generateImplementation if only declarations should be generated then <code>false</code> has to be passed
* @return the generated code
*/
override String genActionCodeMethods(GraphContainer gc, Node node, boolean generateImplementation) {
val mc = gc.modelComponent
val selfPtr = langExt.selfPointer(gc.className, false)
val opScope = langExt.operationScope(gc.className, false)
val opScopePriv = if (langExt.usesInheritance)
opScope
else
""
val state = node.stateGraphNode as State
val entryOp = state.getEntryCodeOperationName()
val exitOp = state.getExitCodeOperationName()
val doOp = state.getDoCodeOperationName()
var entry = translator.getTranslatedCode(state.entryCode)
var exit = translator.getTranslatedCode(state.exitCode)
var docode = translator.getTranslatedCode(state.doCode)
if (state instanceof RefinedState) {
val inhEntry = translator.getTranslatedCode(state.inheritedEntryCode)
val inhExit = translator.getTranslatedCode(state.inheritedExitCode)
val inhDo = translator.getTranslatedCode(state.inheritedDoCode)
if (langExt.usesInheritance) {
// we call the super method in the generated code
val baseName = mc.base.className
if (state.inheritedEntryCode.hasDetailCode)
entry = langExt.superCall(baseName, entryOp, "") + entry
if (state.inheritedExitCode.hasDetailCode)
exit = exit + langExt.superCall(baseName, exitOp, "")
if (state.inheritedDoCode.hasDetailCode)
docode = langExt.superCall(baseName, doOp, "") + docode
}
else {
// the inherited code is added directly
entry = inhEntry + entry
exit = exit + inhExit
docode = inhDo + docode
}
}
'''
«IF !entry.empty»
«IF generateImplementation»
«langExt.accessLevelProtected»void «opScopePriv»«entryOp»(«selfPtr») {
«entry»
}
«ELSE»
«langExt.accessLevelProtected»«langExt.makeOverridable»void «entryOp»(«selfPtr»);
«ENDIF»
«ENDIF»
«IF !exit.empty»
«IF generateImplementation»
«langExt.accessLevelProtected»void «opScopePriv»«exitOp»(«selfPtr») {
«exit»
}
«ELSE»
«langExt.accessLevelProtected»«langExt.makeOverridable»void «exitOp»(«selfPtr»);
«ENDIF»
«ENDIF»
«IF !docode.empty»
«IF generateImplementation»
«langExt.accessLevelProtected» void «opScopePriv»«doOp»(«selfPtr») {
«docode»
}
«ELSE»
«langExt.accessLevelProtected»«langExt.makeOverridable»void «doOp»(«selfPtr»);
«ENDIF»
«ENDIF»
'''
}
/**
* let derived class add extra code after definition of constants
*
* @param xpmc an expanded actor class
* @param generateImplementation or declaration only
* @return the generated code
*/
def genExtra(GraphContainer gc, boolean generateImplementation) {''''''}
}