Skip to main content

links_notation/
parser.rs

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    /// Body of a parenthesized group, kept unflattened until the whole document
21    /// is transformed. `None` for every link that is not a parenthesized group.
22    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    /// Creates a link that stands for a parenthesized group, keeping the links
67    /// parsed inside the parentheses as they were written.
68    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
84/// How deep links may nest when nothing says otherwise.
85///
86/// Every level of nesting is a level of recursion, so the limit is what keeps a
87/// deeply nested document from overflowing the stack, which aborts the process
88/// instead of returning an error. It is set well below what fits: in a debug
89/// build a group written where a value goes, as in `(a (a (a b)))`, costs about
90/// 24 KB of stack a level, so a spawned thread's 2 MiB holds only 86 of them.
91/// The same limit applies in every Links Notation implementation.
92pub 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    /// Nesting depth of the level-zero lines of the current context: the number
99    /// of groups and indentation levels that enclose it.
100    context_depth: RefCell<usize>,
101    max_depth: usize,
102    /// Where the document first nested deeper than `max_depth`, as an address
103    /// into the document being parsed.
104    too_deep: RefCell<Option<usize>>,
105    furthest: RefCell<FurthestFailure>,
106    unreadable_lines: RefCell<HashMap<LineKey, LineFailure>>,
107    /// The delimited references of the document being parsed.
108    references: OnceCell<DelimitedReferences>,
109}
110
111/// Where a line starts, as an address into the document, and whether it is
112/// inside a parenthesized group. Reading a line depends on nothing else: a group
113/// starts a fresh indentation context, and indentation only decides which lines
114/// become children, so a line that could not be read once never can be.
115type LineKey = (usize, bool);
116
117/// How far past the start of an unreadable line the parser failed, and the
118/// `nom` error kind it failed with.
119type LineFailure = (usize, nom::error::ErrorKind);
120
121/// The furthest position any alternative reached before failing, and what could
122/// have continued the document there.
123///
124/// The parser backtracks, so the position the last alternative happens to fail
125/// at says little about where the document stops making sense: a defect in the
126/// middle of line two is reported by `nom` as "expected end of input" at the
127/// start of line two, because that is where the document last parsed cleanly.
128/// The furthest position reached is what a PEG parser points at, and it is what
129/// the JavaScript port reports.
130#[derive(Debug, Clone, Default)]
131struct FurthestFailure {
132    /// Address of the furthest failing position, as a pointer into the document
133    /// being parsed. Turned into an offset once the document is at hand again.
134    address: Option<usize>,
135    expected: Vec<&'static str>,
136}
137
138/// Where the parser stopped, and what it could have accepted there.
139#[derive(Debug, Clone, PartialEq, Eq)]
140pub struct ParseFailure {
141    /// Byte offset into the document the parser stopped at.
142    pub offset: usize,
143    /// What could have continued the document at `offset`, in the wording used
144    /// by the error message. Empty when the failure came from a place that
145    /// names no expectation.
146    pub expected: Vec<&'static str>,
147    /// The `nom` error kind. An internal detail of this parser: it says which
148    /// combinator gave up, not what is wrong with the document, so it is kept
149    /// out of the error message and reachable only through `Debug`.
150    pub kind: Option<nom::error::ErrorKind>,
151    /// The maximum nesting depth when the document nests deeper than it, which
152    /// `offset` then points at; `None` for every other failure.
153    pub max_depth_exceeded: Option<usize>,
154}
155
156/// Indentation state of the context a parenthesized group was opened in.
157pub 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    /// A parser state that refuses links nested deeper than `max_depth`.
175    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    /// Opens a nested context: the group body starts fresh at indentation level
225    /// zero and follows the same rules as the root document.
226    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    /// Restores the context the parenthesized group was opened in.
238    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    /// Nesting depth of the line being parsed: every enclosing parenthesized
253    /// group and every indentation level counts as one.
254    pub fn depth(&self) -> usize {
255        *self.context_depth.borrow() + self.indentation_stack.borrow().len() - 1
256    }
257
258    /// Fails for good when `depth` is deeper than the parser allows, so that
259    /// no alternative goes on to recurse any further. `at` is where the level
260    /// that is one too deep opens.
261    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    /// Records that `what` could have continued the document at `at`, and that
275    /// nothing there did. Only the furthest such position is kept; every
276    /// expectation recorded at that same position is kept alongside it.
277    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    /// Turns everything recorded during a failed parse into a position in
295    /// `document`.
296    ///
297    /// `nom`'s own error position is the fallback and the floor: the parser
298    /// reached at least that far, whatever the tracked alternatives say.
299    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            // The tracked expectations belong to an earlier position, so they
326            // do not describe the place being reported.
327            Vec::new()
328        };
329        ParseFailure {
330            offset,
331            expected,
332            kind,
333            max_depth_exceeded: None,
334        }
335    }
336}
337
338/// Fails the way `nom` does, after recording what was expected at `input`.
339fn 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
375/// The offset just past the delimited reference that starts at `start`, or
376/// `None` when nothing that far into `document` opens one.
377///
378/// Comment stripping needs to know how far a delimited reference reaches so
379/// that a `#` written inside one stays content, and it has to agree with the
380/// parser about it, which is why both read references the same way.
381pub 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
386/// A delimited reference with any number of delimiters. A run of an even
387/// number of delimiters that does not open a reference with a substantive body
388/// is the empty reference.
389fn 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    // Try quoted strings with dynamic quote detection (supports any N quotes)
417    // Then fall back to simple unquoted reference
418    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
438/// Inside a parenthesized group the closing parenthesis ends the last line,
439/// just like a line break does at the root.
440fn 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
455/// Skips the line breaks and blank lines that separate `(` from the first line
456/// of the group body.
457fn 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
503/// The colon that separates an identifier from its values.
504fn colon<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
505    character(':', input, state, "\":\"")
506}
507
508/// Matches one character, recording what was expected when it is not there.
509fn 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
536/// A parenthesized group opens a nested context: its body starts fresh at
537/// indentation level zero and is parsed with the same rules as the root
538/// document, so indentation is structural inside parentheses as well.
539fn 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
563/// The parenthesis that closes a group.
564fn 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
576/// Reads one line, or fails at once when the line was already found unreadable.
577///
578/// A line that does not parse as the first child of the line above it is tried
579/// again as a sibling at every enclosing indentation level. When the line holds
580/// a group, each of those attempts reads the whole group again, so without this
581/// the work doubles with every indented level (issue #314).
582fn 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
601/// A line that starts with a parenthesized group reads that group once and then
602/// branches on what follows it: the end of the line makes the group the whole
603/// link, and more values make it the first value of a value link.
604///
605/// Every other alternative would have to read the group again, which doubles
606/// the work at each level of nesting and makes a few dozen bytes take seconds
607/// ([#314](https://github.com/link-foundation/links-notation/issues/314)).
608fn 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        // Neither an indented ID nor a single-line link can start with a
612        // parenthesis, and a value link would begin with this same group, so
613        // nothing else can read a line that opens one. Report it the way the
614        // single-line value link does, as a missing reference.
615        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    // Only a line that parsed counts, so trailing spaces indented past the limit
675    // are still read as the whitespace they are.
676    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        // No child line followed the indentation. Backtrack to the link so
686        // the document can consume the remaining spaces as whitespace.
687        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    // Set base indentation from the first line and consume it, so that the first
694    // line is parsed exactly like every following line.
695    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    // Blank lines do not break a document, they are simply skipped
702    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
721/// Parses a document and, when it does not parse, says where it stopped.
722///
723/// `parse_document` reports a failure the way `nom` does: with the whole
724/// unconsumed remainder of the input and the combinator that gave up. Neither
725/// tells a reader which line to look at, and the remainder grows with the size
726/// of the document. This is the entry point the library uses.
727pub fn parse_document_with_diagnostics(input: &str) -> Result<Vec<Link>, ParseFailure> {
728    parse_document_with_max_depth(input, DEFAULT_MAX_DEPTH)
729}
730
731/// Parses a document the way [`parse_document_with_diagnostics`] does, refusing
732/// links nested deeper than `max_depth`. Every parenthesized group and every
733/// indentation level is one level of nesting.
734pub 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    // Every reference is read from a part of this document, so the runs of
747    // delimiters are listed from all of it.
748    state
749        .references
750        .get_or_init(|| DelimitedReferences::new(input));
751
752    // Skip leading blank lines but preserve the line structure
753    let document = skip_empty_lines(input);
754
755    // Handle empty or whitespace-only documents
756    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}