]>
git.proxmox.com Git - ceph.git/blob - ceph/doc/scripts/gen_state_diagram.py
6 def do_filter(generator
):
7 return acc_lines(remove_multiline_comments(to_char(remove_single_line_comments(generator
))))
10 def acc_lines(generator
):
17 yield current
.lstrip("\n")
21 def to_char(generator
):
22 for line
in generator
:
30 def remove_single_line_comments(generator
):
32 if len(i
) and i
[0] == '#':
34 yield re
.sub(r
'//.*', '', i
)
37 def remove_multiline_comments(generator
):
40 for char
in generator
:
63 class StateMachineRenderer(object):
65 self
.states
= {} # state -> parent
66 self
.machines
= {} # state-> initial
67 self
.edges
= {} # event -> [(state, state)]
69 self
.context
= [] # [(context, depth_encountered)]
70 self
.context_depth
= 0
71 self
.state_contents
= {}
73 self
.clusterlabel
= {}
76 return "-------------------\n\nstates: %s\n\n machines: %s\n\n edges: %s\n\n context %s\n\n state_contents %s\n\n--------------------" % (
84 def read_input(self
, input_lines
):
85 for line
in input_lines
:
88 self
.get_context(line
)
90 def get_context(self
, line
):
91 match
= re
.search(r
"(\w+::)*::(?P<tag>\w+)::\w+\(const (?P<event>\w+)",
94 self
.context
.append((match
.group('tag'), self
.context_depth
, match
.group('event')))
96 self
.context_depth
+= 1
98 self
.context_depth
-= 1
99 while len(self
.context
) and self
.context
[-1][1] == self
.context_depth
:
102 def get_state(self
, line
):
103 if "boost::statechart::state_machine" in line
:
105 r
"boost::statechart::state_machine<\s*(\w*),\s*(\w*)\s*>",
108 raise "Error: malformed state_machine line: " + line
109 self
.machines
[tokens
.group(1)] = tokens
.group(2)
110 self
.context
.append((tokens
.group(1), self
.context_depth
, ""))
112 if "boost::statechart::state" in line
:
114 r
"boost::statechart::state<\s*(\w*),\s*(\w*)\s*,?\s*(\w*)\s*>",
117 raise "Error: malformed state line: " + line
118 self
.states
[tokens
.group(1)] = tokens
.group(2)
119 if tokens
.group(2) not in self
.state_contents
.keys():
120 self
.state_contents
[tokens
.group(2)] = []
121 self
.state_contents
[tokens
.group(2)].append(tokens
.group(1))
122 if tokens
.group(3) is not "":
123 self
.machines
[tokens
.group(1)] = tokens
.group(3)
124 self
.context
.append((tokens
.group(1), self
.context_depth
, ""))
127 def get_event(self
, line
):
128 if "boost::statechart::transition" in line
:
129 for i
in re
.finditer(r
'boost::statechart::transition<\s*([\w:]*)\s*,\s*(\w*)\s*>',
131 if i
.group(1) not in self
.edges
.keys():
132 self
.edges
[i
.group(1)] = []
133 if len(self
.context
) is 0:
134 raise "no context at line: " + line
135 self
.edges
[i
.group(1)].append((self
.context
[-1][0], i
.group(2)))
136 i
= re
.search("return\s+transit<\s*(\w*)\s*>()", line
)
138 if len(self
.context
) is 0:
139 raise "no context at line: " + line
140 if self
.context
[-1][2] is "":
141 raise "no event in context at line: " + line
142 if self
.context
[-1][2] not in self
.edges
.keys():
143 self
.edges
[self
.context
[-1][2]] = []
144 self
.edges
[self
.context
[-1][2]].append((self
.context
[-1][0], i
.group(1)))
148 for state
in self
.machines
.keys():
149 if state
not in self
.states
.keys():
150 top_level
.append(state
)
151 print >> sys
.stderr
, "Top Level States: ", str(top_level
)
152 print """digraph G {"""
154 print """\tcompound=true;"""
155 for i
in self
.emit_state(top_level
[0]):
157 for i
in self
.edges
.keys():
158 for j
in self
.emit_event(i
):
162 def emit_state(self
, state
):
163 if state
in self
.state_contents
.keys():
164 self
.clusterlabel
[state
] = "cluster%s" % (str(self
.subgraphnum
),)
165 yield "subgraph cluster%s {" % (str(self
.subgraphnum
),)
166 self
.subgraphnum
+= 1
167 yield """\tlabel = "%s";""" % (state
,)
168 yield """\tcolor = "blue";"""
169 for j
in self
.state_contents
[state
]:
170 for i
in self
.emit_state(j
):
175 for (k
, v
) in self
.machines
.items():
177 yield state
+"[shape=Mdiamond];"
183 def emit_event(self
, event
):
190 for (fro
, to
) in self
.edges
[event
]:
191 appendix
= ['label="%s"' % (event
,)]
192 if fro
in self
.machines
.keys():
193 appendix
.append("ltail=%s" % (self
.clusterlabel
[fro
],))
194 while fro
in self
.machines
.keys():
195 fro
= self
.machines
[fro
]
196 if to
in self
.machines
.keys():
197 appendix
.append("lhead=%s" % (self
.clusterlabel
[to
],))
198 while to
in self
.machines
.keys():
199 to
= self
.machines
[to
]
200 yield("%s -> %s %s;" % (fro
, to
, append(appendix
)))
203 INPUT_GENERATOR
= do_filter(sys
.stdin
.xreadlines())
204 RENDERER
= StateMachineRenderer()
205 RENDERER
.read_input(INPUT_GENERATOR
)