merman-core 0.9.0

Mermaid parser + semantic model (headless; parity-focused).
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
// Sequence diagram minimal grammar (phase 1).

grammar(arena: &mut ActionArena, control: &crate::OperationControl);

use crate::diagrams::sequence::ast::{ActionArena, ActionList};

use crate::diagrams::sequence::{
  Action, Tok, LINETYPE_ALT_ELSE, LINETYPE_ALT_END, LINETYPE_ALT_START, LINETYPE_BREAK_END,
  LINETYPE_BREAK_START, LINETYPE_CRITICAL_END, LINETYPE_CRITICAL_OPTION, LINETYPE_CRITICAL_START,
  LINETYPE_CENTRAL_CONNECTION, LINETYPE_CENTRAL_CONNECTION_DUAL,
  LINETYPE_CENTRAL_CONNECTION_REVERSE, LINETYPE_LOOP_END, LINETYPE_LOOP_START, LINETYPE_OPT_END,
  LINETYPE_OPT_START, LINETYPE_PAR_AND, LINETYPE_PAR_END, LINETYPE_PAR_OVER_START,
  LINETYPE_PAR_START, LINETYPE_RECT_END, LINETYPE_RECT_START
};

extern {
  type Location = usize;
  type Error = crate::diagrams::sequence::LexError;

  enum Tok {
    Newline => Tok::Newline,

    "sequenceDiagram" => Tok::SequenceDiagram,
    "participant" => Tok::Participant,
    "actor" => Tok::ActorKw,
    "create" => Tok::Create,
    "destroy" => Tok::Destroy,
    "as" => Tok::As,

    "box" => Tok::Box,
    "end" => Tok::End,

    "loop" => Tok::Loop,
    "rect" => Tok::Rect,
    "opt" => Tok::Opt,
    "alt" => Tok::Alt,
    "else" => Tok::Else,
    "par" => Tok::Par,
    "par_over" => Tok::ParOver,
    "and" => Tok::And,
    "critical" => Tok::Critical,
    "option" => Tok::Option,
    "break" => Tok::Break,

    "note" => Tok::Note,
    "left_of" => Tok::LeftOf,
    "right_of" => Tok::RightOf,
    "over" => Tok::Over,

    "links" => Tok::Links,
    "link" => Tok::Link,
    "properties" => Tok::Properties,
    "details" => Tok::Details,

    "autonumber" => Tok::Autonumber,
    "off" => Tok::Off,

    "activate" => Tok::Activate,
    "deactivate" => Tok::Deactivate,

    Comma => Tok::Comma,
    Plus => Tok::Plus,
    Minus => Tok::Minus,
    Central => Tok::Central,

    Num => Tok::Num(<f64>),
    Actor => Tok::Actor(<String>),
    Text => Tok::Text(<String>),
    RestOfLine => Tok::RestOfLine(<String>),
    SignalType => Tok::SignalType(<i32>),
    Config => Tok::Config(<String>),

    Title => Tok::Title(<String>),
    CompatTitle => Tok::CompatTitle(<String>),
    AccTitle => Tok::AccTitle(<String>),
    AccDescr => Tok::AccDescr(<String>),
    AccDescrMultiline => Tok::AccDescrMultiline(<String>),
  }
}

pub Actions: ActionList = {
  <_n:Newlines> "sequenceDiagram" <_n2:Newlines> <a:Statements> => a
};

Statements: ActionList = {
  => ActionList::default(),
  <s:Statement> <rest:StatementRest> =>? arena.concat(s, rest, control),
};

StatementRest: ActionList = {
  <_n:Newlines1> <s:Statement> <rest:StatementRest> =>? arena.concat(s, rest, control),
  Newlines => ActionList::default(),
};

Newlines: () = {
  => (),
  Newline Newlines => (),
};

Newlines1: () = {
  Newline Newlines => (),
};

Statement: ActionList = {
  <p:ParticipantStatement> =>? arena.push_actions(p, control),
  <c:CreateStatement> =>? arena.push_actions(c, control),
  <d:DestroyStatement> =>? arena.push_actions(d, control),
  <b:BlockStatement> => b,
  <s:SignalStatement> =>? arena.push_actions(s, control),
  <n:NoteStatement> =>? arena.push_actions(n, control),
  <b:BoxStatement> => b,
  <l:LinksStatement> =>? arena.push_actions(l, control),
  <l:LinkStatement> =>? arena.push_actions(l, control),
  <p:PropertiesStatement> =>? arena.push_actions(p, control),
  <d:DetailsStatement> =>? arena.push_actions(d, control),
  <t:TitleStatement> =>? arena.push_actions(vec![Action::SetTitle(t)], control),
  <a:AccTitleStatement> =>? arena.push_actions(vec![Action::SetAccTitle(a)], control),
  <d:AccDescrStatement> =>? arena.push_actions(vec![Action::SetAccDescr(d)], control),
  <au:AutonumberStatement> =>? arena.push_actions(vec![au], control),
  <ac:ActivateStatement> =>? arena.push_actions(vec![ac], control),
  <de:DeactivateStatement> =>? arena.push_actions(vec![de], control),
};

Doc: ActionList = {
  => ActionList::default(),
  Newline <rest:Doc> => rest,
  <s:Statement> Newline <rest:Doc> =>? arena.concat(s, rest, control),
};

TitleStatement: String = {
  <t:Title> => t,
  <t:CompatTitle> => t,
};

AccTitleStatement: String = {
  <t:AccTitle> => t,
};

AccDescrStatement: String = {
  <t:AccDescr> => t,
  <t:AccDescrMultiline> => t,
};

ActorId: String = {
  <a:Actor> => a,
  <n:Num> => n.to_string(),
};

ParticipantDecl: (String, Option<String>, String, Option<String>) = {
  "participant" <id:ActorId> "as" <desc:RestOfLine> => (id, Some(desc), "participant".to_string(), None),
  "participant" <id:ActorId> <cfg:Config> "as" <desc:RestOfLine> => (id, Some(desc), "participant".to_string(), Some(cfg)),
  "participant" <id:ActorId> <cfg:Config> => (id, None, "participant".to_string(), Some(cfg)),
  "participant" <id:ActorId> => (id, None, "participant".to_string(), None),
  "actor" <id:ActorId> "as" <desc:RestOfLine> => (id, Some(desc), "actor".to_string(), None),
  "actor" <id:ActorId> <cfg:Config> "as" <desc:RestOfLine> => (id, Some(desc), "actor".to_string(), Some(cfg)),
  "actor" <id:ActorId> <cfg:Config> => (id, None, "actor".to_string(), Some(cfg)),
  "actor" <id:ActorId> => (id, None, "actor".to_string(), None),
};

ParticipantStatement: Vec<Action> = {
  <d:ParticipantDecl> => vec![
    Action::AddParticipant { id: d.0, description: d.1, draw: d.2, config: d.3 },
  ],
};

CreateStatement: Vec<Action> = {
  "create" <d:ParticipantDecl> => vec![
    Action::CreateParticipant { id: d.0, description: d.1, draw: d.2, config: d.3 },
  ],
};

DestroyStatement: Vec<Action> = {
  "destroy" <a:ActorId> => vec![Action::DestroyParticipant { id: a }],
};

BlockStatement: ActionList = {
  <l:LoopBlock> => l,
  <o:OptBlock> => o,
  <a:AltBlock> => a,
  <p:ParBlock> => p,
  <p:ParOverBlock> => p,
  <c:CriticalBlock> => c,
  <b:BreakBlock> => b,
  <r:RectBlock> => r,
};

LoopBlock: ActionList = {
  "loop" <h:RestOfLine> <body:Doc> "end" =>? arena.wrap(
    Action::ControlSignal { signal_type: LINETYPE_LOOP_START, text: Some(h) },
    body,
    Action::ControlSignal { signal_type: LINETYPE_LOOP_END, text: None },
    control,
  ),
};

OptBlock: ActionList = {
  "opt" <h:RestOfLine> <body:Doc> "end" =>? arena.wrap(
    Action::ControlSignal { signal_type: LINETYPE_OPT_START, text: Some(h) },
    body,
    Action::ControlSignal { signal_type: LINETYPE_OPT_END, text: None },
    control,
  ),
};

RectBlock: ActionList = {
  "rect" <h:RestOfLine> <body:Doc> "end" =>? arena.wrap(
    Action::ControlSignal { signal_type: LINETYPE_RECT_START, text: Some(h) },
    body,
    Action::ControlSignal { signal_type: LINETYPE_RECT_END, text: None },
    control,
  ),
};

AltBlock: ActionList = {
  "alt" <h:RestOfLine> <body:Doc> <else_branches:AltElseBranch*> "end" =>? arena.branch_block(
    Action::ControlSignal { signal_type: LINETYPE_ALT_START, text: Some(h) },
    body, else_branches, LINETYPE_ALT_ELSE,
    Action::ControlSignal { signal_type: LINETYPE_ALT_END, text: None },
    control,
  ),
};

AltElseBranch: (String, ActionList) = {
  "else" <h:RestOfLine> <body:Doc> => (h, body),
};

ParBlock: ActionList = {
  "par" <h:RestOfLine> <body:Doc> <branches:ParAndBranch*> "end" =>? arena.branch_block(
    Action::ControlSignal { signal_type: LINETYPE_PAR_START, text: Some(h) },
    body, branches, LINETYPE_PAR_AND,
    Action::ControlSignal { signal_type: LINETYPE_PAR_END, text: None },
    control,
  ),
};

ParOverBlock: ActionList = {
  "par_over" <h:RestOfLine> <body:Doc> "end" =>? arena.wrap(
    Action::ControlSignal { signal_type: LINETYPE_PAR_OVER_START, text: Some(h) },
    body,
    Action::ControlSignal { signal_type: LINETYPE_PAR_END, text: None },
    control,
  ),
};

ParAndBranch: (String, ActionList) = {
  "and" <h:RestOfLine> <body:Doc> => (h, body),
};

CriticalBlock: ActionList = {
  "critical" <h:RestOfLine> <body:Doc> <branches:CriticalOptionBranch*> "end" =>? arena.branch_block(
    Action::ControlSignal { signal_type: LINETYPE_CRITICAL_START, text: Some(h) },
    body, branches, LINETYPE_CRITICAL_OPTION,
    Action::ControlSignal { signal_type: LINETYPE_CRITICAL_END, text: None },
    control,
  ),
};

CriticalOptionBranch: (String, ActionList) = {
  "option" <h:RestOfLine> <body:Doc> => (h, body),
};

BreakBlock: ActionList = {
  "break" <h:RestOfLine> <body:Doc> "end" =>? arena.wrap(
    Action::ControlSignal { signal_type: LINETYPE_BREAK_START, text: Some(h) },
    body,
    Action::ControlSignal { signal_type: LINETYPE_BREAK_END, text: None },
    control,
  ),
};

BoxStatement: ActionList = {
  "box" <h:RestOfLine> <_n:Newlines1> <inner:BoxBody> "end" =>? arena.wrap(
    Action::BoxStart { header: h }, inner, Action::BoxEnd, control,
  ),
};

BoxBody: ActionList = {
  => ActionList::default(),
  <p:ParticipantStatement> <_n:Newlines1> <rest:BoxBody> =>? {
    let participant = arena.push_actions(p, control)?;
    arena.concat(participant, rest, control)
  },
};

LinksStatement: Vec<Action> = {
  "links" <a:ActorId> <t:Text> => vec![
    Action::EnsureParticipant { id: a.clone() },
    Action::AddLinks { actor: a, text: t },
  ],
};

LinkStatement: Vec<Action> = {
  "link" <a:ActorId> <t:Text> => vec![
    Action::EnsureParticipant { id: a.clone() },
    Action::AddLink { actor: a, text: t },
  ],
};

PropertiesStatement: Vec<Action> = {
  "properties" <a:ActorId> <t:Text> => vec![
    Action::EnsureParticipant { id: a.clone() },
    Action::AddProperties { actor: a, text: t },
  ],
};

DetailsStatement: Vec<Action> = {
  "details" <a:ActorId> <t:Text> => vec![
    Action::EnsureParticipant { id: a.clone() },
    Action::AddDetails { actor: a, text: t },
  ],
};

SignalStatement: Vec<Action> = {
  <from:ActorId> <ty:SignalType> Plus <to:ActorId> <text:Text> => vec![
    Action::EnsureParticipant { id: from.clone() },
    Action::EnsureParticipant { id: to.clone() },
    Action::AddMessage { from: from.clone(), to: to.clone(), signal_type: ty, text, activate: true, central_connection: 0 },
    Action::ActiveStart { actor: to },
  ],
  <from:ActorId> <ty:SignalType> Minus <to:ActorId> <text:Text> => vec![
    Action::EnsureParticipant { id: from.clone() },
    Action::EnsureParticipant { id: to.clone() },
    Action::AddMessage { from: from.clone(), to: to.clone(), signal_type: ty, text, activate: false, central_connection: 0 },
    Action::ActiveEnd { actor: from },
  ],
  <from:ActorId> <ty:SignalType> Central <to:ActorId> <text:Text> => vec![
    Action::EnsureParticipant { id: from.clone() },
    Action::EnsureParticipant { id: to.clone() },
    Action::AddMessage {
      from: from.clone(),
      to: to.clone(),
      signal_type: ty,
      text,
      activate: true,
      central_connection: LINETYPE_CENTRAL_CONNECTION,
    },
    Action::CentralConnection { actor: to },
  ],
  <from:ActorId> Central <ty:SignalType> <to:ActorId> <text:Text> => vec![
    Action::EnsureParticipant { id: from.clone() },
    Action::EnsureParticipant { id: to.clone() },
    Action::AddMessage {
      from: from.clone(),
      to: to.clone(),
      signal_type: ty,
      text,
      activate: false,
      central_connection: LINETYPE_CENTRAL_CONNECTION_REVERSE,
    },
    Action::CentralConnectionReverse { actor: from },
  ],
  <from:ActorId> Central <ty:SignalType> Central <to:ActorId> <text:Text> => vec![
    Action::EnsureParticipant { id: from.clone() },
    Action::EnsureParticipant { id: to.clone() },
    Action::AddMessage {
      from: from.clone(),
      to: to.clone(),
      signal_type: ty,
      text,
      activate: true,
      central_connection: LINETYPE_CENTRAL_CONNECTION_DUAL,
    },
    Action::CentralConnection { actor: to },
    Action::CentralConnectionReverse { actor: from },
  ],
  <from:ActorId> <ty:SignalType> <to:ActorId> <text:Text> => vec![
    Action::EnsureParticipant { id: from.clone() },
    Action::EnsureParticipant { id: to.clone() },
    Action::AddMessage { from, to, signal_type: ty, text, activate: false, central_connection: 0 },
  ],
};

NoteStatement: Vec<Action> = {
  "note" <p:Placement> <a:ActorId> <t:Text> => vec![
    Action::EnsureParticipant { id: a.clone() },
    Action::AddNote { actors: vec![a], placement: p, text: t },
  ],
  "note" "over" <a:ActorId> Comma <b:ActorId> <t:Text> => vec![
    Action::EnsureParticipant { id: a.clone() },
    Action::EnsureParticipant { id: b.clone() },
    Action::AddNote { actors: vec![a, b], placement: 2, text: t },
  ],
  "note" "over" <a:ActorId> <t:Text> => vec![
    Action::EnsureParticipant { id: a.clone() },
    Action::AddNote { actors: vec![a.clone(), a], placement: 2, text: t },
  ],
};

Placement: i32 = {
  "left_of" => 0,
  "right_of" => 1,
};

AutonumberStatement: Action = {
  "autonumber" <a:Num> <b:Num> => Action::Autonumber { start: Some(a), step: Some(b), visible: true },
  "autonumber" <a:Num> => Action::Autonumber { start: Some(a), step: Some(1.0), visible: true },
  "autonumber" "off" => Action::Autonumber { start: None, step: None, visible: false },
  "autonumber" => Action::Autonumber { start: None, step: None, visible: true },
};

ActivateStatement: Action = {
  "activate" <a:ActorId> => Action::ActiveStart { actor: a },
};

DeactivateStatement: Action = {
  "deactivate" <a:ActorId> => Action::ActiveEnd { actor: a },
};