1use crate::quotes::{DelimitedReferences, QUOTES, Reading, read_reference};
2use nom::{
3 IResult, Parser,
4 branch::alt,
5 bytes::complete::{tag, take_while, take_while1},
6 character::complete::{char, line_ending},
7 combinator::eof,
8 multi::{many0, many1},
9 sequence::{preceded, terminated},
10};
11use std::cell::{Cell, OnceCell, RefCell};
12use std::collections::HashMap;
13use std::ops::Range;
14
15#[derive(Debug, Clone, PartialEq)]
16pub struct Link {
17 pub id: Option<String>,
18 pub values: Vec<Link>,
19 pub children: Vec<Link>,
20 pub is_indented_id: bool,
21 pub nested: Option<Vec<Link>>,
24 pub id_span: Option<Range<usize>>,
30}
31
32impl Link {
33 pub fn new_singlet(id: String) -> Self {
34 Link {
35 id: Some(id),
36 values: vec![],
37 children: vec![],
38 is_indented_id: false,
39 nested: None,
40 id_span: None,
41 }
42 }
43
44 pub fn new_indented_id(id: String) -> Self {
45 Link {
46 id: Some(id),
47 values: vec![],
48 children: vec![],
49 is_indented_id: true,
50 nested: None,
51 id_span: None,
52 }
53 }
54
55 pub fn new_value(values: Vec<Link>) -> Self {
56 Link {
57 id: None,
58 values,
59 children: vec![],
60 is_indented_id: false,
61 nested: None,
62 id_span: None,
63 }
64 }
65
66 pub fn new_link(id: Option<String>, values: Vec<Link>) -> Self {
67 Link {
68 id,
69 values,
70 children: vec![],
71 is_indented_id: false,
72 nested: None,
73 id_span: None,
74 }
75 }
76
77 pub fn new_nested(body: Vec<Link>) -> Self {
80 Link {
81 id: None,
82 values: vec![],
83 children: vec![],
84 is_indented_id: false,
85 nested: Some(body),
86 id_span: None,
87 }
88 }
89
90 pub fn with_children(mut self, children: Vec<Link>) -> Self {
91 self.children = children;
92 self
93 }
94
95 pub fn with_id_span(mut self, span: Range<usize>) -> Self {
97 self.id_span = Some(span);
98 self
99 }
100}
101
102pub const DEFAULT_MAX_DEPTH: usize = 64;
111
112pub struct ParserState {
113 indentation_stack: RefCell<Vec<usize>>,
114 base_indentation: RefCell<Option<usize>>,
115 nested_depth: RefCell<usize>,
116 context_depth: RefCell<usize>,
119 max_depth: usize,
120 too_deep: RefCell<Option<usize>>,
123 furthest: RefCell<FurthestFailure>,
124 unreadable_lines: RefCell<HashMap<LineKey, LineFailure>>,
125 references: OnceCell<DelimitedReferences>,
128 source: Option<Box<str>>,
133 document_start: Cell<usize>,
136}
137
138type LineKey = (usize, bool);
143
144type LineFailure = (usize, nom::error::ErrorKind);
147
148#[derive(Debug, Clone, Default)]
158struct FurthestFailure {
159 address: Option<usize>,
162 expected: Vec<&'static str>,
163}
164
165#[derive(Debug, Clone, PartialEq, Eq)]
167pub struct ParseFailure {
168 pub offset: usize,
170 pub expected: Vec<&'static str>,
174 pub kind: Option<nom::error::ErrorKind>,
178 pub max_depth_exceeded: Option<usize>,
181}
182
183pub struct SavedContext {
185 indentation_stack: Vec<usize>,
186 base_indentation: Option<usize>,
187 context_depth: usize,
188}
189
190impl Default for ParserState {
191 fn default() -> Self {
192 Self::new()
193 }
194}
195
196impl ParserState {
197 pub fn new() -> Self {
198 Self::with_max_depth(DEFAULT_MAX_DEPTH)
199 }
200
201 pub fn with_max_depth(max_depth: usize) -> Self {
203 ParserState {
204 indentation_stack: RefCell::new(vec![0]),
205 base_indentation: RefCell::new(None),
206 nested_depth: RefCell::new(0),
207 context_depth: RefCell::new(0),
208 max_depth,
209 too_deep: RefCell::new(None),
210 furthest: RefCell::new(FurthestFailure::default()),
211 unreadable_lines: RefCell::new(HashMap::new()),
212 references: OnceCell::new(),
213 source: None,
214 document_start: Cell::new(0),
215 }
216 }
217
218 fn written<'s>(&'s self, input: &'s str) -> &'s str {
224 match &self.source {
225 Some(source) if input.as_bytes().first().is_some_and(|b| QUOTES.contains(b)) => source
226 .len()
227 .checked_sub(input.len())
228 .and_then(|start| source.get(start..))
229 .unwrap_or(input),
230 _ => input,
231 }
232 }
233
234 fn references(&self, input: &str) -> &DelimitedReferences {
238 self.references
239 .get_or_init(|| DelimitedReferences::new(self.source.as_deref().unwrap_or(input)))
240 }
241
242 pub fn set_base_indentation(&self, indent: usize) {
243 let mut base = self.base_indentation.borrow_mut();
244 if base.is_none() {
245 *base = Some(indent);
246 }
247 }
248
249 pub fn get_base_indentation(&self) -> usize {
250 self.base_indentation.borrow().unwrap_or(0)
251 }
252
253 pub fn normalize_indentation(&self, indent: usize) -> usize {
254 let base = self.get_base_indentation();
255 indent.saturating_sub(base)
256 }
257
258 pub fn push_indentation(&self, indent: usize) {
259 self.indentation_stack.borrow_mut().push(indent);
260 }
261
262 pub fn pop_indentation(&self) {
263 let mut stack = self.indentation_stack.borrow_mut();
264 if stack.len() > 1 {
265 stack.pop();
266 }
267 }
268
269 pub fn current_indentation(&self) -> usize {
270 *self.indentation_stack.borrow().last().unwrap_or(&0)
271 }
272
273 pub fn check_indentation(&self, indent: usize) -> bool {
274 indent >= self.current_indentation()
275 }
276
277 pub fn enter_nested_context(&self) -> SavedContext {
280 let depth = self.depth() + 1;
281 let saved = SavedContext {
282 indentation_stack: self.indentation_stack.replace(vec![0]),
283 base_indentation: self.base_indentation.replace(None),
284 context_depth: self.context_depth.replace(depth),
285 };
286 *self.nested_depth.borrow_mut() += 1;
287 saved
288 }
289
290 pub fn exit_nested_context(&self, saved: SavedContext) {
292 *self.indentation_stack.borrow_mut() = saved.indentation_stack;
293 *self.base_indentation.borrow_mut() = saved.base_indentation;
294 *self.context_depth.borrow_mut() = saved.context_depth;
295 let mut depth = self.nested_depth.borrow_mut();
296 if *depth > 0 {
297 *depth -= 1;
298 }
299 }
300
301 pub fn is_inside_nested_context(&self) -> bool {
302 *self.nested_depth.borrow() > 0
303 }
304
305 pub fn depth(&self) -> usize {
308 *self.context_depth.borrow() + self.indentation_stack.borrow().len() - 1
309 }
310
311 fn check_depth<'a>(&self, at: &'a str, depth: usize) -> IResult<&'a str, ()> {
315 if depth <= self.max_depth {
316 return Ok((at, ()));
317 }
318 self.too_deep
319 .borrow_mut()
320 .get_or_insert(at.as_ptr() as usize);
321 Err(nom::Err::Failure(nom::error::Error::new(
322 at,
323 nom::error::ErrorKind::TooLarge,
324 )))
325 }
326
327 fn expected_at(&self, at: &str, what: &'static str) {
331 let address = at.as_ptr() as usize;
332 let mut furthest = self.furthest.borrow_mut();
333 match furthest.address {
334 Some(recorded) if recorded > address => {}
335 Some(recorded) if recorded == address => {
336 if !furthest.expected.contains(&what) {
337 furthest.expected.push(what);
338 }
339 }
340 _ => {
341 furthest.address = Some(address);
342 furthest.expected = vec![what];
343 }
344 }
345 }
346
347 fn failure(&self, document: &str, error: &nom::Err<nom::error::Error<&str>>) -> ParseFailure {
353 let base = document.as_ptr() as usize;
354 let (nom_offset, kind) = match error {
355 nom::Err::Error(e) | nom::Err::Failure(e) => (
356 (e.input.as_ptr() as usize).saturating_sub(base),
357 Some(e.code),
358 ),
359 nom::Err::Incomplete(_) => (document.len(), None),
360 };
361 if let Some(address) = *self.too_deep.borrow() {
362 return ParseFailure {
363 offset: address.saturating_sub(base).min(document.len()),
364 expected: Vec::new(),
365 kind,
366 max_depth_exceeded: Some(self.max_depth),
367 };
368 }
369 let furthest = self.furthest.borrow();
370 let tracked = furthest
371 .address
372 .map(|address| address.saturating_sub(base))
373 .unwrap_or(0);
374 let offset = tracked.max(nom_offset).min(document.len());
375 let expected = if tracked == offset {
376 furthest.expected.clone()
377 } else {
378 Vec::new()
381 };
382 ParseFailure {
383 offset,
384 expected,
385 kind,
386 max_depth_exceeded: None,
387 }
388 }
389}
390
391fn expected<'a, T>(
393 input: &'a str,
394 state: &ParserState,
395 what: &'static str,
396 kind: nom::error::ErrorKind,
397) -> IResult<&'a str, T> {
398 state.expected_at(input, what);
399 Err(nom::Err::Error(nom::error::Error::new(input, kind)))
400}
401
402pub(crate) fn is_whitespace_char(c: char) -> bool {
403 c == ' ' || c == '\t' || c == '\n' || c == '\r'
404}
405
406fn is_horizontal_whitespace(c: char) -> bool {
407 c == ' ' || c == '\t'
408}
409
410fn is_reference_char(c: char) -> bool {
411 !is_whitespace_char(c) && c != '(' && c != ':' && c != ')'
412}
413
414fn horizontal_whitespace(input: &str) -> IResult<&str, &str> {
415 take_while(is_horizontal_whitespace)(input)
416}
417
418fn whitespace(input: &str) -> IResult<&str, &str> {
419 take_while(is_whitespace_char)(input)
420}
421
422fn simple_reference(input: &str) -> IResult<&str, String> {
423 take_while1(is_reference_char)
424 .map(|s: &str| s.to_string())
425 .parse(input)
426}
427
428pub fn quoted_reference_end(document: &str, start: usize) -> Option<usize> {
435 let reading = read_reference(document.get(start..)?)?;
436 Some(start + reading.length)
437}
438
439fn delimited_reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
447 match state.references(input).read(state.written(input)) {
448 Some(Reading { value, length, .. }) => Ok((&input[length..], value)),
449 None => Err(nom::Err::Error(nom::error::Error::new(
450 input,
451 nom::error::ErrorKind::Tag,
452 ))),
453 }
454}
455
456fn reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
457 if let Some(prefix) = crate::reference_literal::prefix_end(input) {
458 if let Some(closing) = input[prefix..].find('}') {
459 let length = prefix + closing + 1;
460 if let Ok(value) = crate::decode_reference_literal(&input[..length]) {
461 return Ok((&input[length..], value));
462 }
463 }
464 state.expected_at(input, "a valid version 1 reference literal");
465 return Err(nom::Err::Failure(nom::error::Error::new(
466 input,
467 nom::error::ErrorKind::Tag,
468 )));
469 }
470 let parsed = alt((|i| delimited_reference(i, state), simple_reference)).parse(input);
473 if parsed.is_err() {
474 state.expected_at(input, "a reference");
475 }
476 parsed
477}
478
479fn spanned_reference<'a>(
482 input: &'a str,
483 state: &ParserState,
484) -> IResult<&'a str, (String, Range<usize>)> {
485 let (rest, value) = reference(input, state)?;
486 let start = (input.as_ptr() as usize).saturating_sub(state.document_start.get());
487 let end = start + (input.len() - rest.len());
488 Ok((rest, (value, start..end)))
489}
490
491fn eol<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
492 let parsed = alt((
493 preceded(horizontal_whitespace, alt((line_ending, tag("\r")))),
494 preceded(horizontal_whitespace, eof),
495 |i| nested_group_end(i, state),
496 ))
497 .parse(input);
498 if parsed.is_err() {
499 state.expected_at(input, "end of line");
500 }
501 parsed
502}
503
504fn nested_group_end<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
507 if !state.is_inside_nested_context() {
508 return Err(nom::Err::Error(nom::error::Error::new(
509 input,
510 nom::error::ErrorKind::Verify,
511 )));
512 }
513 let (rest, _) = horizontal_whitespace(input)?;
514 if rest.starts_with(')') {
515 Ok((rest, ""))
516 } else {
517 expected(rest, state, "\")\"", nom::error::ErrorKind::Char)
518 }
519}
520
521fn skip_empty_lines(input: &str) -> &str {
524 let mut rest = input;
525 loop {
526 let line_start = rest.trim_start_matches(is_horizontal_whitespace);
527 match strip_line_ending(line_start) {
528 Some(next) => rest = next,
529 None => return rest,
530 }
531 }
532}
533
534fn strip_line_ending(input: &str) -> Option<&str> {
535 input
536 .strip_prefix("\r\n")
537 .or_else(|| input.strip_prefix('\n'))
538 .or_else(|| input.strip_prefix('\r'))
539}
540
541fn reference_or_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
542 alt((
543 |i| nested_group(i, state),
544 (|i| spanned_reference(i, state))
545 .map(|(id, span)| Link::new_singlet(id).with_id_span(span)),
546 ))
547 .parse(input)
548}
549
550fn single_line_value_and_whitespace<'a>(
551 input: &'a str,
552 state: &ParserState,
553) -> IResult<&'a str, Link> {
554 preceded(horizontal_whitespace, |i| reference_or_link(i, state)).parse(input)
555}
556
557fn single_line_values<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
558 many1(|i| single_line_value_and_whitespace(i, state)).parse(input)
559}
560
561fn single_line_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
562 let (input, _) = horizontal_whitespace(input)?;
563 let (input, (id, span)) = spanned_reference(input, state)?;
564 let (input, _) = horizontal_whitespace(input)?;
565 let (input, _) = colon(input, state)?;
566 let (input, values) = single_line_values(input, state)?;
567 Ok((input, Link::new_link(Some(id), values).with_id_span(span)))
568}
569
570fn colon<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
572 character(':', input, state, "\":\"")
573}
574
575fn character<'a>(
577 wanted: char,
578 input: &'a str,
579 state: &ParserState,
580 what: &'static str,
581) -> IResult<&'a str, char> {
582 let parsed: IResult<&'a str, char> = char(wanted).parse(input);
583 match parsed {
584 Ok(parsed) => Ok(parsed),
585 Err(_) => expected(input, state, what, nom::error::ErrorKind::Char),
586 }
587}
588
589fn single_line_value_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
590 (|i| single_line_values(i, state))
591 .map(Link::new_value)
592 .parse(input)
593}
594
595fn indented_id_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
596 let (input, (id, span)) = spanned_reference(input, state)?;
597 let (input, _) = horizontal_whitespace(input)?;
598 let (input, _) = colon(input, state)?;
599 let (input, _) = eol(input, state)?;
600 Ok((input, Link::new_indented_id(id).with_id_span(span)))
601}
602
603fn nested_group<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
607 let (body_input, _) = character('(', input, state, "\"(\"")?;
608 state.check_depth(input, state.depth() + 1)?;
609 let saved = state.enter_nested_context();
610 let result = nested_group_body(body_input, state);
611 state.exit_nested_context(saved);
612 result
613}
614
615fn nested_group_body<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
616 match links(skip_empty_lines(input), state) {
617 Ok((rest, body)) => {
618 let (rest, _) = whitespace(rest)?;
619 let (rest, _) = closing_parenthesis(rest, state)?;
620 return Ok((rest, Link::new_nested(body)));
621 }
622 Err(failure @ nom::Err::Failure(_)) => return Err(failure),
623 Err(_) => {}
624 }
625 let (rest, _) = whitespace(input)?;
626 let (rest, _) = closing_parenthesis(rest, state)?;
627 Ok((rest, Link::new_nested(vec![])))
628}
629
630fn closing_parenthesis<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
632 character(')', input, state, "\")\"")
633}
634
635fn single_line_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
636 alt((
637 terminated(|i| single_line_link(i, state), |i| eol(i, state)),
638 terminated(|i| single_line_value_link(i, state), |i| eol(i, state)),
639 ))
640 .parse(input)
641}
642
643fn any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
650 let key = (input.as_ptr() as usize, state.is_inside_nested_context());
651 if let Some(&(offset, kind)) = state.unreadable_lines.borrow().get(&key) {
652 return Err(nom::Err::Error(nom::error::Error::new(
653 &input[offset..],
654 kind,
655 )));
656 }
657 let parsed = read_any_link(input, state);
658 if let Err(nom::Err::Error(error)) = &parsed {
659 let offset = error.input.as_ptr() as usize - input.as_ptr() as usize;
660 state
661 .unreadable_lines
662 .borrow_mut()
663 .insert(key, (offset, error.code));
664 }
665 parsed
666}
667
668fn read_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
676 let (rest, group) = match nested_group(input, state) {
677 Ok(parsed) => parsed,
678 Err(_) if input.starts_with('(') => {
683 return spanned_reference(input, state)
684 .map(|(rest, (id, span))| (rest, Link::new_singlet(id).with_id_span(span)));
685 }
686 Err(_) => {
687 return alt((
688 |i| indented_id_link(i, state),
689 |i| single_line_any_link(i, state),
690 ))
691 .parse(input);
692 }
693 };
694 if let Ok((rest, _)) = eol(rest, state) {
695 return Ok((rest, group));
696 }
697 let (rest, more) = many0(|i| single_line_value_and_whitespace(i, state)).parse(rest)?;
698 let (rest, _) = eol(rest, state)?;
699 let mut values = Vec::with_capacity(more.len() + 1);
700 values.push(group);
701 values.extend(more);
702 Ok((rest, Link::new_value(values)))
703}
704
705fn count_indentation(input: &str) -> IResult<&str, usize> {
706 take_while(|c| c == ' ').map(|s: &str| s.len()).parse(input)
707}
708
709fn push_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
710 let (input, spaces) = count_indentation(skip_empty_lines(input))?;
711 let normalized_spaces = state.normalize_indentation(spaces);
712 let current = state.current_indentation();
713
714 if normalized_spaces > current {
715 state.push_indentation(normalized_spaces);
716 Ok((input, ()))
717 } else {
718 Err(nom::Err::Error(nom::error::Error::new(
719 input,
720 nom::error::ErrorKind::Verify,
721 )))
722 }
723}
724
725fn check_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
726 let (input, spaces) = count_indentation(input)?;
727 let normalized_spaces = state.normalize_indentation(spaces);
728
729 if state.check_indentation(normalized_spaces) {
730 Ok((input, ()))
731 } else {
732 Err(nom::Err::Error(nom::error::Error::new(
733 input,
734 nom::error::ErrorKind::Verify,
735 )))
736 }
737}
738
739fn element<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
740 let start = input;
741 let (input, link) = any_link(input, state)?;
742 state.check_depth(start, state.depth())?;
745
746 let indentation = state.indentation_stack.borrow().clone();
747 if let Ok((child_input, _)) = push_indentation(input, state) {
748 match links(child_input, state) {
749 Ok((rest, children)) => return Ok((rest, link.with_children(children))),
750 Err(failure @ nom::Err::Failure(_)) => return Err(failure),
751 Err(_) => {}
752 }
753 state.indentation_stack.replace(indentation);
756 }
757 Ok((input, link))
758}
759
760fn first_line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
761 let (input, spaces) = count_indentation(input)?;
764 state.set_base_indentation(spaces);
765 element(input, state)
766}
767
768fn line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
769 preceded(|i| check_indentation(i, state), |i| element(i, state)).parse(skip_empty_lines(input))
771}
772
773fn links<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
774 let (input, first) = first_line(input, state)?;
775 let (input, rest) = many0(|i| line(i, state)).parse(input)?;
776
777 state.pop_indentation();
778
779 let mut result = vec![first];
780 result.extend(rest);
781 Ok((input, result))
782}
783
784pub fn parse_document(input: &str) -> IResult<&str, Vec<Link>> {
785 let state = ParserState::new();
786 document(input, &state)
787}
788
789pub fn parse_document_with_diagnostics(input: &str) -> Result<Vec<Link>, ParseFailure> {
796 parse_document_with_max_depth(input, DEFAULT_MAX_DEPTH)
797}
798
799pub fn parse_document_with_max_depth(
803 input: &str,
804 max_depth: usize,
805) -> Result<Vec<Link>, ParseFailure> {
806 let state = ParserState::with_max_depth(max_depth);
807 match document(input, &state) {
808 Ok((_, links)) => Ok(links),
809 Err(error) => Err(state.failure(input, &error)),
810 }
811}
812
813pub(crate) fn parse_prepared_document(
817 prepared: &str,
818 source: &str,
819 max_depth: usize,
820) -> Result<Vec<Link>, ParseFailure> {
821 debug_assert_eq!(prepared.len(), source.len());
822 let mut state = ParserState::with_max_depth(max_depth);
823 if prepared != source {
824 state.source = Some(source.into());
825 }
826 match document(prepared, &state) {
827 Ok((_, links)) => Ok(links),
828 Err(error) => Err(state.failure(prepared, &error)),
829 }
830}
831
832fn document<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
833 state.references(input);
836 state.document_start.set(input.as_ptr() as usize);
837
838 let document = skip_empty_lines(input);
840
841 if document.trim_matches(is_whitespace_char).is_empty() {
843 return Ok(("", vec![]));
844 }
845
846 let (rest, result) = links(document, state)?;
847 let (rest, _) = whitespace(rest)?;
848 let end: IResult<&'a str, &'a str> = eof(rest);
849 let (rest, _) = match end {
850 Ok(parsed) => parsed,
851 Err(_) => return expected(rest, state, "end of input", nom::error::ErrorKind::Eof),
852 };
853
854 Ok((rest, result))
855}