1use crate::quotes::{read_reference, DelimitedReferences, Reading};
2use nom::{
3 branch::alt,
4 bytes::complete::{tag, take_while, take_while1},
5 character::complete::{char, line_ending},
6 combinator::eof,
7 multi::{many0, many1},
8 sequence::{preceded, terminated},
9 IResult, Parser,
10};
11use std::cell::{OnceCell, RefCell};
12use std::collections::HashMap;
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct Link {
16 pub id: Option<String>,
17 pub values: Vec<Link>,
18 pub children: Vec<Link>,
19 pub is_indented_id: bool,
20 pub nested: Option<Vec<Link>>,
23}
24
25impl Link {
26 pub fn new_singlet(id: String) -> Self {
27 Link {
28 id: Some(id),
29 values: vec![],
30 children: vec![],
31 is_indented_id: false,
32 nested: None,
33 }
34 }
35
36 pub fn new_indented_id(id: String) -> Self {
37 Link {
38 id: Some(id),
39 values: vec![],
40 children: vec![],
41 is_indented_id: true,
42 nested: None,
43 }
44 }
45
46 pub fn new_value(values: Vec<Link>) -> Self {
47 Link {
48 id: None,
49 values,
50 children: vec![],
51 is_indented_id: false,
52 nested: None,
53 }
54 }
55
56 pub fn new_link(id: Option<String>, values: Vec<Link>) -> Self {
57 Link {
58 id,
59 values,
60 children: vec![],
61 is_indented_id: false,
62 nested: None,
63 }
64 }
65
66 pub fn new_nested(body: Vec<Link>) -> Self {
69 Link {
70 id: None,
71 values: vec![],
72 children: vec![],
73 is_indented_id: false,
74 nested: Some(body),
75 }
76 }
77
78 pub fn with_children(mut self, children: Vec<Link>) -> Self {
79 self.children = children;
80 self
81 }
82}
83
84pub const DEFAULT_MAX_DEPTH: usize = 64;
93
94pub struct ParserState {
95 indentation_stack: RefCell<Vec<usize>>,
96 base_indentation: RefCell<Option<usize>>,
97 nested_depth: RefCell<usize>,
98 context_depth: RefCell<usize>,
101 max_depth: usize,
102 too_deep: RefCell<Option<usize>>,
105 furthest: RefCell<FurthestFailure>,
106 unreadable_lines: RefCell<HashMap<LineKey, LineFailure>>,
107 references: OnceCell<DelimitedReferences>,
109}
110
111type LineKey = (usize, bool);
116
117type LineFailure = (usize, nom::error::ErrorKind);
120
121#[derive(Debug, Clone, Default)]
131struct FurthestFailure {
132 address: Option<usize>,
135 expected: Vec<&'static str>,
136}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
140pub struct ParseFailure {
141 pub offset: usize,
143 pub expected: Vec<&'static str>,
147 pub kind: Option<nom::error::ErrorKind>,
151 pub max_depth_exceeded: Option<usize>,
154}
155
156pub struct SavedContext {
158 indentation_stack: Vec<usize>,
159 base_indentation: Option<usize>,
160 context_depth: usize,
161}
162
163impl Default for ParserState {
164 fn default() -> Self {
165 Self::new()
166 }
167}
168
169impl ParserState {
170 pub fn new() -> Self {
171 Self::with_max_depth(DEFAULT_MAX_DEPTH)
172 }
173
174 pub fn with_max_depth(max_depth: usize) -> Self {
176 ParserState {
177 indentation_stack: RefCell::new(vec![0]),
178 base_indentation: RefCell::new(None),
179 nested_depth: RefCell::new(0),
180 context_depth: RefCell::new(0),
181 max_depth,
182 too_deep: RefCell::new(None),
183 furthest: RefCell::new(FurthestFailure::default()),
184 unreadable_lines: RefCell::new(HashMap::new()),
185 references: OnceCell::new(),
186 }
187 }
188
189 pub fn set_base_indentation(&self, indent: usize) {
190 let mut base = self.base_indentation.borrow_mut();
191 if base.is_none() {
192 *base = Some(indent);
193 }
194 }
195
196 pub fn get_base_indentation(&self) -> usize {
197 self.base_indentation.borrow().unwrap_or(0)
198 }
199
200 pub fn normalize_indentation(&self, indent: usize) -> usize {
201 let base = self.get_base_indentation();
202 indent.saturating_sub(base)
203 }
204
205 pub fn push_indentation(&self, indent: usize) {
206 self.indentation_stack.borrow_mut().push(indent);
207 }
208
209 pub fn pop_indentation(&self) {
210 let mut stack = self.indentation_stack.borrow_mut();
211 if stack.len() > 1 {
212 stack.pop();
213 }
214 }
215
216 pub fn current_indentation(&self) -> usize {
217 *self.indentation_stack.borrow().last().unwrap_or(&0)
218 }
219
220 pub fn check_indentation(&self, indent: usize) -> bool {
221 indent >= self.current_indentation()
222 }
223
224 pub fn enter_nested_context(&self) -> SavedContext {
227 let depth = self.depth() + 1;
228 let saved = SavedContext {
229 indentation_stack: self.indentation_stack.replace(vec![0]),
230 base_indentation: self.base_indentation.replace(None),
231 context_depth: self.context_depth.replace(depth),
232 };
233 *self.nested_depth.borrow_mut() += 1;
234 saved
235 }
236
237 pub fn exit_nested_context(&self, saved: SavedContext) {
239 *self.indentation_stack.borrow_mut() = saved.indentation_stack;
240 *self.base_indentation.borrow_mut() = saved.base_indentation;
241 *self.context_depth.borrow_mut() = saved.context_depth;
242 let mut depth = self.nested_depth.borrow_mut();
243 if *depth > 0 {
244 *depth -= 1;
245 }
246 }
247
248 pub fn is_inside_nested_context(&self) -> bool {
249 *self.nested_depth.borrow() > 0
250 }
251
252 pub fn depth(&self) -> usize {
255 *self.context_depth.borrow() + self.indentation_stack.borrow().len() - 1
256 }
257
258 fn check_depth<'a>(&self, at: &'a str, depth: usize) -> IResult<&'a str, ()> {
262 if depth <= self.max_depth {
263 return Ok((at, ()));
264 }
265 self.too_deep
266 .borrow_mut()
267 .get_or_insert(at.as_ptr() as usize);
268 Err(nom::Err::Failure(nom::error::Error::new(
269 at,
270 nom::error::ErrorKind::TooLarge,
271 )))
272 }
273
274 fn expected_at(&self, at: &str, what: &'static str) {
278 let address = at.as_ptr() as usize;
279 let mut furthest = self.furthest.borrow_mut();
280 match furthest.address {
281 Some(recorded) if recorded > address => {}
282 Some(recorded) if recorded == address => {
283 if !furthest.expected.contains(&what) {
284 furthest.expected.push(what);
285 }
286 }
287 _ => {
288 furthest.address = Some(address);
289 furthest.expected = vec![what];
290 }
291 }
292 }
293
294 fn failure(&self, document: &str, error: &nom::Err<nom::error::Error<&str>>) -> ParseFailure {
300 let base = document.as_ptr() as usize;
301 let (nom_offset, kind) = match error {
302 nom::Err::Error(e) | nom::Err::Failure(e) => (
303 (e.input.as_ptr() as usize).saturating_sub(base),
304 Some(e.code),
305 ),
306 nom::Err::Incomplete(_) => (document.len(), None),
307 };
308 if let Some(address) = *self.too_deep.borrow() {
309 return ParseFailure {
310 offset: address.saturating_sub(base).min(document.len()),
311 expected: Vec::new(),
312 kind,
313 max_depth_exceeded: Some(self.max_depth),
314 };
315 }
316 let furthest = self.furthest.borrow();
317 let tracked = furthest
318 .address
319 .map(|address| address.saturating_sub(base))
320 .unwrap_or(0);
321 let offset = tracked.max(nom_offset).min(document.len());
322 let expected = if tracked == offset {
323 furthest.expected.clone()
324 } else {
325 Vec::new()
328 };
329 ParseFailure {
330 offset,
331 expected,
332 kind,
333 max_depth_exceeded: None,
334 }
335 }
336}
337
338fn expected<'a, T>(
340 input: &'a str,
341 state: &ParserState,
342 what: &'static str,
343 kind: nom::error::ErrorKind,
344) -> IResult<&'a str, T> {
345 state.expected_at(input, what);
346 Err(nom::Err::Error(nom::error::Error::new(input, kind)))
347}
348
349pub(crate) fn is_whitespace_char(c: char) -> bool {
350 c == ' ' || c == '\t' || c == '\n' || c == '\r'
351}
352
353fn is_horizontal_whitespace(c: char) -> bool {
354 c == ' ' || c == '\t'
355}
356
357fn is_reference_char(c: char) -> bool {
358 !is_whitespace_char(c) && c != '(' && c != ':' && c != ')'
359}
360
361fn horizontal_whitespace(input: &str) -> IResult<&str, &str> {
362 take_while(is_horizontal_whitespace)(input)
363}
364
365fn whitespace(input: &str) -> IResult<&str, &str> {
366 take_while(is_whitespace_char)(input)
367}
368
369fn simple_reference(input: &str) -> IResult<&str, String> {
370 take_while1(is_reference_char)
371 .map(|s: &str| s.to_string())
372 .parse(input)
373}
374
375pub fn quoted_reference_end(document: &str, start: usize) -> Option<usize> {
382 let reading = read_reference(document.get(start..)?)?;
383 Some(start + reading.length)
384}
385
386fn delimited_reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
390 let references = state
391 .references
392 .get_or_init(|| DelimitedReferences::new(input));
393 match references.read(input) {
394 Some(Reading { value, length }) => Ok((&input[length..], value)),
395 None => Err(nom::Err::Error(nom::error::Error::new(
396 input,
397 nom::error::ErrorKind::Tag,
398 ))),
399 }
400}
401
402fn reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
403 if let Some(prefix) = crate::reference_literal::prefix_end(input) {
404 if let Some(closing) = input[prefix..].find('}') {
405 let length = prefix + closing + 1;
406 if let Ok(value) = crate::decode_reference_literal(&input[..length]) {
407 return Ok((&input[length..], value));
408 }
409 }
410 state.expected_at(input, "a valid version 1 reference literal");
411 return Err(nom::Err::Failure(nom::error::Error::new(
412 input,
413 nom::error::ErrorKind::Tag,
414 )));
415 }
416 let parsed = alt((|i| delimited_reference(i, state), simple_reference)).parse(input);
419 if parsed.is_err() {
420 state.expected_at(input, "a reference");
421 }
422 parsed
423}
424
425fn eol<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
426 let parsed = alt((
427 preceded(horizontal_whitespace, alt((line_ending, tag("\r")))),
428 preceded(horizontal_whitespace, eof),
429 |i| nested_group_end(i, state),
430 ))
431 .parse(input);
432 if parsed.is_err() {
433 state.expected_at(input, "end of line");
434 }
435 parsed
436}
437
438fn nested_group_end<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
441 if !state.is_inside_nested_context() {
442 return Err(nom::Err::Error(nom::error::Error::new(
443 input,
444 nom::error::ErrorKind::Verify,
445 )));
446 }
447 let (rest, _) = horizontal_whitespace(input)?;
448 if rest.starts_with(')') {
449 Ok((rest, ""))
450 } else {
451 expected(rest, state, "\")\"", nom::error::ErrorKind::Char)
452 }
453}
454
455fn skip_empty_lines(input: &str) -> &str {
458 let mut rest = input;
459 loop {
460 let line_start = rest.trim_start_matches(is_horizontal_whitespace);
461 match strip_line_ending(line_start) {
462 Some(next) => rest = next,
463 None => return rest,
464 }
465 }
466}
467
468fn strip_line_ending(input: &str) -> Option<&str> {
469 input
470 .strip_prefix("\r\n")
471 .or_else(|| input.strip_prefix('\n'))
472 .or_else(|| input.strip_prefix('\r'))
473}
474
475fn reference_or_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
476 alt((
477 |i| nested_group(i, state),
478 (|i| reference(i, state)).map(Link::new_singlet),
479 ))
480 .parse(input)
481}
482
483fn single_line_value_and_whitespace<'a>(
484 input: &'a str,
485 state: &ParserState,
486) -> IResult<&'a str, Link> {
487 preceded(horizontal_whitespace, |i| reference_or_link(i, state)).parse(input)
488}
489
490fn single_line_values<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
491 many1(|i| single_line_value_and_whitespace(i, state)).parse(input)
492}
493
494fn single_line_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
495 let (input, _) = horizontal_whitespace(input)?;
496 let (input, id) = reference(input, state)?;
497 let (input, _) = horizontal_whitespace(input)?;
498 let (input, _) = colon(input, state)?;
499 let (input, values) = single_line_values(input, state)?;
500 Ok((input, Link::new_link(Some(id), values)))
501}
502
503fn colon<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
505 character(':', input, state, "\":\"")
506}
507
508fn character<'a>(
510 wanted: char,
511 input: &'a str,
512 state: &ParserState,
513 what: &'static str,
514) -> IResult<&'a str, char> {
515 let parsed: IResult<&'a str, char> = char(wanted).parse(input);
516 match parsed {
517 Ok(parsed) => Ok(parsed),
518 Err(_) => expected(input, state, what, nom::error::ErrorKind::Char),
519 }
520}
521
522fn single_line_value_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
523 (|i| single_line_values(i, state))
524 .map(Link::new_value)
525 .parse(input)
526}
527
528fn indented_id_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
529 let (input, id) = reference(input, state)?;
530 let (input, _) = horizontal_whitespace(input)?;
531 let (input, _) = colon(input, state)?;
532 let (input, _) = eol(input, state)?;
533 Ok((input, Link::new_indented_id(id)))
534}
535
536fn nested_group<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
540 let (body_input, _) = character('(', input, state, "\"(\"")?;
541 state.check_depth(input, state.depth() + 1)?;
542 let saved = state.enter_nested_context();
543 let result = nested_group_body(body_input, state);
544 state.exit_nested_context(saved);
545 result
546}
547
548fn nested_group_body<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
549 match links(skip_empty_lines(input), state) {
550 Ok((rest, body)) => {
551 let (rest, _) = whitespace(rest)?;
552 let (rest, _) = closing_parenthesis(rest, state)?;
553 return Ok((rest, Link::new_nested(body)));
554 }
555 Err(failure @ nom::Err::Failure(_)) => return Err(failure),
556 Err(_) => {}
557 }
558 let (rest, _) = whitespace(input)?;
559 let (rest, _) = closing_parenthesis(rest, state)?;
560 Ok((rest, Link::new_nested(vec![])))
561}
562
563fn closing_parenthesis<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
565 character(')', input, state, "\")\"")
566}
567
568fn single_line_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
569 alt((
570 terminated(|i| single_line_link(i, state), |i| eol(i, state)),
571 terminated(|i| single_line_value_link(i, state), |i| eol(i, state)),
572 ))
573 .parse(input)
574}
575
576fn any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
583 let key = (input.as_ptr() as usize, state.is_inside_nested_context());
584 if let Some(&(offset, kind)) = state.unreadable_lines.borrow().get(&key) {
585 return Err(nom::Err::Error(nom::error::Error::new(
586 &input[offset..],
587 kind,
588 )));
589 }
590 let parsed = read_any_link(input, state);
591 if let Err(nom::Err::Error(error)) = &parsed {
592 let offset = error.input.as_ptr() as usize - input.as_ptr() as usize;
593 state
594 .unreadable_lines
595 .borrow_mut()
596 .insert(key, (offset, error.code));
597 }
598 parsed
599}
600
601fn read_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
609 let (rest, group) = match nested_group(input, state) {
610 Ok(parsed) => parsed,
611 Err(_) if input.starts_with('(') => {
616 return reference(input, state).map(|(rest, id)| (rest, Link::new_singlet(id)))
617 }
618 Err(_) => {
619 return alt((
620 |i| indented_id_link(i, state),
621 |i| single_line_any_link(i, state),
622 ))
623 .parse(input)
624 }
625 };
626 if let Ok((rest, _)) = eol(rest, state) {
627 return Ok((rest, group));
628 }
629 let (rest, more) = many0(|i| single_line_value_and_whitespace(i, state)).parse(rest)?;
630 let (rest, _) = eol(rest, state)?;
631 let mut values = Vec::with_capacity(more.len() + 1);
632 values.push(group);
633 values.extend(more);
634 Ok((rest, Link::new_value(values)))
635}
636
637fn count_indentation(input: &str) -> IResult<&str, usize> {
638 take_while(|c| c == ' ').map(|s: &str| s.len()).parse(input)
639}
640
641fn push_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
642 let (input, spaces) = count_indentation(skip_empty_lines(input))?;
643 let normalized_spaces = state.normalize_indentation(spaces);
644 let current = state.current_indentation();
645
646 if normalized_spaces > current {
647 state.push_indentation(normalized_spaces);
648 Ok((input, ()))
649 } else {
650 Err(nom::Err::Error(nom::error::Error::new(
651 input,
652 nom::error::ErrorKind::Verify,
653 )))
654 }
655}
656
657fn check_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
658 let (input, spaces) = count_indentation(input)?;
659 let normalized_spaces = state.normalize_indentation(spaces);
660
661 if state.check_indentation(normalized_spaces) {
662 Ok((input, ()))
663 } else {
664 Err(nom::Err::Error(nom::error::Error::new(
665 input,
666 nom::error::ErrorKind::Verify,
667 )))
668 }
669}
670
671fn element<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
672 let start = input;
673 let (input, link) = any_link(input, state)?;
674 state.check_depth(start, state.depth())?;
677
678 let indentation = state.indentation_stack.borrow().clone();
679 if let Ok((child_input, _)) = push_indentation(input, state) {
680 match links(child_input, state) {
681 Ok((rest, children)) => return Ok((rest, link.with_children(children))),
682 Err(failure @ nom::Err::Failure(_)) => return Err(failure),
683 Err(_) => {}
684 }
685 state.indentation_stack.replace(indentation);
688 }
689 Ok((input, link))
690}
691
692fn first_line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
693 let (input, spaces) = count_indentation(input)?;
696 state.set_base_indentation(spaces);
697 element(input, state)
698}
699
700fn line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
701 preceded(|i| check_indentation(i, state), |i| element(i, state)).parse(skip_empty_lines(input))
703}
704
705fn links<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
706 let (input, first) = first_line(input, state)?;
707 let (input, rest) = many0(|i| line(i, state)).parse(input)?;
708
709 state.pop_indentation();
710
711 let mut result = vec![first];
712 result.extend(rest);
713 Ok((input, result))
714}
715
716pub fn parse_document(input: &str) -> IResult<&str, Vec<Link>> {
717 let state = ParserState::new();
718 document(input, &state)
719}
720
721pub fn parse_document_with_diagnostics(input: &str) -> Result<Vec<Link>, ParseFailure> {
728 parse_document_with_max_depth(input, DEFAULT_MAX_DEPTH)
729}
730
731pub fn parse_document_with_max_depth(
735 input: &str,
736 max_depth: usize,
737) -> Result<Vec<Link>, ParseFailure> {
738 let state = ParserState::with_max_depth(max_depth);
739 match document(input, &state) {
740 Ok((_, links)) => Ok(links),
741 Err(error) => Err(state.failure(input, &error)),
742 }
743}
744
745fn document<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
746 state
749 .references
750 .get_or_init(|| DelimitedReferences::new(input));
751
752 let document = skip_empty_lines(input);
754
755 if document.trim_matches(is_whitespace_char).is_empty() {
757 return Ok(("", vec![]));
758 }
759
760 let (rest, result) = links(document, state)?;
761 let (rest, _) = whitespace(rest)?;
762 let end: IResult<&'a str, &'a str> = eof(rest);
763 let (rest, _) = match end {
764 Ok(parsed) => parsed,
765 Err(_) => return expected(rest, state, "end of input", nom::error::ErrorKind::Eof),
766 };
767
768 Ok((rest, result))
769}