flou/parse/
ast.rs

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        // Without all_consuming the parser just stops once it reaches "()".
590        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}