flux_syntax/parser/
utils.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! Implementation of parser combinators

use super::{LAngle, RAngle, lookahead::Peek};
use crate::{
    ParseCtxt, ParseResult,
    lexer::{Delimiter, Token},
};

/// Parses a list of one ore more items separated by the requested token. Parsing continues
/// until no separation token is found.
pub(crate) fn sep1<R>(
    cx: &mut ParseCtxt,
    sep: Token,
    mut parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<Vec<R>> {
    let mut items = vec![parse(cx)?];
    while cx.advance_if(sep) {
        items.push(parse(cx)?);
    }
    Ok(items)
}

/// Parses a list of zero or more items. Parsing stops when the next token does *not* match
/// the specified rule.
pub(crate) fn repeat_while<P: Peek, R>(
    cx: &mut ParseCtxt,
    next: P,
    mut parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<Vec<R>> {
    let mut items = vec![];
    while cx.peek(next) {
        items.push(parse(cx)?);
    }
    Ok(items)
}

/// Parses a list of zero or more items. Parsing continues until the requested `end` token
/// is reached. This does not consume the end token.
pub(crate) fn until<P: Peek, R>(
    cx: &mut ParseCtxt,
    end: P,
    mut parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<Vec<R>> {
    let mut items = vec![];
    while !cx.peek(end) {
        items.push(parse(cx)?);
    }
    Ok(items)
}

/// Parses a list of zero or more items separated by a punctuation, with optional trailing
/// punctuation. Parsing continues until the requested `end` token is reached. This does not
/// consume the end token.
///
/// Returns the vector of items and a boolean indicating whether trailing punctuation was present.
pub(crate) fn punctuated_with_trailing<E: Peek, R>(
    cx: &mut ParseCtxt,
    sep: Token,
    end: E,
    mut parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<(Vec<R>, bool)> {
    let mut items = vec![];
    let mut trailing = false;
    while !cx.peek(end) {
        items.push(parse(cx)?);
        trailing = cx.advance_if(sep);
        if !trailing {
            break;
        }
    }
    Ok((items, trailing))
}

/// Parses a list of zero or more items separated by a punctuation, with optional trailing
/// punctuation. Parsing continues until the requested `end` token is reached. This does not
/// consume the end token.
pub(crate) fn punctuated_until<E: Peek, R>(
    cx: &mut ParseCtxt,
    sep: Token,
    end: E,
    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<Vec<R>> {
    Ok(punctuated_with_trailing(cx, sep, end, parse)?.0)
}

/// Parses an item surrounded by an opening an closing [`Delimiter`]
pub(crate) fn delimited<R>(
    cx: &mut ParseCtxt,
    delim: Delimiter,
    parse: impl FnOnce(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<R> {
    cx.expect(Token::OpenDelim(delim))?;
    let r = parse(cx)?;
    cx.expect(Token::CloseDelim(delim))?;
    Ok(r)
}

pub(crate) fn opt_angle<R>(
    cx: &mut ParseCtxt,
    sep: Token,
    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<Vec<R>> {
    if !cx.peek(LAngle) {
        return Ok(vec![]);
    }
    angle(cx, sep, parse)
}

pub(crate) fn angle<R>(
    cx: &mut ParseCtxt,
    sep: Token,
    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<Vec<R>> {
    cx.expect(LAngle)?;
    let items = punctuated_until(cx, sep, RAngle, parse)?;
    cx.expect(RAngle)?;
    Ok(items)
}

fn punctuated_delimited<R>(
    cx: &mut ParseCtxt,
    delim: Delimiter,
    sep: Token,
    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<Vec<R>> {
    cx.expect(Token::OpenDelim(delim))?;
    let r = punctuated_until(cx, sep, Token::CloseDelim(delim), parse)?;
    cx.expect(Token::CloseDelim(delim))?;
    Ok(r)
}

pub(crate) fn brackets<R>(
    cx: &mut ParseCtxt,
    sep: Token,
    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<Vec<R>> {
    punctuated_delimited(cx, Delimiter::Bracket, sep, parse)
}

pub(crate) fn parens<R>(
    cx: &mut ParseCtxt,
    sep: Token,
    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<Vec<R>> {
    punctuated_delimited(cx, Delimiter::Parenthesis, sep, parse)
}

pub(crate) fn braces<R>(
    cx: &mut ParseCtxt,
    sep: Token,
    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
) -> ParseResult<Vec<R>> {
    punctuated_delimited(cx, Delimiter::Brace, sep, parse)
}