From 9b5905739479467e05dbd5a99f215a86c22411b7 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 26 Mar 2021 21:29:23 -0400 Subject: [PATCH] Added support for external transitions (could use a full test). --- .../xyz/colinholzman/makina/CodeGenerator.kt | 10 ++--- .../src/xyz/colinholzman/makina/State.kt | 8 +--- .../src/xyz/colinholzman/makina/Transition.kt | 29 +++++++++---- .../test/xyz/colinholzman/makina/StateTest.kt | 1 + .../xyz/colinholzman/makina/TransitionTest.kt | 43 ++++++++++++------- 5 files changed, 55 insertions(+), 36 deletions(-) diff --git a/makina-compiler/src/xyz/colinholzman/makina/CodeGenerator.kt b/makina-compiler/src/xyz/colinholzman/makina/CodeGenerator.kt index 4a7e354..0fba398 100644 --- a/makina-compiler/src/xyz/colinholzman/makina/CodeGenerator.kt +++ b/makina-compiler/src/xyz/colinholzman/makina/CodeGenerator.kt @@ -56,7 +56,7 @@ class CodeGenerator(val machine: Machine, private fun generateExitActions(handler: Handler.Event, sourceState: State, activeLeafState: State, output: PrintWriter) { if (handler.target != null) output.apply { val target = handler.getTargetState(sourceState, machine) - val transition = Transition(activeLeafState, target) + val transition = Transition(activeLeafState, sourceState, target) val exitSet = transition.getExitSet() for (stateToExit in exitSet) { for (exit in stateToExit.handlers.filterIsInstance()) { @@ -70,10 +70,10 @@ class CodeGenerator(val machine: Machine, private fun generateEntryActions(handler: Handler.Event, sourceState: State, activeLeafState: State, output: PrintWriter) { if (handler.target != null) output.apply { val target = handler.getTargetState(sourceState, machine) - val transition = Transition(activeLeafState, target) - val entrySet = transition.getEntrySet() + target.getDefaultEntrySet() - val leafStateTarget = if (target.isLeafState()) target else target.getDefaultEntrySet().last() - println("\t\t\tself->state = ${machine.id}_${leafStateTarget.getFullyQualifiedIdString()};") + val transition = Transition(activeLeafState, sourceState, target) + val entrySet = transition.getEntrySet() + val targetLeafState = entrySet.last() + println("\t\t\tself->state = ${machine.id}_${targetLeafState.getFullyQualifiedIdString()};") for (stateToEnter in entrySet) { for (entry in stateToEnter.handlers.filterIsInstance()) { println("\t\t\t${entry.action}(self, event);") diff --git a/makina-compiler/src/xyz/colinholzman/makina/State.kt b/makina-compiler/src/xyz/colinholzman/makina/State.kt index 96e6678..4b409b5 100644 --- a/makina-compiler/src/xyz/colinholzman/makina/State.kt +++ b/makina-compiler/src/xyz/colinholzman/makina/State.kt @@ -88,7 +88,8 @@ class State(val id: String, return ret } - fun isDescendantOf(other: State): Boolean { + fun isDescendantOf(other: State?): Boolean { + if (other == null) return true var current: State? = this while (current != null) { if (current.parent == other) @@ -172,11 +173,6 @@ class State(val id: String, } return null } - - //returns true if all states are descendants of the same ancestor - fun List.areRelated(): Boolean { - return map { it.getStateConfiguration().getParentState() }.toSet().size == 1 - } } } \ No newline at end of file diff --git a/makina-compiler/src/xyz/colinholzman/makina/Transition.kt b/makina-compiler/src/xyz/colinholzman/makina/Transition.kt index a9b6eb6..d8130d0 100644 --- a/makina-compiler/src/xyz/colinholzman/makina/Transition.kt +++ b/makina-compiler/src/xyz/colinholzman/makina/Transition.kt @@ -1,17 +1,28 @@ package xyz.colinholzman.makina -import xyz.colinholzman.makina.State.Companion.areRelated import xyz.colinholzman.makina.State.Companion.getLCCA -data class Transition(val source: State, val target: State) { - init { - if (!source.isLeafState()) - throw RuntimeException("source must be a leaf state") - } +data class Transition(val activeLeafState: State, + val source: State, val target: State, + val kind: Target.Kind = Target.Kind.DEFAULT) { fun getEntrySet(): List { - return (listOf(target) + target.getProperAncestors(listOf(source, target).getLCCA())).reversed() + return (listOf(target) + target.getDefaultEntrySet() + target.getProperAncestors(getDomain())) + .sortedBy { it.getDepth() } } + fun getExitSet(): List { - return listOf(source) + source.getProperAncestors(listOf(source, target).getLCCA()) + val domain = getDomain() + return activeLeafState.getStateConfiguration().states + .filter { it.isDescendantOf(domain) } + .sortedBy { it.getDepth() }.reversed() + } + + fun getDomain(): State? { + return if (kind == Target.Kind.DEFAULT + && !source.isLeafState() + && target.isDescendantOf(source)) + source + else + listOf(source, target).getLCCA() } -} \ No newline at end of file +} diff --git a/makina-compiler/test/xyz/colinholzman/makina/StateTest.kt b/makina-compiler/test/xyz/colinholzman/makina/StateTest.kt index 734bff2..7137565 100644 --- a/makina-compiler/test/xyz/colinholzman/makina/StateTest.kt +++ b/makina-compiler/test/xyz/colinholzman/makina/StateTest.kt @@ -134,6 +134,7 @@ internal class StateTest { bar.parent = foo assert(bar.isDescendantOf(foo)) assertFalse(foo.isDescendantOf(bar)) + assertTrue(foo.isDescendantOf(null)) } @Test diff --git a/makina-compiler/test/xyz/colinholzman/makina/TransitionTest.kt b/makina-compiler/test/xyz/colinholzman/makina/TransitionTest.kt index 02fccee..70b79d0 100644 --- a/makina-compiler/test/xyz/colinholzman/makina/TransitionTest.kt +++ b/makina-compiler/test/xyz/colinholzman/makina/TransitionTest.kt @@ -7,6 +7,7 @@ import xyz.colinholzman.makina.TestStates.Companion.s1 import xyz.colinholzman.makina.TestStates.Companion.s11 import xyz.colinholzman.makina.TestStates.Companion.s111 import xyz.colinholzman.makina.TestStates.Companion.s12 +import xyz.colinholzman.makina.TestStates.Companion.s121 import xyz.colinholzman.makina.TestStates.Companion.s122 import xyz.colinholzman.makina.TestStates.Companion.s2 import xyz.colinholzman.makina.TestStates.Companion.s21 @@ -15,25 +16,35 @@ internal class TransitionTest { @Test fun getEntrySet() { - var transition = Transition(s111, s122) - assertEquals(listOf(s12, s122), transition.getEntrySet()) - transition = Transition(s111, s21) - assertEquals(listOf(s2, s21), transition.getEntrySet()) - transition = Transition(s111, s111) - assertEquals(listOf(s111), transition.getEntrySet()) - transition = Transition(s111, s1) - assertEquals(listOf(s1), transition.getEntrySet()) + assertEquals(listOf(s12, s122), Transition(s111, s111, s122).getEntrySet()) + assertEquals(listOf(s2, s21), Transition(s111, s111, s21).getEntrySet()) + assertEquals(listOf(s111), Transition(s111, s111, s111).getEntrySet()) + assertEquals(listOf(s1, s12, s121), Transition(s111, s111, s1).getEntrySet()) + assertEquals(listOf(s1, s12, s121), Transition(s111, s1, s1).getEntrySet()) + assertEquals(listOf(s2, s21), Transition(s111, s111, s2).getEntrySet()) } @Test fun getExitSet() { - var transition = Transition(s111, s122) - assertEquals(listOf(s111, s11), transition.getExitSet()) - transition = Transition(s111, s21) - assertEquals(listOf(s111, s11, s1), transition.getExitSet()) - transition = Transition(s111, s111) - assertEquals(listOf(s111), transition.getExitSet()) - transition = Transition(s111, s1) - assertEquals(listOf(s111, s11, s1), transition.getExitSet()) + assertEquals(listOf(s111, s11), Transition(s111, s111, s122).getExitSet()) + assertEquals(listOf(s111, s11, s1), Transition(s111, s111, s21).getExitSet()) + assertEquals(listOf(s111), Transition(s111, s111, s111).getExitSet()) + assertEquals(listOf(s111, s11, s1), Transition(s111, s111, s1).getExitSet()) + assertEquals(listOf(s111, s11, s1), Transition(s111, s1, s1).getExitSet()) + assertEquals(listOf(s111, s11), Transition(s111, s1, s12).getExitSet()) + assertEquals(listOf(s111, s11, s1), Transition(s111, s1, s12, Target.Kind.EXTERNAL).getExitSet()) + assertEquals(listOf(s111, s11, s1), Transition(s111, s1, s121, Target.Kind.EXTERNAL).getExitSet()) + assertEquals(listOf(s111), Transition(s111, s111, s111, Target.Kind.EXTERNAL).getExitSet()) + assertEquals(listOf(s111, s11, s1), Transition(s111, s1, s1, Target.Kind.EXTERNAL).getExitSet()) + } + + @Test + fun getDomain() { + assertEquals(null, Transition(s111, s1, s2).getDomain()) + assertEquals(null, Transition(s111, s11, s21).getDomain()) + assertEquals(s1, Transition(s111, s11, s12).getDomain()) + assertEquals(s1, Transition(s111, s1, s11).getDomain()) + assertEquals(null, Transition(s111, s1, s11, Target.Kind.EXTERNAL).getDomain()) + assertEquals(null, Transition(s111, s11, s1).getDomain()) } } \ No newline at end of file