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 let parsed = alt((|i| delimited_reference(i, state), simple_reference)).parse(input);
406 if parsed.is_err() {
407 state.expected_at(input, "a reference");
408 }
409 parsed
410}
411
412fn eol<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
413 let parsed = alt((
414 preceded(horizontal_whitespace, alt((line_ending, tag("\r")))),
415 preceded(horizontal_whitespace, eof),
416 |i| nested_group_end(i, state),
417 ))
418 .parse(input);
419 if parsed.is_err() {
420 state.expected_at(input, "end of line");
421 }
422 parsed
423}
424
425fn nested_group_end<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
428 if !state.is_inside_nested_context() {
429 return Err(nom::Err::Error(nom::error::Error::new(
430 input,
431 nom::error::ErrorKind::Verify,
432 )));
433 }
434 let (rest, _) = horizontal_whitespace(input)?;
435 if rest.starts_with(')') {
436 Ok((rest, ""))
437 } else {
438 expected(rest, state, "\")\"", nom::error::ErrorKind::Char)
439 }
440}
441
442fn skip_empty_lines(input: &str) -> &str {
445 let mut rest = input;
446 loop {
447 let line_start = rest.trim_start_matches(is_horizontal_whitespace);
448 match strip_line_ending(line_start) {
449 Some(next) => rest = next,
450 None => return rest,
451 }
452 }
453}
454
455fn strip_line_ending(input: &str) -> Option<&str> {
456 input
457 .strip_prefix("\r\n")
458 .or_else(|| input.strip_prefix('\n'))
459 .or_else(|| input.strip_prefix('\r'))
460}
461
462fn reference_or_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
463 alt((
464 |i| nested_group(i, state),
465 (|i| reference(i, state)).map(Link::new_singlet),
466 ))
467 .parse(input)
468}
469
470fn single_line_value_and_whitespace<'a>(
471 input: &'a str,
472 state: &ParserState,
473) -> IResult<&'a str, Link> {
474 preceded(horizontal_whitespace, |i| reference_or_link(i, state)).parse(input)
475}
476
477fn single_line_values<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
478 many1(|i| single_line_value_and_whitespace(i, state)).parse(input)
479}
480
481fn single_line_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
482 let (input, _) = horizontal_whitespace(input)?;
483 let (input, id) = reference(input, state)?;
484 let (input, _) = horizontal_whitespace(input)?;
485 let (input, _) = colon(input, state)?;
486 let (input, values) = single_line_values(input, state)?;
487 Ok((input, Link::new_link(Some(id), values)))
488}
489
490fn colon<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
492 character(':', input, state, "\":\"")
493}
494
495fn character<'a>(
497 wanted: char,
498 input: &'a str,
499 state: &ParserState,
500 what: &'static str,
501) -> IResult<&'a str, char> {
502 let parsed: IResult<&'a str, char> = char(wanted).parse(input);
503 match parsed {
504 Ok(parsed) => Ok(parsed),
505 Err(_) => expected(input, state, what, nom::error::ErrorKind::Char),
506 }
507}
508
509fn single_line_value_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
510 (|i| single_line_values(i, state))
511 .map(Link::new_value)
512 .parse(input)
513}
514
515fn indented_id_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
516 let (input, id) = reference(input, state)?;
517 let (input, _) = horizontal_whitespace(input)?;
518 let (input, _) = colon(input, state)?;
519 let (input, _) = eol(input, state)?;
520 Ok((input, Link::new_indented_id(id)))
521}
522
523fn nested_group<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
527 let (body_input, _) = character('(', input, state, "\"(\"")?;
528 state.check_depth(input, state.depth() + 1)?;
529 let saved = state.enter_nested_context();
530 let result = nested_group_body(body_input, state);
531 state.exit_nested_context(saved);
532 result
533}
534
535fn nested_group_body<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
536 match links(skip_empty_lines(input), state) {
537 Ok((rest, body)) => {
538 let (rest, _) = whitespace(rest)?;
539 let (rest, _) = closing_parenthesis(rest, state)?;
540 return Ok((rest, Link::new_nested(body)));
541 }
542 Err(failure @ nom::Err::Failure(_)) => return Err(failure),
543 Err(_) => {}
544 }
545 let (rest, _) = whitespace(input)?;
546 let (rest, _) = closing_parenthesis(rest, state)?;
547 Ok((rest, Link::new_nested(vec![])))
548}
549
550fn closing_parenthesis<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
552 character(')', input, state, "\")\"")
553}
554
555fn single_line_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
556 alt((
557 terminated(|i| single_line_link(i, state), |i| eol(i, state)),
558 terminated(|i| single_line_value_link(i, state), |i| eol(i, state)),
559 ))
560 .parse(input)
561}
562
563fn any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
570 let key = (input.as_ptr() as usize, state.is_inside_nested_context());
571 if let Some(&(offset, kind)) = state.unreadable_lines.borrow().get(&key) {
572 return Err(nom::Err::Error(nom::error::Error::new(
573 &input[offset..],
574 kind,
575 )));
576 }
577 let parsed = read_any_link(input, state);
578 if let Err(nom::Err::Error(error)) = &parsed {
579 let offset = error.input.as_ptr() as usize - input.as_ptr() as usize;
580 state
581 .unreadable_lines
582 .borrow_mut()
583 .insert(key, (offset, error.code));
584 }
585 parsed
586}
587
588fn read_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
596 let (rest, group) = match nested_group(input, state) {
597 Ok(parsed) => parsed,
598 Err(_) if input.starts_with('(') => {
603 return reference(input, state).map(|(rest, id)| (rest, Link::new_singlet(id)))
604 }
605 Err(_) => {
606 return alt((
607 |i| indented_id_link(i, state),
608 |i| single_line_any_link(i, state),
609 ))
610 .parse(input)
611 }
612 };
613 if let Ok((rest, _)) = eol(rest, state) {
614 return Ok((rest, group));
615 }
616 let (rest, more) = many0(|i| single_line_value_and_whitespace(i, state)).parse(rest)?;
617 let (rest, _) = eol(rest, state)?;
618 let mut values = Vec::with_capacity(more.len() + 1);
619 values.push(group);
620 values.extend(more);
621 Ok((rest, Link::new_value(values)))
622}
623
624fn count_indentation(input: &str) -> IResult<&str, usize> {
625 take_while(|c| c == ' ').map(|s: &str| s.len()).parse(input)
626}
627
628fn push_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
629 let (input, spaces) = count_indentation(skip_empty_lines(input))?;
630 let normalized_spaces = state.normalize_indentation(spaces);
631 let current = state.current_indentation();
632
633 if normalized_spaces > current {
634 state.push_indentation(normalized_spaces);
635 Ok((input, ()))
636 } else {
637 Err(nom::Err::Error(nom::error::Error::new(
638 input,
639 nom::error::ErrorKind::Verify,
640 )))
641 }
642}
643
644fn check_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
645 let (input, spaces) = count_indentation(input)?;
646 let normalized_spaces = state.normalize_indentation(spaces);
647
648 if state.check_indentation(normalized_spaces) {
649 Ok((input, ()))
650 } else {
651 Err(nom::Err::Error(nom::error::Error::new(
652 input,
653 nom::error::ErrorKind::Verify,
654 )))
655 }
656}
657
658fn element<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
659 let start = input;
660 let (input, link) = any_link(input, state)?;
661 state.check_depth(start, state.depth())?;
664
665 let indentation = state.indentation_stack.borrow().clone();
666 if let Ok((child_input, _)) = push_indentation(input, state) {
667 match links(child_input, state) {
668 Ok((rest, children)) => return Ok((rest, link.with_children(children))),
669 Err(failure @ nom::Err::Failure(_)) => return Err(failure),
670 Err(_) => {}
671 }
672 state.indentation_stack.replace(indentation);
675 }
676 Ok((input, link))
677}
678
679fn first_line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
680 let (input, spaces) = count_indentation(input)?;
683 state.set_base_indentation(spaces);
684 element(input, state)
685}
686
687fn line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
688 preceded(|i| check_indentation(i, state), |i| element(i, state)).parse(skip_empty_lines(input))
690}
691
692fn links<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
693 let (input, first) = first_line(input, state)?;
694 let (input, rest) = many0(|i| line(i, state)).parse(input)?;
695
696 state.pop_indentation();
697
698 let mut result = vec![first];
699 result.extend(rest);
700 Ok((input, result))
701}
702
703pub fn parse_document(input: &str) -> IResult<&str, Vec<Link>> {
704 let state = ParserState::new();
705 document(input, &state)
706}
707
708pub fn parse_document_with_diagnostics(input: &str) -> Result<Vec<Link>, ParseFailure> {
715 parse_document_with_max_depth(input, DEFAULT_MAX_DEPTH)
716}
717
718pub fn parse_document_with_max_depth(
722 input: &str,
723 max_depth: usize,
724) -> Result<Vec<Link>, ParseFailure> {
725 let state = ParserState::with_max_depth(max_depth);
726 match document(input, &state) {
727 Ok((_, links)) => Ok(links),
728 Err(error) => Err(state.failure(input, &error)),
729 }
730}
731
732fn document<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
733 state
736 .references
737 .get_or_init(|| DelimitedReferences::new(input));
738
739 let document = skip_empty_lines(input);
741
742 if document.trim_matches(is_whitespace_char).is_empty() {
744 return Ok(("", vec![]));
745 }
746
747 let (rest, result) = links(document, state)?;
748 let (rest, _) = whitespace(rest)?;
749 let end: IResult<&'a str, &'a str> = eof(rest);
750 let (rest, _) = match end {
751 Ok(parsed) => parsed,
752 Err(_) => return expected(rest, state, "end of input", nom::error::ErrorKind::Eof),
753 };
754
755 Ok((rest, result))
756}