1use crate::quotes::{DelimitedReferences, 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>,
127 document_start: Cell<usize>,
130}
131
132type LineKey = (usize, bool);
137
138type LineFailure = (usize, nom::error::ErrorKind);
141
142#[derive(Debug, Clone, Default)]
152struct FurthestFailure {
153 address: Option<usize>,
156 expected: Vec<&'static str>,
157}
158
159#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct ParseFailure {
162 pub offset: usize,
164 pub expected: Vec<&'static str>,
168 pub kind: Option<nom::error::ErrorKind>,
172 pub max_depth_exceeded: Option<usize>,
175}
176
177pub struct SavedContext {
179 indentation_stack: Vec<usize>,
180 base_indentation: Option<usize>,
181 context_depth: usize,
182}
183
184impl Default for ParserState {
185 fn default() -> Self {
186 Self::new()
187 }
188}
189
190impl ParserState {
191 pub fn new() -> Self {
192 Self::with_max_depth(DEFAULT_MAX_DEPTH)
193 }
194
195 pub fn with_max_depth(max_depth: usize) -> Self {
197 ParserState {
198 indentation_stack: RefCell::new(vec![0]),
199 base_indentation: RefCell::new(None),
200 nested_depth: RefCell::new(0),
201 context_depth: RefCell::new(0),
202 max_depth,
203 too_deep: RefCell::new(None),
204 furthest: RefCell::new(FurthestFailure::default()),
205 unreadable_lines: RefCell::new(HashMap::new()),
206 references: OnceCell::new(),
207 document_start: Cell::new(0),
208 }
209 }
210
211 pub fn set_base_indentation(&self, indent: usize) {
212 let mut base = self.base_indentation.borrow_mut();
213 if base.is_none() {
214 *base = Some(indent);
215 }
216 }
217
218 pub fn get_base_indentation(&self) -> usize {
219 self.base_indentation.borrow().unwrap_or(0)
220 }
221
222 pub fn normalize_indentation(&self, indent: usize) -> usize {
223 let base = self.get_base_indentation();
224 indent.saturating_sub(base)
225 }
226
227 pub fn push_indentation(&self, indent: usize) {
228 self.indentation_stack.borrow_mut().push(indent);
229 }
230
231 pub fn pop_indentation(&self) {
232 let mut stack = self.indentation_stack.borrow_mut();
233 if stack.len() > 1 {
234 stack.pop();
235 }
236 }
237
238 pub fn current_indentation(&self) -> usize {
239 *self.indentation_stack.borrow().last().unwrap_or(&0)
240 }
241
242 pub fn check_indentation(&self, indent: usize) -> bool {
243 indent >= self.current_indentation()
244 }
245
246 pub fn enter_nested_context(&self) -> SavedContext {
249 let depth = self.depth() + 1;
250 let saved = SavedContext {
251 indentation_stack: self.indentation_stack.replace(vec![0]),
252 base_indentation: self.base_indentation.replace(None),
253 context_depth: self.context_depth.replace(depth),
254 };
255 *self.nested_depth.borrow_mut() += 1;
256 saved
257 }
258
259 pub fn exit_nested_context(&self, saved: SavedContext) {
261 *self.indentation_stack.borrow_mut() = saved.indentation_stack;
262 *self.base_indentation.borrow_mut() = saved.base_indentation;
263 *self.context_depth.borrow_mut() = saved.context_depth;
264 let mut depth = self.nested_depth.borrow_mut();
265 if *depth > 0 {
266 *depth -= 1;
267 }
268 }
269
270 pub fn is_inside_nested_context(&self) -> bool {
271 *self.nested_depth.borrow() > 0
272 }
273
274 pub fn depth(&self) -> usize {
277 *self.context_depth.borrow() + self.indentation_stack.borrow().len() - 1
278 }
279
280 fn check_depth<'a>(&self, at: &'a str, depth: usize) -> IResult<&'a str, ()> {
284 if depth <= self.max_depth {
285 return Ok((at, ()));
286 }
287 self.too_deep
288 .borrow_mut()
289 .get_or_insert(at.as_ptr() as usize);
290 Err(nom::Err::Failure(nom::error::Error::new(
291 at,
292 nom::error::ErrorKind::TooLarge,
293 )))
294 }
295
296 fn expected_at(&self, at: &str, what: &'static str) {
300 let address = at.as_ptr() as usize;
301 let mut furthest = self.furthest.borrow_mut();
302 match furthest.address {
303 Some(recorded) if recorded > address => {}
304 Some(recorded) if recorded == address => {
305 if !furthest.expected.contains(&what) {
306 furthest.expected.push(what);
307 }
308 }
309 _ => {
310 furthest.address = Some(address);
311 furthest.expected = vec![what];
312 }
313 }
314 }
315
316 fn failure(&self, document: &str, error: &nom::Err<nom::error::Error<&str>>) -> ParseFailure {
322 let base = document.as_ptr() as usize;
323 let (nom_offset, kind) = match error {
324 nom::Err::Error(e) | nom::Err::Failure(e) => (
325 (e.input.as_ptr() as usize).saturating_sub(base),
326 Some(e.code),
327 ),
328 nom::Err::Incomplete(_) => (document.len(), None),
329 };
330 if let Some(address) = *self.too_deep.borrow() {
331 return ParseFailure {
332 offset: address.saturating_sub(base).min(document.len()),
333 expected: Vec::new(),
334 kind,
335 max_depth_exceeded: Some(self.max_depth),
336 };
337 }
338 let furthest = self.furthest.borrow();
339 let tracked = furthest
340 .address
341 .map(|address| address.saturating_sub(base))
342 .unwrap_or(0);
343 let offset = tracked.max(nom_offset).min(document.len());
344 let expected = if tracked == offset {
345 furthest.expected.clone()
346 } else {
347 Vec::new()
350 };
351 ParseFailure {
352 offset,
353 expected,
354 kind,
355 max_depth_exceeded: None,
356 }
357 }
358}
359
360fn expected<'a, T>(
362 input: &'a str,
363 state: &ParserState,
364 what: &'static str,
365 kind: nom::error::ErrorKind,
366) -> IResult<&'a str, T> {
367 state.expected_at(input, what);
368 Err(nom::Err::Error(nom::error::Error::new(input, kind)))
369}
370
371pub(crate) fn is_whitespace_char(c: char) -> bool {
372 c == ' ' || c == '\t' || c == '\n' || c == '\r'
373}
374
375fn is_horizontal_whitespace(c: char) -> bool {
376 c == ' ' || c == '\t'
377}
378
379fn is_reference_char(c: char) -> bool {
380 !is_whitespace_char(c) && c != '(' && c != ':' && c != ')'
381}
382
383fn horizontal_whitespace(input: &str) -> IResult<&str, &str> {
384 take_while(is_horizontal_whitespace)(input)
385}
386
387fn whitespace(input: &str) -> IResult<&str, &str> {
388 take_while(is_whitespace_char)(input)
389}
390
391fn simple_reference(input: &str) -> IResult<&str, String> {
392 take_while1(is_reference_char)
393 .map(|s: &str| s.to_string())
394 .parse(input)
395}
396
397pub fn quoted_reference_end(document: &str, start: usize) -> Option<usize> {
404 let reading = read_reference(document.get(start..)?)?;
405 Some(start + reading.length)
406}
407
408fn delimited_reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
412 let references = state
413 .references
414 .get_or_init(|| DelimitedReferences::new(input));
415 match references.read(input) {
416 Some(Reading { value, length }) => Ok((&input[length..], value)),
417 None => Err(nom::Err::Error(nom::error::Error::new(
418 input,
419 nom::error::ErrorKind::Tag,
420 ))),
421 }
422}
423
424fn reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
425 if let Some(prefix) = crate::reference_literal::prefix_end(input) {
426 if let Some(closing) = input[prefix..].find('}') {
427 let length = prefix + closing + 1;
428 if let Ok(value) = crate::decode_reference_literal(&input[..length]) {
429 return Ok((&input[length..], value));
430 }
431 }
432 state.expected_at(input, "a valid version 1 reference literal");
433 return Err(nom::Err::Failure(nom::error::Error::new(
434 input,
435 nom::error::ErrorKind::Tag,
436 )));
437 }
438 let parsed = alt((|i| delimited_reference(i, state), simple_reference)).parse(input);
441 if parsed.is_err() {
442 state.expected_at(input, "a reference");
443 }
444 parsed
445}
446
447fn spanned_reference<'a>(
450 input: &'a str,
451 state: &ParserState,
452) -> IResult<&'a str, (String, Range<usize>)> {
453 let (rest, value) = reference(input, state)?;
454 let start = (input.as_ptr() as usize).saturating_sub(state.document_start.get());
455 let end = start + (input.len() - rest.len());
456 Ok((rest, (value, start..end)))
457}
458
459fn eol<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
460 let parsed = alt((
461 preceded(horizontal_whitespace, alt((line_ending, tag("\r")))),
462 preceded(horizontal_whitespace, eof),
463 |i| nested_group_end(i, state),
464 ))
465 .parse(input);
466 if parsed.is_err() {
467 state.expected_at(input, "end of line");
468 }
469 parsed
470}
471
472fn nested_group_end<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
475 if !state.is_inside_nested_context() {
476 return Err(nom::Err::Error(nom::error::Error::new(
477 input,
478 nom::error::ErrorKind::Verify,
479 )));
480 }
481 let (rest, _) = horizontal_whitespace(input)?;
482 if rest.starts_with(')') {
483 Ok((rest, ""))
484 } else {
485 expected(rest, state, "\")\"", nom::error::ErrorKind::Char)
486 }
487}
488
489fn skip_empty_lines(input: &str) -> &str {
492 let mut rest = input;
493 loop {
494 let line_start = rest.trim_start_matches(is_horizontal_whitespace);
495 match strip_line_ending(line_start) {
496 Some(next) => rest = next,
497 None => return rest,
498 }
499 }
500}
501
502fn strip_line_ending(input: &str) -> Option<&str> {
503 input
504 .strip_prefix("\r\n")
505 .or_else(|| input.strip_prefix('\n'))
506 .or_else(|| input.strip_prefix('\r'))
507}
508
509fn reference_or_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
510 alt((
511 |i| nested_group(i, state),
512 (|i| spanned_reference(i, state))
513 .map(|(id, span)| Link::new_singlet(id).with_id_span(span)),
514 ))
515 .parse(input)
516}
517
518fn single_line_value_and_whitespace<'a>(
519 input: &'a str,
520 state: &ParserState,
521) -> IResult<&'a str, Link> {
522 preceded(horizontal_whitespace, |i| reference_or_link(i, state)).parse(input)
523}
524
525fn single_line_values<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
526 many1(|i| single_line_value_and_whitespace(i, state)).parse(input)
527}
528
529fn single_line_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
530 let (input, _) = horizontal_whitespace(input)?;
531 let (input, (id, span)) = spanned_reference(input, state)?;
532 let (input, _) = horizontal_whitespace(input)?;
533 let (input, _) = colon(input, state)?;
534 let (input, values) = single_line_values(input, state)?;
535 Ok((input, Link::new_link(Some(id), values).with_id_span(span)))
536}
537
538fn colon<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
540 character(':', input, state, "\":\"")
541}
542
543fn character<'a>(
545 wanted: char,
546 input: &'a str,
547 state: &ParserState,
548 what: &'static str,
549) -> IResult<&'a str, char> {
550 let parsed: IResult<&'a str, char> = char(wanted).parse(input);
551 match parsed {
552 Ok(parsed) => Ok(parsed),
553 Err(_) => expected(input, state, what, nom::error::ErrorKind::Char),
554 }
555}
556
557fn single_line_value_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
558 (|i| single_line_values(i, state))
559 .map(Link::new_value)
560 .parse(input)
561}
562
563fn indented_id_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
564 let (input, (id, span)) = spanned_reference(input, state)?;
565 let (input, _) = horizontal_whitespace(input)?;
566 let (input, _) = colon(input, state)?;
567 let (input, _) = eol(input, state)?;
568 Ok((input, Link::new_indented_id(id).with_id_span(span)))
569}
570
571fn nested_group<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
575 let (body_input, _) = character('(', input, state, "\"(\"")?;
576 state.check_depth(input, state.depth() + 1)?;
577 let saved = state.enter_nested_context();
578 let result = nested_group_body(body_input, state);
579 state.exit_nested_context(saved);
580 result
581}
582
583fn nested_group_body<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
584 match links(skip_empty_lines(input), state) {
585 Ok((rest, body)) => {
586 let (rest, _) = whitespace(rest)?;
587 let (rest, _) = closing_parenthesis(rest, state)?;
588 return Ok((rest, Link::new_nested(body)));
589 }
590 Err(failure @ nom::Err::Failure(_)) => return Err(failure),
591 Err(_) => {}
592 }
593 let (rest, _) = whitespace(input)?;
594 let (rest, _) = closing_parenthesis(rest, state)?;
595 Ok((rest, Link::new_nested(vec![])))
596}
597
598fn closing_parenthesis<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
600 character(')', input, state, "\")\"")
601}
602
603fn single_line_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
604 alt((
605 terminated(|i| single_line_link(i, state), |i| eol(i, state)),
606 terminated(|i| single_line_value_link(i, state), |i| eol(i, state)),
607 ))
608 .parse(input)
609}
610
611fn any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
618 let key = (input.as_ptr() as usize, state.is_inside_nested_context());
619 if let Some(&(offset, kind)) = state.unreadable_lines.borrow().get(&key) {
620 return Err(nom::Err::Error(nom::error::Error::new(
621 &input[offset..],
622 kind,
623 )));
624 }
625 let parsed = read_any_link(input, state);
626 if let Err(nom::Err::Error(error)) = &parsed {
627 let offset = error.input.as_ptr() as usize - input.as_ptr() as usize;
628 state
629 .unreadable_lines
630 .borrow_mut()
631 .insert(key, (offset, error.code));
632 }
633 parsed
634}
635
636fn read_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
644 let (rest, group) = match nested_group(input, state) {
645 Ok(parsed) => parsed,
646 Err(_) if input.starts_with('(') => {
651 return spanned_reference(input, state)
652 .map(|(rest, (id, span))| (rest, Link::new_singlet(id).with_id_span(span)));
653 }
654 Err(_) => {
655 return alt((
656 |i| indented_id_link(i, state),
657 |i| single_line_any_link(i, state),
658 ))
659 .parse(input);
660 }
661 };
662 if let Ok((rest, _)) = eol(rest, state) {
663 return Ok((rest, group));
664 }
665 let (rest, more) = many0(|i| single_line_value_and_whitespace(i, state)).parse(rest)?;
666 let (rest, _) = eol(rest, state)?;
667 let mut values = Vec::with_capacity(more.len() + 1);
668 values.push(group);
669 values.extend(more);
670 Ok((rest, Link::new_value(values)))
671}
672
673fn count_indentation(input: &str) -> IResult<&str, usize> {
674 take_while(|c| c == ' ').map(|s: &str| s.len()).parse(input)
675}
676
677fn push_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
678 let (input, spaces) = count_indentation(skip_empty_lines(input))?;
679 let normalized_spaces = state.normalize_indentation(spaces);
680 let current = state.current_indentation();
681
682 if normalized_spaces > current {
683 state.push_indentation(normalized_spaces);
684 Ok((input, ()))
685 } else {
686 Err(nom::Err::Error(nom::error::Error::new(
687 input,
688 nom::error::ErrorKind::Verify,
689 )))
690 }
691}
692
693fn check_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
694 let (input, spaces) = count_indentation(input)?;
695 let normalized_spaces = state.normalize_indentation(spaces);
696
697 if state.check_indentation(normalized_spaces) {
698 Ok((input, ()))
699 } else {
700 Err(nom::Err::Error(nom::error::Error::new(
701 input,
702 nom::error::ErrorKind::Verify,
703 )))
704 }
705}
706
707fn element<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
708 let start = input;
709 let (input, link) = any_link(input, state)?;
710 state.check_depth(start, state.depth())?;
713
714 let indentation = state.indentation_stack.borrow().clone();
715 if let Ok((child_input, _)) = push_indentation(input, state) {
716 match links(child_input, state) {
717 Ok((rest, children)) => return Ok((rest, link.with_children(children))),
718 Err(failure @ nom::Err::Failure(_)) => return Err(failure),
719 Err(_) => {}
720 }
721 state.indentation_stack.replace(indentation);
724 }
725 Ok((input, link))
726}
727
728fn first_line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
729 let (input, spaces) = count_indentation(input)?;
732 state.set_base_indentation(spaces);
733 element(input, state)
734}
735
736fn line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
737 preceded(|i| check_indentation(i, state), |i| element(i, state)).parse(skip_empty_lines(input))
739}
740
741fn links<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
742 let (input, first) = first_line(input, state)?;
743 let (input, rest) = many0(|i| line(i, state)).parse(input)?;
744
745 state.pop_indentation();
746
747 let mut result = vec![first];
748 result.extend(rest);
749 Ok((input, result))
750}
751
752pub fn parse_document(input: &str) -> IResult<&str, Vec<Link>> {
753 let state = ParserState::new();
754 document(input, &state)
755}
756
757pub fn parse_document_with_diagnostics(input: &str) -> Result<Vec<Link>, ParseFailure> {
764 parse_document_with_max_depth(input, DEFAULT_MAX_DEPTH)
765}
766
767pub fn parse_document_with_max_depth(
771 input: &str,
772 max_depth: usize,
773) -> Result<Vec<Link>, ParseFailure> {
774 let state = ParserState::with_max_depth(max_depth);
775 match document(input, &state) {
776 Ok((_, links)) => Ok(links),
777 Err(error) => Err(state.failure(input, &error)),
778 }
779}
780
781fn document<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
782 state
785 .references
786 .get_or_init(|| DelimitedReferences::new(input));
787 state.document_start.set(input.as_ptr() as usize);
788
789 let document = skip_empty_lines(input);
791
792 if document.trim_matches(is_whitespace_char).is_empty() {
794 return Ok(("", vec![]));
795 }
796
797 let (rest, result) = links(document, state)?;
798 let (rest, _) = whitespace(rest)?;
799 let end: IResult<&'a str, &'a str> = eof(rest);
800 let (rest, _) = match end {
801 Ok(parsed) => parsed,
802 Err(_) => return expected(rest, state, "end of input", nom::error::ErrorKind::Eof),
803 };
804
805 Ok((rest, result))
806}