1use super::*;
2
3#[derive(Debug, Clone, PartialEq)]
5pub struct RdSexpr<'a> {
6 path: RdPath,
7 code: &'a str,
8 options: Option<RdOptionList<'a>>,
9}
10
11impl<'a> RdSexpr<'a> {
12 pub fn path(&self) -> &RdPath {
14 &self.path
15 }
16 pub fn code(&self) -> &'a str {
18 self.code
19 }
20 pub fn options(&self) -> Option<&RdOptionList<'a>> {
22 self.options.as_ref()
23 }
24 pub fn option_overrides(&self) -> RdSexprOptionOverrides {
26 self.options
27 .as_ref()
28 .map_or_else(RdSexprOptionOverrides::empty, RdOptionList::typed)
29 }
30}
31
32#[derive(Debug, Clone, PartialEq)]
34pub struct RdOpts<'a> {
35 path: RdPath,
36 options: RdOptionList<'a>,
37}
38
39impl<'a> RdOpts<'a> {
40 pub fn path(&self) -> &RdPath {
42 &self.path
43 }
44 pub fn options(&self) -> &RdOptionList<'a> {
46 &self.options
47 }
48 pub fn option_overrides(&self) -> RdSexprOptionOverrides {
50 self.options.typed()
51 }
52}
53
54#[derive(Debug, Clone, PartialEq)]
56pub struct RdResolvedSexpr<'a> {
57 view: RdSexpr<'a>,
58 effective: RdEffectiveSexprOptions,
59}
60
61impl<'a> RdResolvedSexpr<'a> {
62 pub fn view(&self) -> &RdSexpr<'a> {
64 &self.view
65 }
66 pub fn effective_options(&self) -> RdEffectiveSexprOptions {
68 self.effective
69 }
70 pub fn state(&self) -> RdDynamicMarkupState {
72 RdDynamicMarkupState::Unresolved {
73 stage: self.effective.stage,
74 }
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88#[non_exhaustive]
89pub enum RdDynamicMarkupState {
90 Unresolved { stage: RdSexprStage },
92}
93
94#[derive(Debug, Clone, PartialEq)]
96#[non_exhaustive]
97pub enum RdDynamicMarkupEvent<'a> {
98 OptionsChanged {
100 view: RdOpts<'a>,
101 effective: RdEffectiveSexprOptions,
102 },
103 Sexpr(RdResolvedSexpr<'a>),
105}
106
107pub struct RdDynamicMarkupIter<'a> {
114 frames: Vec<RdTraversalFrame<'a>>,
115 effective: RdEffectiveSexprOptions,
116}
117
118struct RdTraversalFrame<'a> {
119 nodes: &'a [RdNode],
120 next: usize,
121 path: RdPath,
122 top_level: bool,
123}
124
125impl<'a> Iterator for RdDynamicMarkupIter<'a> {
126 type Item = Result<RdDynamicMarkupEvent<'a>, RdOptionError>;
127 fn next(&mut self) -> Option<Self::Item> {
128 loop {
129 let frame = self.frames.last_mut()?;
130 if frame.next == frame.nodes.len() {
131 self.frames.pop();
132 continue;
133 }
134 let index = frame.next;
135 frame.next += 1;
136 let path = if frame.top_level {
137 RdPath::new(vec![RdPathSegment::TopLevel(index)])
138 } else {
139 frame.path.with_child(index)
140 };
141 let node = &frame.nodes[index];
142 if let Some(tagged) = node.as_tagged() {
143 let result = match tagged.tag() {
144 RdTag::RdOpts => match tagged.inspect_rd_opts(&path) {
145 Ok(view) => {
146 let mut effective = self.effective;
147 view.option_overrides().apply_to(&mut effective);
148 self.effective = effective;
149 Ok(RdDynamicMarkupEvent::OptionsChanged { view, effective })
150 }
151 Err(error) => Err(error),
152 },
153 RdTag::Sexpr => match tagged.inspect_sexpr(&path) {
154 Ok(view) => {
155 let mut effective = self.effective;
156 view.option_overrides().apply_to(&mut effective);
157 Ok(RdDynamicMarkupEvent::Sexpr(RdResolvedSexpr {
158 view,
159 effective,
160 }))
161 }
162 Err(error) => Err(error),
163 },
164 _ => {
165 self.push_children(tagged.children(), path);
166 continue;
167 }
168 };
169 self.push_children(tagged.children(), path);
170 return Some(result);
171 }
172 if let RdNode::Group(group) = node {
173 self.push_children(group.children(), path);
174 }
175 }
176 }
177}
178
179impl<'a> RdDynamicMarkupIter<'a> {
180 fn push_children(&mut self, nodes: &'a [RdNode], path: RdPath) {
181 self.frames.push(RdTraversalFrame {
182 nodes,
183 next: 0,
184 path,
185 top_level: false,
186 });
187 }
188}
189
190impl RdDocument {
191 pub fn inspect_dynamic_markup(&self) -> RdDynamicMarkupIter<'_> {
199 RdDynamicMarkupIter {
200 frames: vec![RdTraversalFrame {
201 nodes: self.nodes(),
202 next: 0,
203 path: RdPath::new(vec![]),
204 top_level: true,
205 }],
206 effective: RdEffectiveSexprOptions::default(),
207 }
208 }
209}
210
211impl RdTagged {
212 pub fn inspect_sexpr<'a>(&'a self, base_path: &RdPath) -> Result<RdSexpr<'a>, RdOptionError> {
214 if self.tag() != &RdTag::Sexpr {
215 return Err(shape(
216 base_path.clone(),
217 Some(self.tag().clone()),
218 RdShapeErrorKind::UnexpectedNode {
219 expected: RdExpectedNode::Sexpr,
220 actual: RdNodeKind::Tagged,
221 },
222 )
223 .into());
224 }
225 let children = self.children();
226 if children.len() != 1 {
227 return Err(shape(
228 base_path.clone(),
229 Some(RdTag::Sexpr),
230 RdShapeErrorKind::WrongArity {
231 expected: RdArity::Exactly(1),
232 actual: children.len(),
233 },
234 )
235 .into());
236 }
237 let code = match &children[0] {
238 RdNode::RCode(code) => code.as_str(),
239 node => {
240 return Err(shape(
241 base_path.with_child(0),
242 Some(RdTag::Sexpr),
243 RdShapeErrorKind::UnexpectedContent {
244 actual: RdNodeKind::of(node),
245 },
246 )
247 .into());
248 }
249 };
250 let options = self
251 .option()
252 .map(|nodes| RdOptionList::parse(nodes, base_path.with_option()))
253 .transpose()?;
254 Ok(RdSexpr {
255 path: base_path.clone(),
256 code,
257 options,
258 })
259 }
260
261 pub fn inspect_rd_opts<'a>(&'a self, base_path: &RdPath) -> Result<RdOpts<'a>, RdOptionError> {
263 if self.tag() != &RdTag::RdOpts {
264 return Err(shape(
265 base_path.clone(),
266 Some(self.tag().clone()),
267 RdShapeErrorKind::UnexpectedNode {
268 expected: RdExpectedNode::RdOpts,
269 actual: RdNodeKind::Tagged,
270 },
271 )
272 .into());
273 }
274 if self.option().is_some() {
275 return Err(shape(
276 base_path.clone(),
277 Some(RdTag::RdOpts),
278 RdShapeErrorKind::UnexpectedOption,
279 )
280 .into());
281 }
282 let options = RdOptionList::parse(self.children(), base_path.clone())?;
283 Ok(RdOpts {
284 path: base_path.clone(),
285 options,
286 })
287 }
288}