1use std::char::CharTryFromError;
21
22use nom::{
23 branch::alt,
24 character::complete::char,
25 combinator::eof,
26 error::{FromExternalError, ParseError},
27 Err as NomErr, IResult, Parser,
28};
29use nom_supreme::{context::ContextError, tag::TagError, ParserExt};
30
31use crate::{
32 annotation::{with_annotation, AnnotationBuilder, GenericAnnotated, RecognizedAnnotation},
33 number::BoundsError,
34 property::{parse_property, GenericProperty},
35 string::{parse_identifier, StringBuilder},
36 value::{parse_value, ValueBuilder},
37 whitespace::{parse_linespace, parse_node_space, parse_node_terminator},
38};
39
40fn run_parser_on<I, O, E>(input: &mut I, mut parser: impl Parser<I, O, E>) -> Result<O, NomErr<E>>
44where
45 I: Clone,
46{
47 parser.parse(input.clone()).map(|(tail, value)| {
48 *input = tail;
49 value
50 })
51}
52
53fn parse_node_start<'i, T, A, E>(
56 end_of_nodes: impl Parser<&'i str, (), E>,
57) -> impl Parser<&'i str, Option<GenericAnnotated<A, T>>, E>
58where
59 T: StringBuilder<'i>,
60 A: AnnotationBuilder<'i>,
61 E: ParseError<&'i str>,
62 E: TagError<&'i str, &'static str>,
63 E: FromExternalError<&'i str, CharTryFromError>,
64 E: ContextError<&'i str, &'static str>,
65{
66 with_annotation(parse_identifier)
67 .map(Some)
68 .context("node")
69 .or(end_of_nodes.map(|()| None))
70 .preceded_by(parse_linespace)
71}
72
73#[derive(Debug)]
77pub struct Node<'i, 'a, Name> {
78 pub name: Name,
80
81 pub content: NodeContent<'i, 'a>,
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub enum DrainOutcome {
89 Empty,
91
92 NotEmpty,
94}
95
96pub type RecognizedNode<'i, 'a> = Node<'i, 'a, ()>;
102
103pub trait NodeList<'i>: Sized {
106 fn next_node<'s, Annotation, Name, E>(
113 &'s mut self,
114 ) -> Result<Option<GenericAnnotated<Annotation, Node<'i, 's, Name>>>, NomErr<E>>
115 where
116 Annotation: AnnotationBuilder<'i>,
117 Name: StringBuilder<'i>,
118 E: ParseError<&'i str>,
119 E: TagError<&'i str, &'static str>,
120 E: FromExternalError<&'i str, CharTryFromError>,
121 E: ContextError<&'i str, &'static str>;
122
123 fn drain<E>(mut self) -> Result<DrainOutcome, NomErr<E>>
129 where
130 E: ParseError<&'i str>,
131 E: TagError<&'i str, &'static str>,
132 E: FromExternalError<&'i str, CharTryFromError>,
133 E: FromExternalError<&'i str, BoundsError>,
134 E: ContextError<&'i str, &'static str>,
135 {
136 match self.next_node()? {
137 None => Ok(DrainOutcome::Empty),
138 Some(RecognizedAnnotation {
139 item: RecognizedNode { content, .. },
140 ..
141 }) => {
142 content.drain()?;
143
144 while let Some(RecognizedAnnotation {
145 item: RecognizedNode { content, .. },
146 ..
147 }) = self.next_node()?
148 {
149 content.drain()?;
150 }
151
152 Ok(DrainOutcome::NotEmpty)
153 }
154 }
155 }
156}
157
158impl<'i, T: NodeList<'i>> NodeList<'i> for &mut T {
159 fn next_node<'s, Annotation, Name, E>(
160 &'s mut self,
161 ) -> Result<Option<GenericAnnotated<Annotation, Node<'i, 's, Name>>>, NomErr<E>>
162 where
163 Annotation: AnnotationBuilder<'i>,
164 Name: StringBuilder<'i>,
165 E: ParseError<&'i str>,
166 E: TagError<&'i str, &'static str>,
167 E: FromExternalError<&'i str, CharTryFromError>,
168 E: ContextError<&'i str, &'static str>,
169 {
170 T::next_node(*self)
171 }
172}
173
174#[derive(Debug, Clone)]
176pub struct Document<'i> {
177 state: &'i str,
179
180 child_in_progress: bool,
184}
185
186impl<'i> Document<'i> {
187 pub fn new(input: &'i str) -> Self {
189 Self {
190 state: input,
191 child_in_progress: false,
192 }
193 }
194
195 fn run_parser<T, E>(&mut self, parser: impl Parser<&'i str, T, E>) -> Result<T, NomErr<E>> {
196 run_parser_on(&mut self.state, parser)
197 }
198}
199
200impl<'i> NodeList<'i> for Document<'i> {
201 fn next_node<'s, Annotation, Name, E>(
202 &'s mut self,
203 ) -> Result<Option<GenericAnnotated<Annotation, Node<'i, 's, Name>>>, NomErr<E>>
204 where
205 Annotation: AnnotationBuilder<'i>,
206 Name: StringBuilder<'i>,
207 E: ParseError<&'i str>,
208 E: TagError<&'i str, &'static str>,
209 E: FromExternalError<&'i str, CharTryFromError>,
210 E: ContextError<&'i str, &'static str>,
211 {
212 if self.child_in_progress {
213 panic!(
214 "Called next_node before the previous node was fully parsed. This is a kaydle bug."
215 )
216 }
217
218 self.run_parser(parse_node_start(eof.value(())))
219 .map(move |opt_name| {
220 opt_name.map(move |annotated_name| {
221 self.child_in_progress = true;
222
223 annotated_name.map_item(|name| Node {
224 name,
225 content: NodeContent {
226 state: &mut self.state,
227 in_progress: &mut self.child_in_progress,
228 },
229 })
230 })
231 })
232 }
233}
234
235enum InternalNodeEvent<
236 ArgumentAnnotation,
237 Argument,
238 PropertyKey,
239 PropertyValueAnnotation,
240 PropertyValue,
241> {
242 Argument(GenericAnnotated<ArgumentAnnotation, Argument>),
243 Property(GenericProperty<PropertyKey, PropertyValueAnnotation, PropertyValue>),
244 Children,
245 End,
246}
247
248#[derive(Debug)]
250pub enum NodeEvent<
251 'i,
252 'p,
253 ArgumentAnnotation,
254 Argument,
255 PropertyKey,
256 PropertyValueAnnotation,
257 PropertyValue,
258> {
259 Argument {
261 argument: GenericAnnotated<ArgumentAnnotation, Argument>,
263 tail: NodeContent<'i, 'p>,
265 },
266
267 Property {
269 property: GenericProperty<PropertyKey, PropertyValueAnnotation, PropertyValue>,
271 tail: NodeContent<'i, 'p>,
273 },
274
275 Children {
277 children: Children<'i, 'p>,
279 },
280
281 End,
283}
284
285pub type RecognizedNodeEvent<'i, 'p> = NodeEvent<'i, 'p, (), (), (), (), ()>;
288
289fn parse_node_event<'i, E, VA, V, K, PA, P>(
290 input: &'i str,
291) -> IResult<&'i str, InternalNodeEvent<VA, V, K, PA, P>, E>
292where
293 V: ValueBuilder<'i>,
294 VA: AnnotationBuilder<'i>,
295 K: StringBuilder<'i>,
296 P: ValueBuilder<'i>,
297 PA: AnnotationBuilder<'i>,
298 E: ParseError<&'i str>,
299 E: TagError<&'i str, &'static str>,
300 E: FromExternalError<&'i str, CharTryFromError>,
301 E: FromExternalError<&'i str, BoundsError>,
302 E: ContextError<&'i str, &'static str>,
303{
304 alt((
305 alt((
307 parse_property
310 .map(InternalNodeEvent::Property)
311 .context("property"),
312 parse_value
313 .map(InternalNodeEvent::Argument)
314 .context("value"),
315 ))
316 .preceded_by(parse_node_space),
317 alt((
319 char('{')
320 .map(|_| InternalNodeEvent::Children)
321 .context("children"),
322 parse_node_terminator.map(|()| InternalNodeEvent::End),
323 ))
324 .preceded_by(parse_node_space.opt()),
325 ))
326 .parse(input)
327}
328
329#[derive(Debug)]
334pub struct NodeContent<'i, 'p> {
335 state: &'p mut &'i str,
337
338 in_progress: &'p mut bool,
341}
342
343impl<'i, 'p> NodeContent<'i, 'p> {
344 pub fn next_event<
354 ArgumentAnnotation,
355 Argument,
356 PropertyKey,
357 PropertyValueAnnotation,
358 PropertyValue,
359 Error,
360 >(
361 mut self,
362 ) -> Result<
363 NodeEvent<
364 'i,
365 'p,
366 ArgumentAnnotation,
367 Argument,
368 PropertyKey,
369 PropertyValueAnnotation,
370 PropertyValue,
371 >,
372 NomErr<Error>,
373 >
374 where
375 Argument: ValueBuilder<'i>,
376 ArgumentAnnotation: AnnotationBuilder<'i>,
377 PropertyKey: StringBuilder<'i>,
378 PropertyValue: ValueBuilder<'i>,
379 PropertyValueAnnotation: AnnotationBuilder<'i>,
380 Error: ParseError<&'i str>,
381 Error: TagError<&'i str, &'static str>,
382 Error: FromExternalError<&'i str, CharTryFromError>,
383 Error: FromExternalError<&'i str, BoundsError>,
384 Error: ContextError<&'i str, &'static str>,
385 {
386 self.run_parser(parse_node_event)
390 .map(move |event| match event {
391 InternalNodeEvent::Argument(argument) => NodeEvent::Argument {
392 argument,
393 tail: self,
394 },
395 InternalNodeEvent::Property(property) => NodeEvent::Property {
396 property,
397 tail: self,
398 },
399 InternalNodeEvent::Children => NodeEvent::Children {
400 children: Children {
401 state: self.state,
402 in_progress: self.in_progress,
403 child_in_progress: false,
404 },
405 },
406 InternalNodeEvent::End => {
407 *self.in_progress = false;
408 NodeEvent::End
409 }
410 })
411 }
412
413 pub fn drain<E>(mut self) -> Result<DrainOutcome, NomErr<E>>
418 where
419 E: ParseError<&'i str>,
420 E: TagError<&'i str, &'static str>,
421 E: FromExternalError<&'i str, CharTryFromError>,
422 E: FromExternalError<&'i str, BoundsError>,
423 E: ContextError<&'i str, &'static str>,
424 {
425 self = match self.next_event()? {
426 RecognizedNodeEvent::Argument { tail, .. } => tail,
427 RecognizedNodeEvent::Property { tail, .. } => tail,
428 RecognizedNodeEvent::Children { children } => return children.drain(),
429 RecognizedNodeEvent::End => return Ok(DrainOutcome::Empty),
430 };
431
432 loop {
433 self = match self.next_event()? {
434 RecognizedNodeEvent::Argument { tail, .. } => tail,
435 RecognizedNodeEvent::Property { tail, .. } => tail,
436 RecognizedNodeEvent::Children { children } => {
437 children.drain()?;
438 return Ok(DrainOutcome::NotEmpty);
439 }
440 RecognizedNodeEvent::End => return Ok(DrainOutcome::NotEmpty),
441 }
442 }
443 }
444
445 fn run_parser<T, E>(&mut self, parser: impl Parser<&'i str, T, E>) -> Result<T, NomErr<E>> {
446 run_parser_on(self.state, parser)
447 }
448}
449
450#[derive(Debug)]
453pub struct Children<'i, 'p> {
454 state: &'p mut &'i str,
455
456 in_progress: &'p mut bool,
460
461 child_in_progress: bool,
465}
466
467impl<'i> Children<'i, '_> {
468 fn run_parser<T, E>(&mut self, parser: impl Parser<&'i str, T, E>) -> Result<T, NomErr<E>> {
469 run_parser_on(self.state, parser)
470 }
471}
472
473impl<'i> NodeList<'i> for Children<'i, '_> {
474 fn next_node<'s, A, N, E>(
475 &'s mut self,
476 ) -> Result<Option<GenericAnnotated<A, Node<'i, 's, N>>>, nom::Err<E>>
477 where
478 N: StringBuilder<'i>,
479 A: AnnotationBuilder<'i>,
480 E: ParseError<&'i str>,
481 E: TagError<&'i str, &'static str>,
482
483 E: FromExternalError<&'i str, CharTryFromError>,
484 E: ContextError<&'i str, &'static str>,
485 {
486 if !*self.in_progress {
489 return Ok(None);
490 }
491
492 if self.child_in_progress {
495 panic!(
496 "Called next_node before the previous node was fully parsed. This is a kaydle bug."
497 )
498 }
499
500 self.run_parser(parse_node_start(char('}').value(())))
501 .map(|opt_name| match opt_name {
502 None => {
504 *self.in_progress = false;
505 None
506 }
507 Some(annotated_name) => {
508 self.child_in_progress = true;
509
510 Some(annotated_name.map_item(|name| Node {
511 name,
512 content: NodeContent {
513 state: self.state,
514 in_progress: &mut self.child_in_progress,
515 },
516 }))
517 }
518 })
519 }
520}
521
522#[test]
526fn test_full_document_drain() {
527 let content = r##"
528 // This is a KDL document!
529 node1 "arg1" prop=10 {
530 (u8)item 10
531 (u8)item 20
532 items {
533 a /* An important note here */ "abc"
534 d "def"; g "ghi"
535 }
536 }
537 (annotated)node2
538 primitives null false true 10 10.5 -10 -10.5 3e6 0x10c 0b00001111 0o755
539 (a)annotated (n)null (f)false (t)true (i)10 (f)10.5 (n)-10.5e7
540 "##;
541
542 let processor = Document::new(content);
543
544 let res: Result<DrainOutcome, nom::Err<()>> = processor.drain();
545 assert_eq!(res.expect("parse error"), DrainOutcome::NotEmpty);
546}