1
+ #include < networkprotocoldsl/operation/statemachineoperation.hpp>
2
+
3
+ #include < networkprotocoldsl/operation/staticcallable.hpp>
4
+ #include < networkprotocoldsl/operationconcepts.hpp>
5
+ #include < networkprotocoldsl/print_optreenode.hpp>
6
+ #include < networkprotocoldsl/value.hpp>
7
+
8
+ #include < ostream>
9
+ #include < thread>
10
+
11
+ #include < cassert>
12
+
13
+ // #define DEBUG(x)
14
+ #define DEBUG (x ) \
15
+ std::cerr << std::this_thread::get_id() << " : " << x << std::endl;
16
+
17
+ namespace {
18
+
19
+ using namespace networkprotocoldsl ;
20
+ using namespace networkprotocoldsl ::operation;
21
+
22
+ enum class ProcessingMode {
23
+ Transition,
24
+ State,
25
+ };
26
+
27
+ using StatePair = std::pair<std::string, StateMachineOperation::StateInfo>;
28
+ using TransitionPair =
29
+ std::pair<std::string, StateMachineOperation::TransitionInfo>;
30
+
31
+ struct ProcessingInfo {
32
+ ProcessingMode processing_mode;
33
+ std::optional<StatePair> from_state;
34
+ std::optional<TransitionPair> transition;
35
+ StatePair to_state;
36
+ };
37
+
38
+ } // namespace
39
+
40
+ namespace networkprotocoldsl ::operation {
41
+
42
+ static std::optional<std::shared_ptr<std::vector<Value>>>
43
+ _extract_arguments (const std::vector<std::string> &names,
44
+ const value::Dictionary &d) {
45
+ DEBUG (" Entering _extract_arguments" );
46
+ auto args = std::make_shared<std::vector<Value>>();
47
+ for (const auto &arg_name : names) {
48
+ auto it = d.members ->find (arg_name);
49
+ if (it == d.members ->end ()) {
50
+ return std::nullopt;
51
+ } else {
52
+ args->push_back (it->second );
53
+ }
54
+ }
55
+ return args;
56
+ }
57
+
58
+ static OperationResult
59
+ _start_state_callback (ControlFlowOperationContext &ctx,
60
+ const StateMachineOperation::StateMap &states) {
61
+ DEBUG (" Entering _start_state_callback" );
62
+ ProcessingInfo &info = std::any_cast<ProcessingInfo &>(ctx.additional_info );
63
+ auto &s = info.to_state .second ;
64
+ ctx.callable = value::Callable{s.callback_optree , {" dictionary" }, true };
65
+ ctx.value = std::nullopt;
66
+ info.processing_mode = ProcessingMode::State;
67
+ return ReasonForBlockedOperation::WaitingForCallableInvocation;
68
+ }
69
+
70
+ static OperationResult
71
+ _start_transition_callback (ControlFlowOperationContext &ctx,
72
+ const StateMachineOperation::StateMap &states) {
73
+ DEBUG (" Entering _start_transition_callback" );
74
+ ProcessingInfo &info = std::any_cast<ProcessingInfo &>(ctx.additional_info );
75
+ assert (info.transition .has_value ());
76
+ auto &t = info.transition .value ().second ;
77
+ ctx.callable = value::Callable{t.callback_optree , t.argument_names , true };
78
+ ctx.value = std::nullopt;
79
+ info.processing_mode = ProcessingMode::Transition;
80
+ return ReasonForBlockedOperation::WaitingForCallableInvocation;
81
+ }
82
+
83
+ static OperationResult
84
+ _process_state_return_with_args (ControlFlowOperationContext &ctx,
85
+ const StateMachineOperation::StateMap &states,
86
+ const value::Octets t,
87
+ const value::Dictionary d) {
88
+ DEBUG (" Entering _process_state_return_with_args (Octets, Dictionary)" );
89
+ ProcessingInfo &info = std::any_cast<ProcessingInfo &>(ctx.additional_info );
90
+ if (info.to_state .first == " Closed" ) {
91
+ return d;
92
+ }
93
+ auto &s = info.to_state .second ;
94
+ info.from_state = info.to_state ;
95
+ auto it = s.transitions .find (*t.data );
96
+ if (it == s.transitions .end ()) {
97
+ return value::RuntimeError::NameError;
98
+ }
99
+ auto target_state_name = it->second .target_state ;
100
+ auto it2 = states.find (target_state_name);
101
+ if (it2 == states.end ()) {
102
+ return value::RuntimeError::NameError;
103
+ }
104
+ auto maybe_args = _extract_arguments (it->second .argument_names , d);
105
+ if (!maybe_args.has_value ()) {
106
+ return value::RuntimeError::TypeError;
107
+ }
108
+ ctx.accumulator = maybe_args.value ();
109
+ info.transition = *it;
110
+ info.to_state = *it2;
111
+ return _start_transition_callback (ctx, states);
112
+ }
113
+
114
+ static OperationResult
115
+ _process_state_return_with_args (ControlFlowOperationContext &ctx,
116
+ const StateMachineOperation::StateMap &states,
117
+ const auto &, const auto &) {
118
+ DEBUG (" Entering _process_state_return_with_args (auto, auto)" );
119
+ return value::RuntimeError::TypeError;
120
+ }
121
+
122
+ static OperationResult
123
+ _process_state_return_dynlist (ControlFlowOperationContext &ctx,
124
+ const StateMachineOperation::StateMap &states,
125
+ const value::DynamicList v) {
126
+ DEBUG (" Entering _process_state_return_dynlist (DynamicList)" );
127
+ if (v.values ->size () != 2 ) {
128
+ return value::RuntimeError::TypeError;
129
+ }
130
+ return std::visit (
131
+ [&](auto &t, auto &d) {
132
+ return _process_state_return_with_args (ctx, states, t, d);
133
+ },
134
+ v.values ->at (0 ), v.values ->at (1 ));
135
+ }
136
+
137
+ static OperationResult
138
+ _process_state_return_dynlist (ControlFlowOperationContext &ctx,
139
+ const StateMachineOperation::StateMap &states,
140
+ const value::RuntimeError err) {
141
+ DEBUG (" Entering _process_state_return_dynlist (RuntimeError)" );
142
+ return err;
143
+ }
144
+
145
+ static OperationResult
146
+ _process_state_return_dynlist (ControlFlowOperationContext &ctx,
147
+ const StateMachineOperation::StateMap &states,
148
+ const auto &) {
149
+ DEBUG (" Entering _process_state_return_dynlist (auto)" );
150
+ return value::RuntimeError::TypeError;
151
+ }
152
+
153
+ static OperationResult
154
+ _process_state_return (ControlFlowOperationContext &ctx,
155
+ const StateMachineOperation::StateMap &states) {
156
+ DEBUG (" Entering _process_state_return" );
157
+ assert (ctx.value .has_value ());
158
+ return std::visit (
159
+ [&](auto &v) { return _process_state_return_dynlist (ctx, states, v); },
160
+ ctx.value .value ());
161
+ }
162
+
163
+ static OperationResult _process_transition_return_with_args (
164
+ ControlFlowOperationContext &ctx,
165
+ const StateMachineOperation::StateMap &states, const value::Dictionary &d) {
166
+ DEBUG (" Entering _process_transition_return_with_args (Dictionary)" );
167
+ ctx.accumulator = std::make_shared<std::vector<Value>>(std::vector<Value>{d});
168
+ return _start_state_callback (ctx, states);
169
+ }
170
+
171
+ static OperationResult _process_transition_return_with_args (
172
+ ControlFlowOperationContext &ctx,
173
+ const StateMachineOperation::StateMap &states,
174
+ const value::RuntimeError &err) {
175
+ DEBUG (" Entering _process_transition_return_with_args (RuntimeError)" );
176
+ return err;
177
+ }
178
+
179
+ static OperationResult _process_transition_return_with_args (
180
+ ControlFlowOperationContext &ctx,
181
+ const StateMachineOperation::StateMap &states, const auto &) {
182
+ DEBUG (" Entering _process_transition_return_with_args (auto)" );
183
+ return value::RuntimeError::TypeError;
184
+ }
185
+
186
+ static OperationResult _process_transition_return_dynlist (
187
+ ControlFlowOperationContext &ctx,
188
+ const StateMachineOperation::StateMap &states,
189
+ const value::DynamicList &l) {
190
+ DEBUG (" Entering _process_transition_return_dynlist (DynamicList)" );
191
+ if (l.values ->size () != 1 ) {
192
+ return value::RuntimeError::TypeError;
193
+ }
194
+ return std::visit (
195
+ [&](auto &v) {
196
+ return _process_transition_return_with_args (ctx, states, v);
197
+ },
198
+ l.values ->at (0 ));
199
+ }
200
+
201
+ static OperationResult _process_transition_return_dynlist (
202
+ ControlFlowOperationContext &ctx,
203
+ const StateMachineOperation::StateMap &states,
204
+ const value::RuntimeError err) {
205
+ DEBUG (" Entering _process_transition_return_dynlist (RuntimeError)" );
206
+ return err;
207
+ }
208
+
209
+ static OperationResult _process_transition_return_dynlist (
210
+ ControlFlowOperationContext &ctx,
211
+ const StateMachineOperation::StateMap &states, const auto &) {
212
+ DEBUG (" Entering _process_transition_return_dynlist (auto)" );
213
+ return value::RuntimeError::TypeError;
214
+ }
215
+
216
+ static OperationResult
217
+ _process_transition_return (ControlFlowOperationContext &ctx,
218
+ const StateMachineOperation::StateMap &states) {
219
+ DEBUG (" Entering _process_transition_return" );
220
+ assert (ctx.value .has_value ());
221
+ return std::visit (
222
+ [&](auto &v) {
223
+ return _process_transition_return_dynlist (ctx, states, v);
224
+ },
225
+ ctx.value .value ());
226
+ }
227
+
228
+ OperationResult
229
+ StateMachineOperation::operator ()(ControlFlowOperationContext &ctx,
230
+ Arguments a) const {
231
+ DEBUG (" Entering StateMachineOperation::operator()" );
232
+ if (ctx.callable .has_value ()) {
233
+ if (ctx.callable_invoked ) {
234
+ if (ctx.value .has_value ()) {
235
+ ProcessingInfo &info =
236
+ std::any_cast<ProcessingInfo &>(ctx.additional_info );
237
+ if (info.processing_mode == ProcessingMode::Transition) {
238
+ if (!info.transition .has_value ()) {
239
+ return value::RuntimeError::NameError;
240
+ }
241
+ return _process_transition_return (ctx, states);
242
+ } else {
243
+ return _process_state_return (ctx, states);
244
+ }
245
+ } else {
246
+ return ReasonForBlockedOperation::WaitingForCallableResult;
247
+ }
248
+ } else {
249
+ return ReasonForBlockedOperation::WaitingForCallableInvocation;
250
+ }
251
+ } else {
252
+ auto it = states.find (" Open" );
253
+ if (it == states.end ()) {
254
+ return value::RuntimeError::NameError;
255
+ }
256
+ ctx.accumulator = std::make_shared<std::vector<Value>>(
257
+ std::vector<Value>{value::Dictionary ()});
258
+ ctx.additional_info = ProcessingInfo{ProcessingMode::Transition,
259
+ std::nullopt, std::nullopt, *it};
260
+ return _start_state_callback (ctx, states);
261
+ }
262
+ }
263
+
264
+ Value StateMachineOperation::get_callable (
265
+ ControlFlowOperationContext &ctx) const {
266
+ DEBUG (" Entering StateMachineOperation::get_callable" );
267
+ assert (ctx.callable .has_value ());
268
+ return ctx.callable .value ();
269
+ }
270
+
271
+ std::shared_ptr<const std::vector<Value>>
272
+ StateMachineOperation::get_argument_list (
273
+ ControlFlowOperationContext &ctx) const {
274
+ DEBUG (" Entering StateMachineOperation::get_argument_list" );
275
+ return ctx.accumulator ;
276
+ }
277
+
278
+ void StateMachineOperation::set_callable_invoked (
279
+ ControlFlowOperationContext &ctx) const {
280
+ DEBUG (" Entering StateMachineOperation::set_callable_invoked" );
281
+ ctx.callable_invoked = true ;
282
+ }
283
+
284
+ void StateMachineOperation::set_callable_return (
285
+ ControlFlowOperationContext &ctx, Value v) const {
286
+ DEBUG (" Entering StateMachineOperation::set_callable_return" );
287
+ ctx.value = v;
288
+ }
289
+
290
+ std::string StateMachineOperation::stringify () const {
291
+ DEBUG (" Entering StateMachineOperation::stringify" );
292
+ std::ostringstream os;
293
+ os << " StateMachineOperation{\n " ;
294
+ for (const auto &[state_name, state_info] : states) {
295
+ os << " State: " << state_name << " \n " ;
296
+ os << " Callback Optree:\n " ;
297
+ if (state_info.callback_optree ) {
298
+ print_optreenode (state_info.callback_optree ->root , os, " │ " ,
299
+ " │ " );
300
+ } else {
301
+ os << " <None>\n " ;
302
+ }
303
+ os << " Transitions:\n " ;
304
+ for (const auto &[transition_name, transition_info] :
305
+ state_info.transitions ) {
306
+ os << " Transition: " << transition_name << " -> "
307
+ << transition_info.target_state << " \n " ;
308
+ os << " Argument Names: [" ;
309
+ for (size_t i = 0 ; i < transition_info.argument_names .size (); ++i) {
310
+ os << " \" " << transition_info.argument_names [i] << " \" " ;
311
+ if (i < transition_info.argument_names .size () - 1 ) {
312
+ os << " , " ;
313
+ }
314
+ }
315
+ os << " ]\n " ;
316
+ os << " Callback Optree:\n " ;
317
+ if (transition_info.callback_optree ) {
318
+ print_optreenode (transition_info.callback_optree ->root , os,
319
+ " │ " , " │ " );
320
+ } else {
321
+ os << " <None>\n " ;
322
+ }
323
+ }
324
+ }
325
+ os << " }" ;
326
+ return os.str ();
327
+ }
328
+
329
+ } // namespace networkprotocoldsl::operation
0 commit comments