1#![allow(dead_code)]
2
3use std::fmt;
4
5use nom::{
6 branch::{alt, permutation},
7 bytes::complete::take_while,
8 character::{
9 complete::{anychar, char},
10 is_alphabetic, is_alphanumeric,
11 },
12 combinator::{map, opt, recognize, value, verify},
13 multi::many1,
14 sequence::{pair, preceded, separated_pair, terminated, tuple},
15 Parser,
16};
17use nom_supreme::{final_parser::final_parser, tag::complete::tag, ParserExt};
18
19use crate::{
20 parse::combinators::enclosed_list0,
21 pos::{pos, IndexPos},
22};
23
24use super::{
25 combinators::{attribute, block, list1, space, ws},
26 constants::*,
27 parts::quoted_string,
28 types::{Input, Result},
29 Error,
30};
31
32#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
33pub struct Identifier<'i>(pub(crate) &'i str);
34
35impl<'i> Identifier<'i> {
36 pub(crate) fn parse(i: Input<'i>) -> Result<Self> {
37 let wchar = take_while(|x: char| x == '_' || is_alphanumeric(x as u8));
38 map(
39 recognize(pair(
40 verify(anychar, |&c| c == '_' || is_alphabetic(c as u8)),
41 wchar,
42 )),
43 Self,
44 )(i)
45 }
46}
47
48impl fmt::Display for Identifier<'_> {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 self.0.fmt(f)
51 }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub(crate) enum NodeShape {
56 Rectangle,
57 Square,
58 Ellipse,
59 Circle,
60 Diamond,
61 AngledSquare,
62}
63
64impl NodeShape {
65 pub(crate) fn parse(i: Input) -> Result<Self> {
66 alt((
67 value(Self::Rectangle, tag("rect")),
68 value(Self::Square, tag("square")),
69 value(Self::Ellipse, tag("ellipse")),
70 value(Self::Circle, tag("circle")),
71 value(Self::Diamond, tag("diamond")),
72 value(Self::AngledSquare, tag("angled_square")),
73 ))(i)
74 }
75}
76
77#[derive(Debug, PartialEq, Eq, Clone, Copy)]
78pub enum Direction {
79 North,
80 South,
81 West,
82 East,
83}
84
85impl Direction {
86 pub(crate) fn parse(i: Input) -> Result<Self> {
87 alt((
88 value(Self::North, tag("n")),
89 value(Self::South, tag("s")),
90 value(Self::West, tag("w")),
91 value(Self::East, tag("e")),
92 ))(i)
93 }
94}
95
96impl fmt::Display for Direction {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 let s = match self {
99 Direction::North => "North",
100 Direction::South => "South",
101 Direction::West => "West",
102 Direction::East => "East",
103 };
104
105 f.write_str(s)
106 }
107}
108
109#[derive(Debug, PartialEq, Eq, Clone, Copy)]
110pub(crate) enum Destination<'i> {
111 Itself,
112 Relative(Direction),
113 Label(Identifier<'i>),
114}
115
116impl<'i> Destination<'i> {
117 pub(crate) fn parse(i: Input<'i>) -> Result<Self> {
118 alt((
119 preceded(
120 char(RELATIVE_SIGIL),
121 map(opt(Direction::parse), |dir| match dir {
122 Some(dir) => Self::Relative(dir),
123 None => Self::Itself,
124 }),
125 ),
126 map(preceded(char(LABEL_SIGIL), Identifier::parse), Self::Label),
127 ))(i)
128 }
129}
130
131#[derive(Debug, PartialEq, Eq, Clone)]
132pub(crate) enum NodeAttribute<'i> {
133 Text(String),
134 Class(String),
135 Shape(NodeShape),
136 Connect(Vec<ConnectionDescriptor<'i>>),
137}
138
139impl<'i> NodeAttribute<'i> {
140 fn parse(i: Input<'i>) -> Result<Self> {
141 let connection_descriptors = alt((
142 map(ConnectionDescriptor::parse, |x| vec![x]),
143 enclosed_list0(BLOCK_DELIMITERS, ConnectionDescriptor::parse, TERMINATOR),
144 ));
145
146 alt((
147 map(attribute("text", quoted_string), Self::Text),
148 map(attribute("class", quoted_string), Self::Class),
149 map(attribute("shape", NodeShape::parse), Self::Shape),
150 map(attribute("connect", connection_descriptors), Self::Connect),
151 ))(i)
152 }
153
154 fn parse_vec(i: Input<'i>) -> Result<Vec<Self>> {
155 alt((
156 map(quoted_string.terminated(opt(char(LIST_SEPARATOR))), |x| {
157 vec![Self::Text(x)]
158 })
159 .terminated(char(LIST_DELIMITERS.1)),
160 map(
161 pair(
162 quoted_string.terminated(ws(char(LIST_SEPARATOR))),
163 list1(Self::parse, LIST_SEPARATOR, LIST_DELIMITERS.1),
164 ),
165 |(text_shorthand, mut tail)| {
166 tail.insert(0, Self::Text(text_shorthand));
167 tail
168 },
169 ),
170 list1(Self::parse, LIST_SEPARATOR, LIST_DELIMITERS.1),
171 ))
172 .preceded_by(char(LIST_DELIMITERS.0))
173 .parse(i)
174 }
175
176 pub(crate) fn as_key(&self) -> &'static str {
177 match self {
178 NodeAttribute::Text(_) => "text",
179 NodeAttribute::Class(_) => "class",
180 NodeAttribute::Shape(_) => "shape",
181 NodeAttribute::Connect(_) => "connect",
182 }
183 }
184}
185
186#[derive(Debug, PartialEq, Eq, Clone)]
187pub(crate) struct ConnectionDescriptor<'i> {
188 pub(crate) to: Destination<'i>,
189 pub(crate) sides: (Direction, Direction),
190 pub(crate) attrs: Vec<ConnectionAttribute>,
191}
192
193impl<'i> ConnectionDescriptor<'i> {
194 pub(crate) fn parse(i: Input<'i>) -> Result<Self> {
195 let sides = separated_pair(Direction::parse, char(SIDES_SIGIL), Direction::parse);
196
197 map(
198 tuple((
199 sides,
200 Destination::parse,
201 opt(ConnectionAttribute::parse_vec),
202 )),
203 |(sides, to, attrs)| Self {
204 to,
205 sides,
206 attrs: attrs.unwrap_or_default(),
207 },
208 )(i)
209 }
210}
211
212#[derive(Debug, PartialEq, Eq, Clone, Copy)]
213pub(crate) enum ArrowheadType {
214 None,
215 Start,
216 End,
217 Both,
218}
219
220impl Default for ArrowheadType {
221 fn default() -> Self {
222 Self::End
223 }
224}
225
226#[derive(Debug, PartialEq, Eq, Clone)]
227pub(crate) enum ConnectionAttribute {
228 Text(String),
229 Class(String),
230 Arrowheads(ArrowheadType),
231}
232
233impl ConnectionAttribute {
234 pub(crate) fn parse(i: Input) -> Result<Self> {
235 let arrowheads = alt((
236 value(ArrowheadType::None, tag("none")),
237 value(ArrowheadType::Start, tag("start")),
238 value(ArrowheadType::End, tag("end")),
239 value(ArrowheadType::Both, tag("both")),
240 ));
241
242 alt((
243 map(attribute("text", quoted_string), Self::Text),
244 map(attribute("class", quoted_string), Self::Class),
245 map(attribute("arrowheads", arrowheads), Self::Arrowheads),
246 ))(i)
247 }
248
249 pub(crate) fn parse_vec(i: Input) -> Result<Vec<Self>> {
250 alt((
251 map(quoted_string, |x| vec![Self::Text(x)]).terminated(char(LIST_DELIMITERS.1)),
252 map(
253 pair(
254 quoted_string.terminated(ws(char(LIST_SEPARATOR))),
255 list1(Self::parse, LIST_SEPARATOR, LIST_DELIMITERS.1),
256 ),
257 |(text_shorthand, mut tail)| {
258 tail.insert(0, Self::Text(text_shorthand));
259 tail
260 },
261 ),
262 list1(Self::parse, LIST_SEPARATOR, LIST_DELIMITERS.1),
263 ))
264 .preceded_by(char(LIST_DELIMITERS.0))
265 .parse(i)
266 }
267
268 pub(crate) fn as_key(&self) -> &'static str {
269 match self {
270 Self::Text(_) => "text",
271 Self::Class(_) => "class",
272 Self::Arrowheads(_) => "arrowheads",
273 }
274 }
275}
276
277#[derive(Debug, PartialEq, Eq)]
278pub(crate) struct Node<'i> {
279 pub(crate) id: Identifier<'i>,
280 pub(crate) label: Option<Identifier<'i>>,
281 pub(crate) attrs: Vec<NodeAttribute<'i>>,
282}
283
284impl<'i> Node<'i> {
285 pub(crate) fn parse(i: Input<'i>) -> Result<Self> {
286 map(
287 tuple((
288 Identifier::parse,
289 opt(preceded(char(LABEL_SIGIL), Identifier::parse)),
290 opt(NodeAttribute::parse_vec),
291 )),
292 |(id, label, attrs)| Self {
293 id,
294 label,
295 attrs: attrs.unwrap_or_default(),
296 },
297 )(i)
298 }
299}
300
301#[derive(Debug, PartialEq, Eq)]
302pub(crate) struct Grid<'i>(Vec<Vec<Option<Node<'i>>>>);
303
304impl<'i> Grid<'i> {
305 pub(crate) fn parse(i: Input<'i>) -> Result<Self> {
306 let empty = tag(EMPTY);
307 let opt_node = alt((map(empty, |_| None), map(Node::parse, Some)));
308 let row = list1(opt_node, LIST_SEPARATOR, TERMINATOR);
309 let grid = map(many1(ws(row)), Self);
310
311 preceded(terminated(tag("grid"), space), block(grid))(i)
312 }
313
314 pub(crate) fn nodes(&self) -> impl Iterator<Item = (IndexPos, &Node<'i>)> {
315 self.0.iter().enumerate().flat_map(|(y, row)| {
316 row.iter()
317 .enumerate()
318 .filter_map(move |(x, node)| node.as_ref().map(|node| (pos(x, y).into(), node)))
319 })
320 }
321
322 pub(crate) fn size(&self) -> IndexPos {
323 let height = self.0.len();
324 let width = self.0.iter().map(|v| v.len()).max().unwrap_or_default();
325
326 pos(width, height).into()
327 }
328}
329
330pub(crate) type Definitions<'i> = Vec<(Identifier<'i>, Vec<NodeAttribute<'i>>)>;
331
332pub(crate) fn parse_definitions(i: Input) -> Result<Definitions> {
333 let definition = pair(Identifier::parse, NodeAttribute::parse_vec).terminated(char(TERMINATOR));
334 let definitions = many1(ws(definition));
335
336 preceded(terminated(tag("define"), space), block(definitions))(i)
337}
338
339#[derive(Debug, PartialEq, Eq)]
340pub(crate) struct Document<'i> {
341 pub(crate) grid: Grid<'i>,
342 pub(crate) definitions: Definitions<'i>,
343}
344
345impl<'i> Document<'i> {
346 pub(crate) fn parse(i: Input<'i>) -> std::result::Result<Self, Error<'i>> {
347 let document = map(
348 permutation((ws(Grid::parse), opt(ws(parse_definitions)))),
349 |(grid, definitions)| Self {
350 grid,
351 definitions: definitions.unwrap_or_default(),
352 },
353 );
354
355 final_parser(document)(i)
356 }
357}
358
359#[cfg(test)]
360mod tests {
361 use nom::combinator::all_consuming;
362
363 use super::*;
364 use crate::test::{assert_not_parsed, assert_parsed_eq};
365
366 #[test]
367 fn valid_identifier() {
368 assert_parsed_eq(Identifier::parse, "foo", Identifier("foo"));
369 assert_parsed_eq(Identifier::parse, "bar21foo", Identifier("bar21foo"));
370 assert_parsed_eq(Identifier::parse, "_example", Identifier("_example"));
371 assert_parsed_eq(Identifier::parse, "text_14", Identifier("text_14"));
372 }
373
374 #[test]
375 fn invalid_identifier() {
376 assert_not_parsed(Identifier::parse, "");
377 assert_not_parsed(Identifier::parse, "12number_first");
378 }
379
380 #[test]
381 fn valid_node_shape() {
382 assert_parsed_eq(NodeShape::parse, "rect", NodeShape::Rectangle);
383 assert_parsed_eq(NodeShape::parse, "square", NodeShape::Square);
384 assert_parsed_eq(NodeShape::parse, "ellipse", NodeShape::Ellipse);
385 assert_parsed_eq(NodeShape::parse, "circle", NodeShape::Circle);
386 assert_parsed_eq(NodeShape::parse, "diamond", NodeShape::Diamond);
387 assert_parsed_eq(NodeShape::parse, "angled_square", NodeShape::AngledSquare);
388 }
389
390 #[test]
391 fn valid_direction() {
392 assert_parsed_eq(Direction::parse, "n", Direction::North);
393 assert_parsed_eq(Direction::parse, "s", Direction::South);
394 assert_parsed_eq(Direction::parse, "w", Direction::West);
395 assert_parsed_eq(Direction::parse, "e", Direction::East);
396 }
397
398 #[test]
399 fn valid_destination() {
400 const NORTH: Destination = Destination::Relative(Direction::North);
401 const SOUTH: Destination = Destination::Relative(Direction::South);
402 const WEST: Destination = Destination::Relative(Direction::West);
403 const EAST: Destination = Destination::Relative(Direction::East);
404
405 assert_parsed_eq(Destination::parse, "@n", NORTH);
406 assert_parsed_eq(Destination::parse, "@s", SOUTH);
407 assert_parsed_eq(Destination::parse, "@w", WEST);
408 assert_parsed_eq(Destination::parse, "@e", EAST);
409
410 assert_parsed_eq(
411 Destination::parse,
412 "#foo",
413 Destination::Label(Identifier("foo")),
414 );
415
416 assert_parsed_eq(Destination::parse, "@", Destination::Itself);
417 }
418
419 #[test]
420 fn valid_node_attribute() {
421 assert_parsed_eq(
422 NodeAttribute::parse,
423 r#"text: "foo""#,
424 NodeAttribute::Text(String::from("foo")),
425 );
426
427 assert_parsed_eq(
428 NodeAttribute::parse,
429 r#"class: "class name here""#,
430 NodeAttribute::Class(String::from("class name here")),
431 );
432
433 assert_parsed_eq(
434 NodeAttribute::parse,
435 r#"shape: diamond"#,
436 NodeAttribute::Shape(NodeShape::Diamond),
437 );
438 }
439
440 #[test]
441 fn valid_connection_attribute() {
442 assert_parsed_eq(
443 ConnectionAttribute::parse,
444 r#"text: "foo""#,
445 ConnectionAttribute::Text(String::from("foo")),
446 );
447
448 assert_parsed_eq(
449 ConnectionAttribute::parse,
450 r#"class: "class name here""#,
451 ConnectionAttribute::Class(String::from("class name here")),
452 );
453
454 assert_parsed_eq(
455 ConnectionAttribute::parse,
456 "arrowheads: none",
457 ConnectionAttribute::Arrowheads(ArrowheadType::None),
458 );
459 }
460
461 #[test]
462 fn valid_connection_descriptor() {
463 assert_parsed_eq(
464 ConnectionDescriptor::parse,
465 r#"n:s@s("foo", class: "bar")"#,
466 ConnectionDescriptor {
467 to: Destination::Relative(Direction::South),
468 sides: (Direction::North, Direction::South),
469 attrs: vec![
470 ConnectionAttribute::Text(String::from("foo")),
471 ConnectionAttribute::Class(String::from("bar")),
472 ],
473 },
474 );
475
476 assert_parsed_eq(
477 ConnectionDescriptor::parse,
478 "w:e@s",
479 ConnectionDescriptor {
480 to: Destination::Relative(Direction::South),
481 sides: (Direction::West, Direction::East),
482 attrs: vec![],
483 },
484 );
485
486 assert_parsed_eq(
487 ConnectionDescriptor::parse,
488 "n:e@s",
489 ConnectionDescriptor {
490 to: Destination::Relative(Direction::South),
491 sides: (Direction::North, Direction::East),
492 attrs: vec![],
493 },
494 );
495 }
496
497 #[test]
498 fn valid_node_connect_attribute() {
499 assert_parsed_eq(
500 NodeAttribute::parse,
501 "connect: n:e@n",
502 NodeAttribute::Connect(vec![ConnectionDescriptor {
503 to: Destination::Relative(Direction::North),
504 sides: (Direction::North, Direction::East),
505 attrs: vec![],
506 }]),
507 );
508
509 assert_parsed_eq(
510 NodeAttribute::parse,
511 "connect: {n:n@e; n:n#foo}",
512 NodeAttribute::Connect(vec![
513 ConnectionDescriptor {
514 to: Destination::Relative(Direction::East),
515 sides: (Direction::North, Direction::North),
516 attrs: vec![],
517 },
518 ConnectionDescriptor {
519 to: Destination::Label(Identifier("foo")),
520 sides: (Direction::North, Direction::North),
521 attrs: vec![],
522 },
523 ]),
524 )
525 }
526
527 #[test]
528 fn valid_node() {
529 assert_parsed_eq(
530 Node::parse,
531 "foo",
532 Node {
533 id: Identifier("foo"),
534 label: None,
535 attrs: vec![],
536 },
537 );
538
539 assert_parsed_eq(
540 Node::parse,
541 "foo#bar(shape: rect)",
542 Node {
543 id: Identifier("foo"),
544 label: Some(Identifier("bar")),
545 attrs: vec![NodeAttribute::Shape(NodeShape::Rectangle)],
546 },
547 );
548
549 assert_parsed_eq(
550 Node::parse,
551 r#"foo("hello",)"#,
552 Node {
553 id: Identifier("foo"),
554 label: None,
555 attrs: vec![NodeAttribute::Text(String::from("hello"))],
556 },
557 );
558
559 assert_parsed_eq(
560 Node::parse,
561 r#"foo("hey", shape: diamond,)"#,
562 Node {
563 id: Identifier("foo"),
564 label: None,
565 attrs: vec![
566 NodeAttribute::Text(String::from("hey")),
567 NodeAttribute::Shape(NodeShape::Diamond),
568 ],
569 },
570 );
571
572 assert_parsed_eq(
573 Node::parse,
574 "foo#bar(shape: rect)",
575 Node {
576 id: Identifier("foo"),
577 label: Some(Identifier("bar")),
578 attrs: vec![NodeAttribute::Shape(NodeShape::Rectangle)],
579 },
580 );
581 }
582
583 #[test]
584 fn invalid_node() {
585 assert_not_parsed(Node::parse, "");
586 assert_not_parsed(Node::parse, "(shape: rect)");
587 assert_not_parsed(Node::parse, "#bar");
588 assert_not_parsed(Node::parse, "#bar(shape: rect)");
589 assert_not_parsed(all_consuming(Node::parse), "foo()");
591 }
592
593 #[test]
594 fn valid_grid() {
595 let input = r#"
596 grid {
597 foo#main, bar;
598 baz, _;
599 _;
600 }
601 "#
602 .trim();
603
604 let foo_node = Node {
605 id: Identifier("foo"),
606 label: Some(Identifier("main")),
607 attrs: vec![],
608 };
609 let bar_node = Node {
610 id: Identifier("bar"),
611 label: None,
612 attrs: vec![],
613 };
614 let baz_node = Node {
615 id: Identifier("baz"),
616 label: None,
617 attrs: vec![],
618 };
619
620 assert_parsed_eq(
621 Grid::parse,
622 input,
623 Grid(vec![
624 vec![Some(foo_node), Some(bar_node)],
625 vec![Some(baz_node), None],
626 vec![None],
627 ]),
628 );
629 }
630
631 #[test]
632 fn invalid_grid() {
633 assert_not_parsed(Grid::parse, "grid {}");
634 assert_not_parsed(Grid::parse, "grid { missing_terminator }");
635 assert_not_parsed(Grid::parse, "grid { missing separator; }");
636 assert_not_parsed(Grid::parse, "grid { foo; ; }");
637 }
638
639 #[test]
640 fn valid_definitions() {
641 let input = r#"
642 define {
643 foo(shape: rect);
644 bar(text: "hello");
645 }
646 "#
647 .trim();
648
649 assert_parsed_eq(
650 parse_definitions,
651 input,
652 vec![
653 (
654 Identifier("foo"),
655 vec![NodeAttribute::Shape(NodeShape::Rectangle)],
656 ),
657 (
658 Identifier("bar"),
659 vec![NodeAttribute::Text(String::from("hello"))],
660 ),
661 ],
662 )
663 }
664
665 #[test]
666 fn invalid_definitions() {
667 assert_not_parsed(parse_definitions, "define {}");
668 assert_not_parsed(parse_definitions, "define { no_attrs; }");
669 assert_not_parsed(parse_definitions, "define { no_terminator(shape: rect) }");
670 assert_not_parsed(parse_definitions, "define { ; }");
671 }
672}