This work is licensed under Apache License 2.0
This project will explore many ways to visualize KFSM definitions.
The Kotlin source containing the FSM is parsed with an ANTLR parser generated at build time from the Kotlin grammar
(src/main/antlr, taken from the develop branch of kotlin-spec, see KOTLIN_SPEC_COMMIT).
No external grammar tools need to be built or installed. Run ./download-kotlin-spec-tools.sh to update the grammar from kotlin-spec develop and rebuild.
Getting Started
repositories {
maven {
url 'https://oss.sonatype.org/content/groups/public/'
}
mavenCentral()
}
dependencies {
testImplementation 'org.infosmid:kfsm-viz:2.0.0'
}
You can implement a test method to generate the required statemachine model artifacts, or you can configure the kfsm-viz-plugin for Gradle to produce visualizations.
PlantUML Statemachine Diagram
By parsing the source code we can extract the details of the guard expressions and actions. This requires that you place one definition inside of one class. There is a chance for the parser based solution to misbehave. We request that you log an issue with the problematic FSM definition.
@Test
fun produceVisualizationTurnstileFSM() {
println("== TurnStile")
val visualisation = parseStateMachine("TurnstileFSM", File("src/test/kotlin/Turnstile.kt"))
File("generated-parsed", "turnstile.plantuml").writeText(plantUml(visualisation, true)) (1)
File("generated-parsed", "turnstile-simple.plantuml").writeText(plantUml(visualisation, false)) (2)
}
-
Detailed Included in State Diagram
-
Detail like actions and guards ignored
AsciiDoctor State Table from VisualStatemachineDefinition
@Test
fun produceVisualizationTurnstileFSM() {
println("== TurnStile")
val visualisation = parseStateMachine("TurnstileFSM", File("src/test/kotlin/Turnstile.kt"))
File("generated-parsed", "turnstile.adoc").writeText(asciiDoc(visualisation))
}
Generated from parsed VisualStateDefinition
We generated an asciidoc table as well as a plantuml statemachine model.
SimpleTurnstileFSM State Chart
SimpleTurnstileFSM State Map
| Start | Event[Guard] | Target | Action |
|---|---|---|---|
UNLOCKED |
|||
LOCKED |
COIN |
UNLOCKED |
|
UNLOCKED |
PASS |
LOCKED |
|
UNLOCKED |
COIN |
UNLOCKED |
|
PayingTurnstileFSM State Chart
PayingTurnstileFSM State Map
| Start | Event[Guard] | Target | Action |
|---|---|---|---|
UNLOCKED |
|||
LOCKED |
COIN |
COINS |
|
LOCKED |
COIN |
COINS |
|
UNLOCKED |
COIN |
UNLOCKED |
|
UNLOCKED |
PASS |
LOCKED |
|
State Map coins
| Start | Event[Guard] | Target | Action |
|---|---|---|---|
COINS |
<<automatic>> |
UNLOCKED |
|
COINS |
<<automatic>> |
UNLOCKED |
|
COINS |
COIN |
COINS |
|
SecureTurnstileFSM State Chart
SecureTurnstileFSM State Map
| Start | Event[Guard] | Target | Action |
|---|---|---|---|
UNLOCKED |
|||
LOCKED |
CARD |
LOCKED |
|
LOCKED |
CARD |
LOCKED |
|
LOCKED |
CARD |
UNLOCKED |
|
LOCKED |
CARD |
LOCKED |
|
UNLOCKED |
CARD |
LOCKED |
|
UNLOCKED |
PASS |
LOCKED |
|
PacketReaderFSM State Chart
PacketReaderFSM State Map
| Start | Event[Guard] | Target | Action |
|---|---|---|---|
START |
CTRL |
RCVPCKT |
|
RCVPCKT |
CTRL |
RCVDATA |
|
RCVPCKT |
BYTE |
RCVCHK |
|
RCVDATA |
BYTE |
RCVDATA |
|
RCVDATA |
CTRL |
RCVPCKT |
|
RCVDATA |
ESC |
RCVESC |
|
RCVESC |
ESC |
RCVDATA |
|
RCVESC |
CTRL |
RCVDATA |
|
RCVCHK |
BYTE |
RCVCHK |
|
RCVCHK |
ESC |
RCVCHKESC |
|
RCVCHK |
CTRL |
CHKSUM |
|
CHKSUM |
<<automatic>> |
[*] |
|
CHKSUM |
<<automatic>> |
[*] |
|
RCVCHKESC |
ESC |
RCVCHK |
|
RCVCHKESC |
CTRL |
RCVCHK |
|
FAQ
What is with the semi-colons?
For guard expression we have decided the keep them on one line and we made the decision to print the implicit semi-colons to remove ambiguity.