Skip to main content

links_notation/
parser.rs

1use crate::quotes::{DelimitedReferences, QUOTES, Reading, read_reference};
2use nom::{
3    IResult, Parser,
4    branch::alt,
5    bytes::complete::{tag, take_while, take_while1},
6    character::complete::{char, line_ending},
7    combinator::eof,
8    multi::{many0, many1},
9    sequence::{preceded, terminated},
10};
11use std::cell::{Cell, OnceCell, RefCell};
12use std::collections::HashMap;
13use std::ops::Range;
14
15#[derive(Debug, Clone, PartialEq)]
16pub struct Link {
17    pub id: Option<String>,
18    pub values: Vec<Link>,
19    pub children: Vec<Link>,
20    pub is_indented_id: bool,
21    /// Body of a parenthesized group, kept unflattened until the whole document
22    /// is transformed. `None` for every link that is not a parenthesized group.
23    pub nested: Option<Vec<Link>>,
24    /// Where the ID was written: the byte range of the reference, quotes,
25    /// escapes and literal syntax included, in the document that was parsed.
26    /// The parser reads a copy of the document with its comments blanked, which
27    /// keeps every byte where it was, so the range also locates the ID in the
28    /// document as the caller wrote it. `None` when the link has no ID.
29    pub id_span: Option<Range<usize>>,
30}
31
32impl Link {
33    pub fn new_singlet(id: String) -> Self {
34        Link {
35            id: Some(id),
36            values: vec![],
37            children: vec![],
38            is_indented_id: false,
39            nested: None,
40            id_span: None,
41        }
42    }
43
44    pub fn new_indented_id(id: String) -> Self {
45        Link {
46            id: Some(id),
47            values: vec![],
48            children: vec![],
49            is_indented_id: true,
50            nested: None,
51            id_span: None,
52        }
53    }
54
55    pub fn new_value(values: Vec<Link>) -> Self {
56        Link {
57            id: None,
58            values,
59            children: vec![],
60            is_indented_id: false,
61            nested: None,
62            id_span: None,
63        }
64    }
65
66    pub fn new_link(id: Option<String>, values: Vec<Link>) -> Self {
67        Link {
68            id,
69            values,
70            children: vec![],
71            is_indented_id: false,
72            nested: None,
73            id_span: None,
74        }
75    }
76
77    /// Creates a link that stands for a parenthesized group, keeping the links
78    /// parsed inside the parentheses as they were written.
79    pub fn new_nested(body: Vec<Link>) -> Self {
80        Link {
81            id: None,
82            values: vec![],
83            children: vec![],
84            is_indented_id: false,
85            nested: Some(body),
86            id_span: None,
87        }
88    }
89
90    pub fn with_children(mut self, children: Vec<Link>) -> Self {
91        self.children = children;
92        self
93    }
94
95    /// The same link, recording where its ID was written.
96    pub fn with_id_span(mut self, span: Range<usize>) -> Self {
97        self.id_span = Some(span);
98        self
99    }
100}
101
102/// How deep links may nest when nothing says otherwise.
103///
104/// Every level of nesting is a level of recursion, so the limit is what keeps a
105/// deeply nested document from overflowing the stack, which aborts the process
106/// instead of returning an error. It is set well below what fits: in a debug
107/// build a group written where a value goes, as in `(a (a (a b)))`, costs about
108/// 24 KB of stack a level, so a spawned thread's 2 MiB holds only 86 of them.
109/// The same limit applies in every Links Notation implementation.
110pub const DEFAULT_MAX_DEPTH: usize = 64;
111
112pub struct ParserState {
113    indentation_stack: RefCell<Vec<usize>>,
114    base_indentation: RefCell<Option<usize>>,
115    nested_depth: RefCell<usize>,
116    /// Nesting depth of the level-zero lines of the current context: the number
117    /// of groups and indentation levels that enclose it.
118    context_depth: RefCell<usize>,
119    max_depth: usize,
120    /// Where the document first nested deeper than `max_depth`, as an address
121    /// into the document being parsed.
122    too_deep: RefCell<Option<usize>>,
123    furthest: RefCell<FurthestFailure>,
124    unreadable_lines: RefCell<HashMap<LineKey, LineFailure>>,
125    /// The delimited references of the document being parsed, listed from the
126    /// document as written.
127    references: OnceCell<DelimitedReferences>,
128    /// The document as written, when the one being parsed has its comments
129    /// blanked. Blanking keeps every byte where it was, and delimited
130    /// references are read here, so blanking a comment never changes what a
131    /// reference holds or how far it reaches (issue #377).
132    source: Option<Box<str>>,
133    /// Address of the first byte of the document being parsed, which turns the
134    /// part of the document a reference was read from into a byte range.
135    document_start: Cell<usize>,
136}
137
138/// Where a line starts, as an address into the document, and whether it is
139/// inside a parenthesized group. Reading a line depends on nothing else: a group
140/// starts a fresh indentation context, and indentation only decides which lines
141/// become children, so a line that could not be read once never can be.
142type LineKey = (usize, bool);
143
144/// How far past the start of an unreadable line the parser failed, and the
145/// `nom` error kind it failed with.
146type LineFailure = (usize, nom::error::ErrorKind);
147
148/// The furthest position any alternative reached before failing, and what could
149/// have continued the document there.
150///
151/// The parser backtracks, so the position the last alternative happens to fail
152/// at says little about where the document stops making sense: a defect in the
153/// middle of line two is reported by `nom` as "expected end of input" at the
154/// start of line two, because that is where the document last parsed cleanly.
155/// The furthest position reached is what a PEG parser points at, and it is what
156/// the JavaScript port reports.
157#[derive(Debug, Clone, Default)]
158struct FurthestFailure {
159    /// Address of the furthest failing position, as a pointer into the document
160    /// being parsed. Turned into an offset once the document is at hand again.
161    address: Option<usize>,
162    expected: Vec<&'static str>,
163}
164
165/// Where the parser stopped, and what it could have accepted there.
166#[derive(Debug, Clone, PartialEq, Eq)]
167pub struct ParseFailure {
168    /// Byte offset into the document the parser stopped at.
169    pub offset: usize,
170    /// What could have continued the document at `offset`, in the wording used
171    /// by the error message. Empty when the failure came from a place that
172    /// names no expectation.
173    pub expected: Vec<&'static str>,
174    /// The `nom` error kind. An internal detail of this parser: it says which
175    /// combinator gave up, not what is wrong with the document, so it is kept
176    /// out of the error message and reachable only through `Debug`.
177    pub kind: Option<nom::error::ErrorKind>,
178    /// The maximum nesting depth when the document nests deeper than it, which
179    /// `offset` then points at; `None` for every other failure.
180    pub max_depth_exceeded: Option<usize>,
181}
182
183/// Indentation state of the context a parenthesized group was opened in.
184pub struct SavedContext {
185    indentation_stack: Vec<usize>,
186    base_indentation: Option<usize>,
187    context_depth: usize,
188}
189
190impl Default for ParserState {
191    fn default() -> Self {
192        Self::new()
193    }
194}
195
196impl ParserState {
197    pub fn new() -> Self {
198        Self::with_max_depth(DEFAULT_MAX_DEPTH)
199    }
200
201    /// A parser state that refuses links nested deeper than `max_depth`.
202    pub fn with_max_depth(max_depth: usize) -> Self {
203        ParserState {
204            indentation_stack: RefCell::new(vec![0]),
205            base_indentation: RefCell::new(None),
206            nested_depth: RefCell::new(0),
207            context_depth: RefCell::new(0),
208            max_depth,
209            too_deep: RefCell::new(None),
210            furthest: RefCell::new(FurthestFailure::default()),
211            unreadable_lines: RefCell::new(HashMap::new()),
212            references: OnceCell::new(),
213            source: None,
214            document_start: Cell::new(0),
215        }
216    }
217
218    /// `input`, a part of the document being parsed that runs to its end, in
219    /// the document as written when it opens a delimited reference.
220    ///
221    /// A delimiter is never blanked, so where `input` opens with one the
222    /// document as written has the same delimiter at the same byte.
223    fn written<'s>(&'s self, input: &'s str) -> &'s str {
224        match &self.source {
225            Some(source) if input.as_bytes().first().is_some_and(|b| QUOTES.contains(b)) => source
226                .len()
227                .checked_sub(input.len())
228                .and_then(|start| source.get(start..))
229                .unwrap_or(input),
230            _ => input,
231        }
232    }
233
234    /// The delimited references of the document being parsed, listed from the
235    /// document as written; `input` is that document when it has no comments
236    /// blanked.
237    fn references(&self, input: &str) -> &DelimitedReferences {
238        self.references
239            .get_or_init(|| DelimitedReferences::new(self.source.as_deref().unwrap_or(input)))
240    }
241
242    pub fn set_base_indentation(&self, indent: usize) {
243        let mut base = self.base_indentation.borrow_mut();
244        if base.is_none() {
245            *base = Some(indent);
246        }
247    }
248
249    pub fn get_base_indentation(&self) -> usize {
250        self.base_indentation.borrow().unwrap_or(0)
251    }
252
253    pub fn normalize_indentation(&self, indent: usize) -> usize {
254        let base = self.get_base_indentation();
255        indent.saturating_sub(base)
256    }
257
258    pub fn push_indentation(&self, indent: usize) {
259        self.indentation_stack.borrow_mut().push(indent);
260    }
261
262    pub fn pop_indentation(&self) {
263        let mut stack = self.indentation_stack.borrow_mut();
264        if stack.len() > 1 {
265            stack.pop();
266        }
267    }
268
269    pub fn current_indentation(&self) -> usize {
270        *self.indentation_stack.borrow().last().unwrap_or(&0)
271    }
272
273    pub fn check_indentation(&self, indent: usize) -> bool {
274        indent >= self.current_indentation()
275    }
276
277    /// Opens a nested context: the group body starts fresh at indentation level
278    /// zero and follows the same rules as the root document.
279    pub fn enter_nested_context(&self) -> SavedContext {
280        let depth = self.depth() + 1;
281        let saved = SavedContext {
282            indentation_stack: self.indentation_stack.replace(vec![0]),
283            base_indentation: self.base_indentation.replace(None),
284            context_depth: self.context_depth.replace(depth),
285        };
286        *self.nested_depth.borrow_mut() += 1;
287        saved
288    }
289
290    /// Restores the context the parenthesized group was opened in.
291    pub fn exit_nested_context(&self, saved: SavedContext) {
292        *self.indentation_stack.borrow_mut() = saved.indentation_stack;
293        *self.base_indentation.borrow_mut() = saved.base_indentation;
294        *self.context_depth.borrow_mut() = saved.context_depth;
295        let mut depth = self.nested_depth.borrow_mut();
296        if *depth > 0 {
297            *depth -= 1;
298        }
299    }
300
301    pub fn is_inside_nested_context(&self) -> bool {
302        *self.nested_depth.borrow() > 0
303    }
304
305    /// Nesting depth of the line being parsed: every enclosing parenthesized
306    /// group and every indentation level counts as one.
307    pub fn depth(&self) -> usize {
308        *self.context_depth.borrow() + self.indentation_stack.borrow().len() - 1
309    }
310
311    /// Fails for good when `depth` is deeper than the parser allows, so that
312    /// no alternative goes on to recurse any further. `at` is where the level
313    /// that is one too deep opens.
314    fn check_depth<'a>(&self, at: &'a str, depth: usize) -> IResult<&'a str, ()> {
315        if depth <= self.max_depth {
316            return Ok((at, ()));
317        }
318        self.too_deep
319            .borrow_mut()
320            .get_or_insert(at.as_ptr() as usize);
321        Err(nom::Err::Failure(nom::error::Error::new(
322            at,
323            nom::error::ErrorKind::TooLarge,
324        )))
325    }
326
327    /// Records that `what` could have continued the document at `at`, and that
328    /// nothing there did. Only the furthest such position is kept; every
329    /// expectation recorded at that same position is kept alongside it.
330    fn expected_at(&self, at: &str, what: &'static str) {
331        let address = at.as_ptr() as usize;
332        let mut furthest = self.furthest.borrow_mut();
333        match furthest.address {
334            Some(recorded) if recorded > address => {}
335            Some(recorded) if recorded == address => {
336                if !furthest.expected.contains(&what) {
337                    furthest.expected.push(what);
338                }
339            }
340            _ => {
341                furthest.address = Some(address);
342                furthest.expected = vec![what];
343            }
344        }
345    }
346
347    /// Turns everything recorded during a failed parse into a position in
348    /// `document`.
349    ///
350    /// `nom`'s own error position is the fallback and the floor: the parser
351    /// reached at least that far, whatever the tracked alternatives say.
352    fn failure(&self, document: &str, error: &nom::Err<nom::error::Error<&str>>) -> ParseFailure {
353        let base = document.as_ptr() as usize;
354        let (nom_offset, kind) = match error {
355            nom::Err::Error(e) | nom::Err::Failure(e) => (
356                (e.input.as_ptr() as usize).saturating_sub(base),
357                Some(e.code),
358            ),
359            nom::Err::Incomplete(_) => (document.len(), None),
360        };
361        if let Some(address) = *self.too_deep.borrow() {
362            return ParseFailure {
363                offset: address.saturating_sub(base).min(document.len()),
364                expected: Vec::new(),
365                kind,
366                max_depth_exceeded: Some(self.max_depth),
367            };
368        }
369        let furthest = self.furthest.borrow();
370        let tracked = furthest
371            .address
372            .map(|address| address.saturating_sub(base))
373            .unwrap_or(0);
374        let offset = tracked.max(nom_offset).min(document.len());
375        let expected = if tracked == offset {
376            furthest.expected.clone()
377        } else {
378            // The tracked expectations belong to an earlier position, so they
379            // do not describe the place being reported.
380            Vec::new()
381        };
382        ParseFailure {
383            offset,
384            expected,
385            kind,
386            max_depth_exceeded: None,
387        }
388    }
389}
390
391/// Fails the way `nom` does, after recording what was expected at `input`.
392fn expected<'a, T>(
393    input: &'a str,
394    state: &ParserState,
395    what: &'static str,
396    kind: nom::error::ErrorKind,
397) -> IResult<&'a str, T> {
398    state.expected_at(input, what);
399    Err(nom::Err::Error(nom::error::Error::new(input, kind)))
400}
401
402pub(crate) fn is_whitespace_char(c: char) -> bool {
403    c == ' ' || c == '\t' || c == '\n' || c == '\r'
404}
405
406fn is_horizontal_whitespace(c: char) -> bool {
407    c == ' ' || c == '\t'
408}
409
410fn is_reference_char(c: char) -> bool {
411    !is_whitespace_char(c) && c != '(' && c != ':' && c != ')'
412}
413
414fn horizontal_whitespace(input: &str) -> IResult<&str, &str> {
415    take_while(is_horizontal_whitespace)(input)
416}
417
418fn whitespace(input: &str) -> IResult<&str, &str> {
419    take_while(is_whitespace_char)(input)
420}
421
422fn simple_reference(input: &str) -> IResult<&str, String> {
423    take_while1(is_reference_char)
424        .map(|s: &str| s.to_string())
425        .parse(input)
426}
427
428/// The offset just past the delimited reference that starts at `start`, or
429/// `None` when nothing that far into `document` opens one.
430///
431/// Comment stripping needs to know how far a delimited reference reaches so
432/// that a `#` written inside one stays content, and it has to agree with the
433/// parser about it, which is why both read references the same way.
434pub fn quoted_reference_end(document: &str, start: usize) -> Option<usize> {
435    let reading = read_reference(document.get(start..)?)?;
436    Some(start + reading.length)
437}
438
439/// A delimited reference with any number of delimiters. A run of an even
440/// number of delimiters that does not open a reference with a substantive body
441/// is the empty reference.
442///
443/// The reference is read in the document as written: blanking a comment keeps
444/// every byte where it was, but may change what an even run encloses, and so
445/// whether it is the empty reference (issue #377).
446fn delimited_reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
447    match state.references(input).read(state.written(input)) {
448        Some(Reading { value, length, .. }) => Ok((&input[length..], value)),
449        None => Err(nom::Err::Error(nom::error::Error::new(
450            input,
451            nom::error::ErrorKind::Tag,
452        ))),
453    }
454}
455
456fn reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
457    if let Some(prefix) = crate::reference_literal::prefix_end(input) {
458        if let Some(closing) = input[prefix..].find('}') {
459            let length = prefix + closing + 1;
460            if let Ok(value) = crate::decode_reference_literal(&input[..length]) {
461                return Ok((&input[length..], value));
462            }
463        }
464        state.expected_at(input, "a valid version 1 reference literal");
465        return Err(nom::Err::Failure(nom::error::Error::new(
466            input,
467            nom::error::ErrorKind::Tag,
468        )));
469    }
470    // Try quoted strings with dynamic quote detection (supports any N quotes)
471    // Then fall back to simple unquoted reference
472    let parsed = alt((|i| delimited_reference(i, state), simple_reference)).parse(input);
473    if parsed.is_err() {
474        state.expected_at(input, "a reference");
475    }
476    parsed
477}
478
479/// A reference together with the byte range it was written at, so that a link
480/// can say how its ID was written.
481fn spanned_reference<'a>(
482    input: &'a str,
483    state: &ParserState,
484) -> IResult<&'a str, (String, Range<usize>)> {
485    let (rest, value) = reference(input, state)?;
486    let start = (input.as_ptr() as usize).saturating_sub(state.document_start.get());
487    let end = start + (input.len() - rest.len());
488    Ok((rest, (value, start..end)))
489}
490
491fn eol<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
492    let parsed = alt((
493        preceded(horizontal_whitespace, alt((line_ending, tag("\r")))),
494        preceded(horizontal_whitespace, eof),
495        |i| nested_group_end(i, state),
496    ))
497    .parse(input);
498    if parsed.is_err() {
499        state.expected_at(input, "end of line");
500    }
501    parsed
502}
503
504/// Inside a parenthesized group the closing parenthesis ends the last line,
505/// just like a line break does at the root.
506fn nested_group_end<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
507    if !state.is_inside_nested_context() {
508        return Err(nom::Err::Error(nom::error::Error::new(
509            input,
510            nom::error::ErrorKind::Verify,
511        )));
512    }
513    let (rest, _) = horizontal_whitespace(input)?;
514    if rest.starts_with(')') {
515        Ok((rest, ""))
516    } else {
517        expected(rest, state, "\")\"", nom::error::ErrorKind::Char)
518    }
519}
520
521/// Skips the line breaks and blank lines that separate `(` from the first line
522/// of the group body.
523fn skip_empty_lines(input: &str) -> &str {
524    let mut rest = input;
525    loop {
526        let line_start = rest.trim_start_matches(is_horizontal_whitespace);
527        match strip_line_ending(line_start) {
528            Some(next) => rest = next,
529            None => return rest,
530        }
531    }
532}
533
534fn strip_line_ending(input: &str) -> Option<&str> {
535    input
536        .strip_prefix("\r\n")
537        .or_else(|| input.strip_prefix('\n'))
538        .or_else(|| input.strip_prefix('\r'))
539}
540
541fn reference_or_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
542    alt((
543        |i| nested_group(i, state),
544        (|i| spanned_reference(i, state))
545            .map(|(id, span)| Link::new_singlet(id).with_id_span(span)),
546    ))
547    .parse(input)
548}
549
550fn single_line_value_and_whitespace<'a>(
551    input: &'a str,
552    state: &ParserState,
553) -> IResult<&'a str, Link> {
554    preceded(horizontal_whitespace, |i| reference_or_link(i, state)).parse(input)
555}
556
557fn single_line_values<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
558    many1(|i| single_line_value_and_whitespace(i, state)).parse(input)
559}
560
561fn single_line_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
562    let (input, _) = horizontal_whitespace(input)?;
563    let (input, (id, span)) = spanned_reference(input, state)?;
564    let (input, _) = horizontal_whitespace(input)?;
565    let (input, _) = colon(input, state)?;
566    let (input, values) = single_line_values(input, state)?;
567    Ok((input, Link::new_link(Some(id), values).with_id_span(span)))
568}
569
570/// The colon that separates an identifier from its values.
571fn colon<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
572    character(':', input, state, "\":\"")
573}
574
575/// Matches one character, recording what was expected when it is not there.
576fn character<'a>(
577    wanted: char,
578    input: &'a str,
579    state: &ParserState,
580    what: &'static str,
581) -> IResult<&'a str, char> {
582    let parsed: IResult<&'a str, char> = char(wanted).parse(input);
583    match parsed {
584        Ok(parsed) => Ok(parsed),
585        Err(_) => expected(input, state, what, nom::error::ErrorKind::Char),
586    }
587}
588
589fn single_line_value_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
590    (|i| single_line_values(i, state))
591        .map(Link::new_value)
592        .parse(input)
593}
594
595fn indented_id_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
596    let (input, (id, span)) = spanned_reference(input, state)?;
597    let (input, _) = horizontal_whitespace(input)?;
598    let (input, _) = colon(input, state)?;
599    let (input, _) = eol(input, state)?;
600    Ok((input, Link::new_indented_id(id).with_id_span(span)))
601}
602
603/// A parenthesized group opens a nested context: its body starts fresh at
604/// indentation level zero and is parsed with the same rules as the root
605/// document, so indentation is structural inside parentheses as well.
606fn nested_group<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
607    let (body_input, _) = character('(', input, state, "\"(\"")?;
608    state.check_depth(input, state.depth() + 1)?;
609    let saved = state.enter_nested_context();
610    let result = nested_group_body(body_input, state);
611    state.exit_nested_context(saved);
612    result
613}
614
615fn nested_group_body<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
616    match links(skip_empty_lines(input), state) {
617        Ok((rest, body)) => {
618            let (rest, _) = whitespace(rest)?;
619            let (rest, _) = closing_parenthesis(rest, state)?;
620            return Ok((rest, Link::new_nested(body)));
621        }
622        Err(failure @ nom::Err::Failure(_)) => return Err(failure),
623        Err(_) => {}
624    }
625    let (rest, _) = whitespace(input)?;
626    let (rest, _) = closing_parenthesis(rest, state)?;
627    Ok((rest, Link::new_nested(vec![])))
628}
629
630/// The parenthesis that closes a group.
631fn closing_parenthesis<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
632    character(')', input, state, "\")\"")
633}
634
635fn single_line_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
636    alt((
637        terminated(|i| single_line_link(i, state), |i| eol(i, state)),
638        terminated(|i| single_line_value_link(i, state), |i| eol(i, state)),
639    ))
640    .parse(input)
641}
642
643/// Reads one line, or fails at once when the line was already found unreadable.
644///
645/// A line that does not parse as the first child of the line above it is tried
646/// again as a sibling at every enclosing indentation level. When the line holds
647/// a group, each of those attempts reads the whole group again, so without this
648/// the work doubles with every indented level (issue #314).
649fn any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
650    let key = (input.as_ptr() as usize, state.is_inside_nested_context());
651    if let Some(&(offset, kind)) = state.unreadable_lines.borrow().get(&key) {
652        return Err(nom::Err::Error(nom::error::Error::new(
653            &input[offset..],
654            kind,
655        )));
656    }
657    let parsed = read_any_link(input, state);
658    if let Err(nom::Err::Error(error)) = &parsed {
659        let offset = error.input.as_ptr() as usize - input.as_ptr() as usize;
660        state
661            .unreadable_lines
662            .borrow_mut()
663            .insert(key, (offset, error.code));
664    }
665    parsed
666}
667
668/// A line that starts with a parenthesized group reads that group once and then
669/// branches on what follows it: the end of the line makes the group the whole
670/// link, and more values make it the first value of a value link.
671///
672/// Every other alternative would have to read the group again, which doubles
673/// the work at each level of nesting and makes a few dozen bytes take seconds
674/// ([#314](https://github.com/link-foundation/links-notation/issues/314)).
675fn read_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
676    let (rest, group) = match nested_group(input, state) {
677        Ok(parsed) => parsed,
678        // Neither an indented ID nor a single-line link can start with a
679        // parenthesis, and a value link would begin with this same group, so
680        // nothing else can read a line that opens one. Report it the way the
681        // single-line value link does, as a missing reference.
682        Err(_) if input.starts_with('(') => {
683            return spanned_reference(input, state)
684                .map(|(rest, (id, span))| (rest, Link::new_singlet(id).with_id_span(span)));
685        }
686        Err(_) => {
687            return alt((
688                |i| indented_id_link(i, state),
689                |i| single_line_any_link(i, state),
690            ))
691            .parse(input);
692        }
693    };
694    if let Ok((rest, _)) = eol(rest, state) {
695        return Ok((rest, group));
696    }
697    let (rest, more) = many0(|i| single_line_value_and_whitespace(i, state)).parse(rest)?;
698    let (rest, _) = eol(rest, state)?;
699    let mut values = Vec::with_capacity(more.len() + 1);
700    values.push(group);
701    values.extend(more);
702    Ok((rest, Link::new_value(values)))
703}
704
705fn count_indentation(input: &str) -> IResult<&str, usize> {
706    take_while(|c| c == ' ').map(|s: &str| s.len()).parse(input)
707}
708
709fn push_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
710    let (input, spaces) = count_indentation(skip_empty_lines(input))?;
711    let normalized_spaces = state.normalize_indentation(spaces);
712    let current = state.current_indentation();
713
714    if normalized_spaces > current {
715        state.push_indentation(normalized_spaces);
716        Ok((input, ()))
717    } else {
718        Err(nom::Err::Error(nom::error::Error::new(
719            input,
720            nom::error::ErrorKind::Verify,
721        )))
722    }
723}
724
725fn check_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
726    let (input, spaces) = count_indentation(input)?;
727    let normalized_spaces = state.normalize_indentation(spaces);
728
729    if state.check_indentation(normalized_spaces) {
730        Ok((input, ()))
731    } else {
732        Err(nom::Err::Error(nom::error::Error::new(
733            input,
734            nom::error::ErrorKind::Verify,
735        )))
736    }
737}
738
739fn element<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
740    let start = input;
741    let (input, link) = any_link(input, state)?;
742    // Only a line that parsed counts, so trailing spaces indented past the limit
743    // are still read as the whitespace they are.
744    state.check_depth(start, state.depth())?;
745
746    let indentation = state.indentation_stack.borrow().clone();
747    if let Ok((child_input, _)) = push_indentation(input, state) {
748        match links(child_input, state) {
749            Ok((rest, children)) => return Ok((rest, link.with_children(children))),
750            Err(failure @ nom::Err::Failure(_)) => return Err(failure),
751            Err(_) => {}
752        }
753        // No child line followed the indentation. Backtrack to the link so
754        // the document can consume the remaining spaces as whitespace.
755        state.indentation_stack.replace(indentation);
756    }
757    Ok((input, link))
758}
759
760fn first_line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
761    // Set base indentation from the first line and consume it, so that the first
762    // line is parsed exactly like every following line.
763    let (input, spaces) = count_indentation(input)?;
764    state.set_base_indentation(spaces);
765    element(input, state)
766}
767
768fn line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
769    // Blank lines do not break a document, they are simply skipped
770    preceded(|i| check_indentation(i, state), |i| element(i, state)).parse(skip_empty_lines(input))
771}
772
773fn links<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
774    let (input, first) = first_line(input, state)?;
775    let (input, rest) = many0(|i| line(i, state)).parse(input)?;
776
777    state.pop_indentation();
778
779    let mut result = vec![first];
780    result.extend(rest);
781    Ok((input, result))
782}
783
784pub fn parse_document(input: &str) -> IResult<&str, Vec<Link>> {
785    let state = ParserState::new();
786    document(input, &state)
787}
788
789/// Parses a document and, when it does not parse, says where it stopped.
790///
791/// `parse_document` reports a failure the way `nom` does: with the whole
792/// unconsumed remainder of the input and the combinator that gave up. Neither
793/// tells a reader which line to look at, and the remainder grows with the size
794/// of the document. This is the entry point the library uses.
795pub fn parse_document_with_diagnostics(input: &str) -> Result<Vec<Link>, ParseFailure> {
796    parse_document_with_max_depth(input, DEFAULT_MAX_DEPTH)
797}
798
799/// Parses a document the way [`parse_document_with_diagnostics`] does, refusing
800/// links nested deeper than `max_depth`. Every parenthesized group and every
801/// indentation level is one level of nesting.
802pub fn parse_document_with_max_depth(
803    input: &str,
804    max_depth: usize,
805) -> Result<Vec<Link>, ParseFailure> {
806    let state = ParserState::with_max_depth(max_depth);
807    match document(input, &state) {
808        Ok((_, links)) => Ok(links),
809        Err(error) => Err(state.failure(input, &error)),
810    }
811}
812
813/// Parses `prepared`, the document `source` with its comments blanked, the way
814/// [`parse_document_with_max_depth`] does, reading delimited references in
815/// `source`: the document as written.
816pub(crate) fn parse_prepared_document(
817    prepared: &str,
818    source: &str,
819    max_depth: usize,
820) -> Result<Vec<Link>, ParseFailure> {
821    debug_assert_eq!(prepared.len(), source.len());
822    let mut state = ParserState::with_max_depth(max_depth);
823    if prepared != source {
824        state.source = Some(source.into());
825    }
826    match document(prepared, &state) {
827        Ok((_, links)) => Ok(links),
828        Err(error) => Err(state.failure(prepared, &error)),
829    }
830}
831
832fn document<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
833    // Every reference is read from a part of this document, so the runs of
834    // delimiters are listed from all of it.
835    state.references(input);
836    state.document_start.set(input.as_ptr() as usize);
837
838    // Skip leading blank lines but preserve the line structure
839    let document = skip_empty_lines(input);
840
841    // Handle empty or whitespace-only documents
842    if document.trim_matches(is_whitespace_char).is_empty() {
843        return Ok(("", vec![]));
844    }
845
846    let (rest, result) = links(document, state)?;
847    let (rest, _) = whitespace(rest)?;
848    let end: IResult<&'a str, &'a str> = eof(rest);
849    let (rest, _) = match end {
850        Ok(parsed) => parsed,
851        Err(_) => return expected(rest, state, "end of input", nom::error::ErrorKind::Eof),
852    };
853
854    Ok((rest, result))
855}