diff --git a/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/Action.kt b/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/Action.kt index 6f260114..d63caa37 100644 --- a/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/Action.kt +++ b/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/Action.kt @@ -39,7 +39,6 @@ sealed interface Action { is MatchDescription -> MatchAction( - Expression.from(description.value), description.cases.associate { Expression.from(it.of) to it.then.map { desc -> create(desc) } }, @@ -61,6 +60,8 @@ sealed interface Action { is ResetDescription -> TimeoutResetAction(description.name) + is LogDescription -> LogAction(Expression.from(description.message)) + else -> error("unknown action type: ${description.javaClass.simpleName}") } @@ -96,17 +97,14 @@ internal constructor( } class MatchAction -internal constructor( - val value: Expression, - val cases: Map>, - val default: Action? = null, -) : EventRaisingAction { +internal constructor(val cases: Map>, val default: Action? = null) : + EventRaisingAction { override fun raises(): List = (cases.values + listOfNotNull(default)).filterIsInstance().flatMap { it.raises() } - override fun toString() = "MatchAction(value='$value', cases='$cases', default='$default')" + override fun toString() = "MatchAction(cases='$cases', default='$default')" } class RaiseAction internal constructor(val event: Event, val target: Expression?) : @@ -128,3 +126,5 @@ internal constructor(val name: String, val delay: Expression, val `do`: Action) class TimeoutResetAction internal constructor(val action: String) : Action { override fun toString() = "TimeoutResetAction(action='$action')" } + +class LogAction internal constructor(val message: Expression) : Action diff --git a/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/ActionCommand.kt b/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/ActionCommand.kt index 0b4b816c..9eb4c1c1 100644 --- a/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/ActionCommand.kt +++ b/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/ActionCommand.kt @@ -8,6 +8,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import mu.KotlinLogging +private val logger = KotlinLogging.logger {} + data class CommandExecutionContext( val scope: Scope, val serviceImplementationSelector: ServiceImplementationSelector, @@ -27,13 +29,14 @@ class ActionCommandFactoryImpl(private val meterRegistry: MeterRegistry) : Actio commandExecutionContext: CommandExecutionContext, ): ActionCommand = when (action) { - is EvalAction -> ActionEvalCommand(action, commandExecutionContext, this, meterRegistry) - is InvokeAction -> ActionInvokeCommand(action, commandExecutionContext, this, meterRegistry) - is MatchAction -> ActionMatchCommand(action, commandExecutionContext, this, meterRegistry) - is RaiseAction -> ActionRaiseCommand(action, commandExecutionContext, this, meterRegistry) - is TimeoutAction -> ActionTimeoutCommand(action, commandExecutionContext, this, meterRegistry) + is EvalAction -> EvalActionCommand(action, commandExecutionContext, this, meterRegistry) + is InvokeAction -> InvokeActionCommand(action, commandExecutionContext, this, meterRegistry) + is MatchAction -> MatchActionCommand(action, commandExecutionContext, this, meterRegistry) + is RaiseAction -> RaiseActionCommand(action, commandExecutionContext, this, meterRegistry) + is TimeoutAction -> TimeoutActionCommand(action, commandExecutionContext, this, meterRegistry) is TimeoutResetAction -> - ActionTimeoutResetCommand(action, commandExecutionContext, this, meterRegistry) + TimeoutResetActionCommand(action, commandExecutionContext, this, meterRegistry) + is LogAction -> LogActionCommand(action, commandExecutionContext, this, meterRegistry) else -> error("unknown action type: ${action::class.simpleName}") } } @@ -51,7 +54,7 @@ internal constructor( abstract fun execute(): List } -class ActionEvalCommand +class EvalActionCommand internal constructor( private val evalAction: EvalAction, commandExecutionContext: CommandExecutionContext, @@ -62,7 +65,7 @@ internal constructor( evalAction.expression.execute(commandExecutionContext.scope.extent).run { emptyList() } } -class ActionInvokeCommand +class InvokeActionCommand internal constructor( private val invokeAction: InvokeAction, commandExecutionContext: CommandExecutionContext, @@ -107,7 +110,7 @@ internal constructor( } } -class ActionMatchCommand +class MatchActionCommand internal constructor( private val matchAction: MatchAction, commandExecutionContext: CommandExecutionContext, @@ -116,11 +119,10 @@ internal constructor( ) : ActionCommand(commandExecutionContext, commandFactory, meterRegistry) { override fun execute(): List { val extent = commandExecutionContext.scope.extent - val matchValue = matchAction.value.execute(extent) val selectedActions: List = matchAction.cases.entries - .filter { (expression, _) -> expression.execute(extent) == matchValue } + .filter { (expression, _) -> expression.execute(extent) == true } .flatMap { it.value } .ifEmpty { listOfNotNull(matchAction.default) } @@ -128,7 +130,7 @@ internal constructor( } } -class ActionRaiseCommand +class RaiseActionCommand internal constructor( private val raiseAction: RaiseAction, commandExecutionContext: CommandExecutionContext, @@ -150,7 +152,7 @@ internal constructor( } } -class ActionTimeoutCommand +class TimeoutActionCommand internal constructor( private val timeoutAction: TimeoutAction, commandExecutionContext: CommandExecutionContext, @@ -161,7 +163,7 @@ internal constructor( listOf(commandFactory.create(timeoutAction.`do`, commandExecutionContext)) } -class ActionTimeoutResetCommand +class TimeoutResetActionCommand internal constructor( val timeoutResetAction: TimeoutResetAction, commandExecutionContext: CommandExecutionContext, @@ -170,3 +172,19 @@ internal constructor( ) : ActionCommand(commandExecutionContext, commandFactory, meterRegistry) { override fun execute(): List = emptyList() } + +class LogActionCommand +internal constructor( + private val logAction: LogAction, + commandExecutionContext: CommandExecutionContext, + commandFactory: ActionCommandFactory, + meterRegistry: MeterRegistry, +) : ActionCommand(commandExecutionContext, commandFactory, meterRegistry) { + override fun execute(): List { + logAction.message.execute(commandExecutionContext.scope.extent).toString().also { + logger.info(it) + } + + return emptyList() + } +} diff --git a/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/StateMachine.kt b/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/StateMachine.kt index fd1fe47f..504f6979 100644 --- a/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/StateMachine.kt +++ b/src/main/kotlin/at/ac/uibk/dps/cirrina/execution/object/StateMachine.kt @@ -207,7 +207,7 @@ internal constructor( val nextBatch = commands.flatMap { command -> command.execute().also { - if (command is ActionTimeoutResetCommand) stopTimeout(command.timeoutResetAction.action) + if (command is TimeoutResetActionCommand) stopTimeout(command.timeoutResetAction.action) } } execute(nextBatch) @@ -232,7 +232,7 @@ internal constructor( val command = commandFactory.create(action, createContext(this, null)) execute( listOf( - command as? ActionRaiseCommand ?: error("timeout action '$action' must be a raise action") + command as? RaiseActionCommand ?: error("timeout action '$action' must be a raise action") ) ) } diff --git a/src/main/resources/pkl/csm/csml.pkl b/src/main/resources/pkl/csm/csml.pkl index 56fca154..57275ad5 100644 --- a/src/main/resources/pkl/csm/csml.pkl +++ b/src/main/resources/pkl/csm/csml.pkl @@ -126,11 +126,14 @@ class CaseDescription { } class MatchDescription extends ActionDescription { - value: Expression cases: Listing default: ActionDescription? } +class LogDescription extends ActionDescription { + message: Expression +} + typealias EventTopic = String(matches(Regex(#"^[a-zA-Z_]\w*$"#))) typealias EventChannel = "internal"|"external"|"global"|"peripheral" @@ -188,13 +191,12 @@ typealias Transition = TransitionDescription typealias Action = ActionDescription typealias Eval = EvalDescription typealias Invoke = InvokeDescription - typealias Case = CaseDescription typealias Match = MatchDescription - typealias Raise = RaiseDescription typealias Timeout = TimeoutDescription typealias Reset = ResetDescription +typealias Log = LogDescription // Event aliases typealias Event = EventDescription diff --git a/src/test/resources/pkl/complete/completeStateMachine.pkl b/src/test/resources/pkl/complete/completeStateMachine.pkl index 638b4298..9865716b 100644 --- a/src/test/resources/pkl/complete/completeStateMachine.pkl +++ b/src/test/resources/pkl/complete/completeStateMachine.pkl @@ -37,10 +37,9 @@ sm = new csml.StateMachine { new csml.Eval { expression = "v = x" } new csml.Eval { expression = "d = d - 1" } new csml.Match { - value = "d" cases { new csml.Case { - of = "0"; then { new csml.Raise { event = new csml.Internal { topic = "e3" } } } + of = "d == 0"; then { new csml.Raise { event = new csml.Internal { topic = "e3" } } } } } default = new csml.Raise { event = new csml.Internal { topic = "e4" } } diff --git a/src/test/resources/pkl/timeout/timeoutStateMachine.pkl b/src/test/resources/pkl/timeout/timeoutStateMachine.pkl index 64fcfa3b..a633ea45 100644 --- a/src/test/resources/pkl/timeout/timeoutStateMachine.pkl +++ b/src/test/resources/pkl/timeout/timeoutStateMachine.pkl @@ -14,14 +14,10 @@ sm = new csml.StateMachine { to = "a" do { new csml.Match { - value = "v < 10" cases { - new csml.Case { of = "true"; then { new csml.Eval { expression = "v = v + 1" } } } - new csml.Case { - of = "false" - then { new csml.Raise { event = new csml.Internal { topic = "tob" } } } - } + new csml.Case { of = "v < 10"; then { new csml.Eval { expression = "v = v + 1" } } } } + default = new csml.Raise { event = new csml.Internal { topic = "tob" } } } } }