Skip to content

Commit 1e4ccb8

Browse files
authored
Merge pull request #86 from codesoap/transition_label_tables
Structure transition labels
2 parents d5361ca + 7b99ca9 commit 1e4ccb8

File tree

2 files changed

+60
-8
lines changed

2 files changed

+60
-8
lines changed

assets/phone-graph.png

18.3 KB
Loading

graph.go

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package stateless
33
import (
44
"context"
55
"fmt"
6+
"html"
67
"sort"
78
"strings"
89
"text/template"
@@ -12,6 +13,13 @@ import (
1213
type graph struct {
1314
}
1415

16+
type transitionLabel struct {
17+
reentry []string
18+
internal []string
19+
transitioning []string
20+
ignored []string
21+
}
22+
1523
func (g *graph) formatStateMachine(sm *StateMachine) string {
1624
var sb strings.Builder
1725
sb.WriteString("digraph {\n\tcompound=true;\n\tnode [shape=Mrecord];\n\trankdir=\"LR\";\n\n")
@@ -34,7 +42,7 @@ func (g *graph) formatStateMachine(sm *StateMachine) string {
3442
dest := sm.stateConfig[sr.InitialTransitionTarget]
3543
if dest != nil {
3644
src := clusterStr(sr.State, true, true)
37-
formatOneLine(&sb, src, str(dest.State, true), "")
45+
formatOneLine(&sb, src, str(dest.State, true), `""`)
3846
}
3947
}
4048
}
@@ -124,7 +132,7 @@ func (g *graph) formatAllStateTransitions(sb *strings.Builder, sm *StateMachine,
124132
destination State
125133
}
126134

127-
lines := make(map[line][]string, len(triggerList))
135+
lines := make(map[line]transitionLabel, len(triggerList))
128136
order := make([]line, 0, len(triggerList))
129137
for _, trigger := range triggerList {
130138
switch t := trigger.(type) {
@@ -133,21 +141,27 @@ func (g *graph) formatAllStateTransitions(sb *strings.Builder, sm *StateMachine,
133141
if _, ok := lines[ln]; !ok {
134142
order = append(order, ln)
135143
}
136-
lines[ln] = append(lines[ln], formatOneTransition(t.Trigger, nil, t.Guard))
144+
transition := lines[ln]
145+
transition.ignored = append(transition.ignored, formatOneTransition(t.Trigger, nil, t.Guard))
146+
lines[ln] = transition
137147
case *reentryTriggerBehaviour:
138148
actions := g.getEntryActions(sr.EntryActions, t.Trigger)
139149
ln := line{sr.State, t.Destination}
140150
if _, ok := lines[ln]; !ok {
141151
order = append(order, ln)
142152
}
143-
lines[ln] = append(lines[ln], formatOneTransition(t.Trigger, actions, t.Guard))
153+
transition := lines[ln]
154+
transition.reentry = append(transition.reentry, formatOneTransition(t.Trigger, actions, t.Guard))
155+
lines[ln] = transition
144156
case *internalTriggerBehaviour:
145157
actions := g.getEntryActions(sr.EntryActions, t.Trigger)
146158
ln := line{sr.State, sr.State}
147159
if _, ok := lines[ln]; !ok {
148160
order = append(order, ln)
149161
}
150-
lines[ln] = append(lines[ln], formatOneTransition(t.Trigger, actions, t.Guard))
162+
transition := lines[ln]
163+
transition.internal = append(transition.internal, formatOneTransition(t.Trigger, actions, t.Guard))
164+
lines[ln] = transition
151165
case *transitioningTriggerBehaviour:
152166
src := sm.stateConfig[sr.State]
153167
if src == nil {
@@ -168,16 +182,54 @@ func (g *graph) formatAllStateTransitions(sb *strings.Builder, sm *StateMachine,
168182
if _, ok := lines[ln]; !ok {
169183
order = append(order, ln)
170184
}
171-
lines[ln] = append(lines[ln], formatOneTransition(t.Trigger, actions, t.Guard))
185+
transition := lines[ln]
186+
transition.transitioning = append(transition.transitioning, formatOneTransition(t.Trigger, actions, t.Guard))
187+
lines[ln] = transition
172188
case *dynamicTriggerBehaviour:
173189
// TODO: not supported yet
174190
}
175191
}
176192

177193
for _, ln := range order {
178194
content := lines[ln]
179-
formatOneLine(sb, str(ln.source, true), str(ln.destination, true), strings.Join(content, "\\n"))
195+
formatOneLine(sb, str(ln.source, true), str(ln.destination, true), toTransitionsLabel(content))
196+
}
197+
}
198+
199+
func toTransitionsLabel(transitions transitionLabel) string {
200+
var sb strings.Builder
201+
sb.WriteString(`<<TABLE BORDER="0">`)
202+
for _, t := range transitions.transitioning {
203+
sb.WriteString(`<TR><TD ALIGN="LEFT">`)
204+
sb.WriteString(html.EscapeString(t))
205+
sb.WriteString(`</TD></TR>`)
206+
}
207+
if len(transitions.reentry) > 0 {
208+
sb.WriteString(`<TR><TD><B>Reentry</B></TD></TR>`)
209+
for _, t := range transitions.reentry {
210+
sb.WriteString(`<TR><TD ALIGN="LEFT">`)
211+
sb.WriteString(html.EscapeString(t))
212+
sb.WriteString(`</TD></TR>`)
213+
}
214+
}
215+
if len(transitions.internal) > 0 {
216+
sb.WriteString(`<TR><TD><B>Internal</B></TD></TR>`)
217+
for _, t := range transitions.internal {
218+
sb.WriteString(`<TR><TD ALIGN="LEFT">`)
219+
sb.WriteString(html.EscapeString(t))
220+
sb.WriteString(`</TD></TR>`)
221+
}
180222
}
223+
if len(transitions.ignored) > 0 {
224+
sb.WriteString(`<TR><TD><B>Ignored</B></TD></TR>`)
225+
for _, t := range transitions.ignored {
226+
sb.WriteString(`<TR><TD ALIGN="LEFT">`)
227+
sb.WriteString(html.EscapeString(t))
228+
sb.WriteString(`</TD></TR>`)
229+
}
230+
}
231+
sb.WriteString(`</TABLE>>`)
232+
return sb.String()
181233
}
182234

183235
func formatOneTransition(trigger Trigger, actions []string, guards transitionGuard) string {
@@ -197,7 +249,7 @@ func formatOneTransition(trigger Trigger, actions []string, guards transitionGua
197249
}
198250

199251
func formatOneLine(sb *strings.Builder, fromNodeName, toNodeName, label string) {
200-
sb.WriteString(fmt.Sprintf("\t%s -> %s [label=\"%s\"", fromNodeName, toNodeName, label))
252+
sb.WriteString(fmt.Sprintf("\t%s -> %s [label=%s", fromNodeName, toNodeName, label))
201253
sb.WriteString("];\n")
202254
}
203255

0 commit comments

Comments
 (0)