ast_description_lang/ast/collapsed/
mod.rs

1use super::Modifier;
2use crate::{
3  collections::{NamedItem, NamedSet, Unnamed},
4  Ident,
5};
6use std::{
7  fmt::{self, Display, Formatter},
8  ops::Deref,
9};
10
11mod transform;
12
13#[derive(Debug, Clone)]
14pub(super) struct Ast<'a> {
15  pub nodes: NamedSet<'a, Node<'a>>,
16  pub cyclic: Vec<usize>,
17}
18
19#[derive(Debug, Clone)]
20pub(super) struct Node<'a> {
21  pub ident: Ident<'a>,
22  pub kind: NodeKind<'a>,
23  pub tag: Option<Ident<'a>>,
24}
25
26#[derive(Debug, Clone)]
27pub(super) struct TaggedNodeKind<'n> {
28  pub kind: NodeKind<'n>,
29  pub tag: Option<Ident<'n>>,
30}
31
32#[derive(Clone, Debug)]
33pub(super) enum NodeKind<'n> {
34  Node(Ident<'n>),
35  StaticToken(Ident<'n>),
36  DynamicToken(Ident<'n>),
37  Group(Group<'n>),
38  /// Represents a parenthesized group that is zero-sized.
39  ///
40  /// It needs special handling, because unlike other groups,
41  /// zero-sized groups are allowed to be anonymous.
42  SubGroup(Vec<Node<'n>>),
43  Choice(Choice<'n>),
44  Delimited(Box<NodeKind<'n>>, Ident<'n>),
45  Modified(Box<NodeKind<'n>>, Modifier),
46  Todo,
47  End,
48}
49
50#[derive(Clone, Debug)]
51pub(super) struct Group<'g> {
52  pub members: Vec<Node<'g>>,
53  pub kind: GroupKind,
54  pub inline: bool,
55}
56
57#[derive(Clone, Debug)]
58pub(super) enum GroupKind {
59  One(usize),
60  Many(Vec<usize>),
61}
62
63#[derive(Clone, Debug)]
64pub(super) struct Choice<'c> {
65  pub kind: ChoiceKind<'c>,
66  pub inline: bool,
67}
68
69#[derive(Clone, Debug)]
70pub(super) enum ChoiceKind<'c> {
71  Regular(Vec<Node<'c>>),
72  Option {
73    primary: Box<Node<'c>>,
74    secondary: Ident<'c>,
75  },
76}
77
78impl Display for Node<'_> {
79  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
80    write!(f, "{}", self.kind)?;
81    if let Some(tag) = self.tag {
82      write!(f, ":{tag}")?;
83    }
84    Ok(())
85  }
86}
87
88impl<'a> Deref for Ast<'a> {
89  type Target = NamedSet<'a, Node<'a>>;
90
91  fn deref(&self) -> &Self::Target {
92    &self.nodes
93  }
94}
95
96impl<'n> NamedItem<'n> for Node<'n> {
97  type Name = Ident<'n>;
98  type Unnamed = TaggedNodeKind<'n>;
99
100  fn name(&self) -> Self::Name {
101    self.ident
102  }
103
104  fn dummy(name: Ident<'n>) -> Self {
105    Node {
106      ident: name,
107      kind: NodeKind::StaticToken(Ident("")),
108      tag: None,
109    }
110  }
111}
112
113impl<'n> Unnamed<'n> for TaggedNodeKind<'n> {
114  type Named = Node<'n>;
115
116  fn add_name(self, name: Ident<'n>) -> Self::Named {
117    Node {
118      ident: name,
119      kind: self.kind,
120      tag: self.tag,
121    }
122  }
123}
124
125impl Display for TaggedNodeKind<'_> {
126  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
127    write!(f, "{}", self.kind)?;
128    if let Some(tag) = self.tag {
129      write!(f, ":{tag}")?;
130    }
131    Ok(())
132  }
133}
134
135impl Display for NodeKind<'_> {
136  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
137    match self {
138      NodeKind::Node(ident) | NodeKind::StaticToken(ident) | NodeKind::DynamicToken(ident) => {
139        write!(f, "{ident}")
140      }
141      NodeKind::Group(Group {
142        members,
143        kind: _,
144        inline,
145      }) => {
146        if *inline {
147          write!(f, "(")?;
148        }
149
150        let mut members = members.iter();
151        write!(f, "{}", members.next().unwrap())?;
152        for member in members {
153          write!(f, " {member}")?;
154        }
155
156        if *inline {
157          write!(f, ")")?;
158        }
159
160        Ok(())
161      }
162      NodeKind::SubGroup(nodes) => {
163        let mut nodes = nodes.iter();
164        write!(f, "({}", nodes.next().unwrap())?;
165        for node in nodes {
166          write!(f, ", {node}")?;
167        }
168        write!(f, ")")?;
169        Ok(())
170      }
171      NodeKind::Choice(Choice {
172        kind: ChoiceKind::Regular(choices),
173        inline,
174      }) => {
175        if *inline {
176          write!(f, "(")?;
177        }
178
179        let mut choices = choices.iter();
180        write!(f, "{}", choices.next().unwrap())?;
181
182        if *inline {
183          write!(f, ")")?;
184        }
185        for choice in choices {
186          write!(f, " | {choice}")?;
187        }
188
189        Ok(())
190      }
191      NodeKind::Choice(Choice {
192        kind: ChoiceKind::Option { primary, secondary },
193        inline: _,
194      }) => {
195        write!(f, "{} | {}", primary.ident, secondary.0)
196      }
197      NodeKind::Delimited(inner, delimiter) => write!(f, "delim[{delimiter}]<{inner}>"),
198      NodeKind::Modified(inner, modifier) => write!(f, "{inner}{modifier}"),
199      NodeKind::Todo => write!(f, "!todo"),
200      NodeKind::End => write!(f, "EOF"),
201    }
202  }
203}
204
205#[cfg(test)]
206#[test]
207fn snapshots() {
208  use super::raw::Ast;
209  use insta::{assert_debug_snapshot, with_settings};
210  use std::{fs, path::Path};
211
212  for name in crate::SNAPSHOT_CASES {
213    let mut path = Path::new(env!("CARGO_MANIFEST_DIR"))
214      .join("examples")
215      .join(name)
216      .join("example");
217
218    path.set_extension("toml");
219    let specs = fs::read_to_string(&path).unwrap();
220    let specs = toml::de::from_str(&specs).unwrap();
221
222    path.set_extension("ast");
223    let text = fs::read_to_string(&path).unwrap();
224    with_settings!({input_file => Some(path)}, {
225      assert_debug_snapshot!(Ast::parse(&text).unwrap().transform(&specs).unwrap().transform());
226    });
227  }
228}