ast_description_lang/ast/collapsed/
mod.rs1use 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 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}