datatypes.fsm: add a fsm_graph.v tool (#13723)

pull/13733/head
Mihai Galos 2022-03-13 10:40:03 +01:00 committed by GitHub
parent 424ef0b2b8
commit 9495aacf3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 0 deletions

View File

@ -19,3 +19,36 @@ When that happens:
After all transitions are checked, and thus the state is changed, the client-specified After all transitions are checked, and thus the state is changed, the client-specified
`on_run()` handler of the now current state is called. `on_run()` handler of the now current state is called.
## Plot States and Transitions
This module includes a tool for generating dot diagrams from .v source code,
that defines a FSM. The tool is located in [fsm_graph.v](tools/fsm_graph.v).
Here is an example of how to generate a .dot file with the graph and transitions:
```bash
v run vlib/datatypes/fsm/tools/fsm_graph.v -f vlib/datatypes/fsm/fsm_test.v > graph.dot
```
You can convert the generated .dot file to a PNG file with Graphviz's `dot`
conversion tool:
```bash
v run vlib/datatypes/fsm/tools/fsm_graph.v -f vlib/datatypes/fsm/fsm_test.v > graph.dot
dot -Tpng graph.dot > graph.png
xdg-open graph.png
```
You can also visualise it with Graphviz (the `dot` command)
& ImageMagick (the `display` command):
```bash
v run vlib/datatypes/fsm/tools/fsm_graph.v -f vlib/datatypes/fsm/fsm_test.v | dot -Tpng | display
```
To view the .dot file, you can also use any of the
[Graphviz Graphical Interfaces](https://graphviz.org/resources/#graphical-interfaces)
and `xdot` in particular:
```bash
v run vlib/datatypes/fsm/tools/fsm_graph.v -f vlib/datatypes/fsm/fsm_test.v | xdot -
```
In all of the above examples, you can replace `vlib/datatypes/fsm/fsm_test.v`
with the path to your own .v code that imports and uses `fsm`.

View File

@ -0,0 +1,44 @@
import os
import flag
pub fn read_file(file string) ?[]string {
if os.is_file(file) {
text := os.read_lines(file) or {
return error(@MOD + '.' + @STRUCT + '.' + @FN + ' Could not read "$file": "$err.msg()"')
}
return text
}
return ['']
}
pub fn extract_transitions(line string) ?string {
mut result := ' '
first_comma := line.index(',') ?
second_comma := line.index_after(',', first_comma + 1)
from := line[..first_comma]
to := line[first_comma + 1..second_comma]
condition := line[second_comma + 1..]
return result + from + ' -> ' + to + ' [label=' + condition + '];'
}
pub fn get_transitions(line string) ?string {
mut raw_text := line[line.index_any('(') + 1..line.index_any(')')]
raw_text = raw_text.replace("'", '').replace(' ', '')
return extract_transitions(raw_text)
}
pub fn main() {
mut fp := flag.new_flag_parser(os.args)
file := fp.string('file', `f`, '', 'input V file with transitions to generate graph from.')
lines := read_file(file) ?
println('digraph fsm {')
for line in lines {
if line.contains('add_transition') {
println(get_transitions(line) ?)
}
}
println('}')
}