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    // Try quoted strings with dynamic quote detection (supports any N quotes)
404    // Then fall back to simple unquoted reference
405    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
425/// Inside a parenthesized group the closing parenthesis ends the last line,
426/// just like a line break does at the root.
427fn 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
442/// Skips the line breaks and blank lines that separate `(` from the first line
443/// of the group body.
444fn 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
490/// The colon that separates an identifier from its values.
491fn colon<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
492    character(':', input, state, "\":\"")
493}
494
495/// Matches one character, recording what was expected when it is not there.
496fn 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
523/// A parenthesized group opens a nested context: its body starts fresh at
524/// indentation level zero and is parsed with the same rules as the root
525/// document, so indentation is structural inside parentheses as well.
526fn 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
550/// The parenthesis that closes a group.
551fn 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
563/// Reads one line, or fails at once when the line was already found unreadable.
564///
565/// A line that does not parse as the first child of the line above it is tried
566/// again as a sibling at every enclosing indentation level. When the line holds
567/// a group, each of those attempts reads the whole group again, so without this
568/// the work doubles with every indented level (issue #314).
569fn 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
588/// A line that starts with a parenthesized group reads that group once and then
589/// branches on what follows it: the end of the line makes the group the whole
590/// link, and more values make it the first value of a value link.
591///
592/// Every other alternative would have to read the group again, which doubles
593/// the work at each level of nesting and makes a few dozen bytes take seconds
594/// ([#314](https://github.com/link-foundation/links-notation/issues/314)).
595fn 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        // Neither an indented ID nor a single-line link can start with a
599        // parenthesis, and a value link would begin with this same group, so
600        // nothing else can read a line that opens one. Report it the way the
601        // single-line value link does, as a missing reference.
602        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    // Only a line that parsed counts, so trailing spaces indented past the limit
662    // are still read as the whitespace they are.
663    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        // No child line followed the indentation. Backtrack to the link so
673        // the document can consume the remaining spaces as whitespace.
674        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    // Set base indentation from the first line and consume it, so that the first
681    // line is parsed exactly like every following line.
682    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    // Blank lines do not break a document, they are simply skipped
689    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
708/// Parses a document and, when it does not parse, says where it stopped.
709///
710/// `parse_document` reports a failure the way `nom` does: with the whole
711/// unconsumed remainder of the input and the combinator that gave up. Neither
712/// tells a reader which line to look at, and the remainder grows with the size
713/// of the document. This is the entry point the library uses.
714pub fn parse_document_with_diagnostics(input: &str) -> Result<Vec<Link>, ParseFailure> {
715    parse_document_with_max_depth(input, DEFAULT_MAX_DEPTH)
716}
717
718/// Parses a document the way [`parse_document_with_diagnostics`] does, refusing
719/// links nested deeper than `max_depth`. Every parenthesized group and every
720/// indentation level is one level of nesting.
721pub 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    // Every reference is read from a part of this document, so the runs of
734    // delimiters are listed from all of it.
735    state
736        .references
737        .get_or_init(|| DelimitedReferences::new(input));
738
739    // Skip leading blank lines but preserve the line structure
740    let document = skip_empty_lines(input);
741
742    // Handle empty or whitespace-only documents
743    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}