flux_syntax/parser/
utils.rs

1//! Implementation of parser combinators
2
3use super::{LAngle, RAngle, lookahead::Peek};
4use crate::{
5    ParseCtxt, ParseResult,
6    lexer::{Delimiter, Token},
7};
8
9/// Parses a list of one ore more items separated by the requested token. Parsing continues
10/// until no separation token is found.
11pub(crate) fn sep1<R>(
12    cx: &mut ParseCtxt,
13    sep: Token,
14    mut parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
15) -> ParseResult<Vec<R>> {
16    let mut items = vec![parse(cx)?];
17    while cx.advance_if(sep) {
18        items.push(parse(cx)?);
19    }
20    Ok(items)
21}
22
23/// Parses a list of zero or more items. Parsing stops when the next token does *not* match
24/// the specified rule.
25pub(crate) fn repeat_while<P: Peek, R>(
26    cx: &mut ParseCtxt,
27    next: P,
28    mut parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
29) -> ParseResult<Vec<R>> {
30    let mut items = vec![];
31    while cx.peek(next) {
32        items.push(parse(cx)?);
33    }
34    Ok(items)
35}
36
37/// Parses a list of zero or more items. Parsing continues until the requested `end` token
38/// is reached. This does not consume the end token.
39pub(crate) fn until<P: Peek, R>(
40    cx: &mut ParseCtxt,
41    end: P,
42    mut parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
43) -> ParseResult<Vec<R>> {
44    let mut items = vec![];
45    while !cx.peek(end) {
46        items.push(parse(cx)?);
47    }
48    Ok(items)
49}
50
51/// Parses a list of zero or more items separated by a punctuation, with optional trailing
52/// punctuation. Parsing continues until the requested `end` token is reached. This does not
53/// consume the end token.
54///
55/// Returns the vector of items and a boolean indicating whether trailing punctuation was present.
56pub(crate) fn punctuated_with_trailing<E: Peek, R>(
57    cx: &mut ParseCtxt,
58    sep: Token,
59    end: E,
60    mut parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
61) -> ParseResult<(Vec<R>, bool)> {
62    let mut items = vec![];
63    let mut trailing = false;
64    while !cx.peek(end) {
65        items.push(parse(cx)?);
66        trailing = cx.advance_if(sep);
67        if !trailing {
68            break;
69        }
70    }
71    Ok((items, trailing))
72}
73
74/// Parses a list of zero or more items separated by a punctuation, with optional trailing
75/// punctuation. Parsing continues until the requested `end` token is reached. This does not
76/// consume the end token.
77pub(crate) fn punctuated_until<E: Peek, R>(
78    cx: &mut ParseCtxt,
79    sep: Token,
80    end: E,
81    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
82) -> ParseResult<Vec<R>> {
83    Ok(punctuated_with_trailing(cx, sep, end, parse)?.0)
84}
85
86/// Parses an item surrounded by an opening an closing [`Delimiter`]
87pub(crate) fn delimited<R>(
88    cx: &mut ParseCtxt,
89    delim: Delimiter,
90    parse: impl FnOnce(&mut ParseCtxt) -> ParseResult<R>,
91) -> ParseResult<R> {
92    cx.expect(Token::OpenDelim(delim))?;
93    let r = parse(cx)?;
94    cx.expect(Token::CloseDelim(delim))?;
95    Ok(r)
96}
97
98pub(crate) fn opt_angle<R>(
99    cx: &mut ParseCtxt,
100    sep: Token,
101    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
102) -> ParseResult<Vec<R>> {
103    if !cx.peek(LAngle) {
104        return Ok(vec![]);
105    }
106    angle(cx, sep, parse)
107}
108
109pub(crate) fn angle<R>(
110    cx: &mut ParseCtxt,
111    sep: Token,
112    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
113) -> ParseResult<Vec<R>> {
114    cx.expect(LAngle)?;
115    let items = punctuated_until(cx, sep, RAngle, parse)?;
116    cx.expect(RAngle)?;
117    Ok(items)
118}
119
120fn punctuated_delimited<R>(
121    cx: &mut ParseCtxt,
122    delim: Delimiter,
123    sep: Token,
124    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
125) -> ParseResult<Vec<R>> {
126    cx.expect(Token::OpenDelim(delim))?;
127    let r = punctuated_until(cx, sep, Token::CloseDelim(delim), parse)?;
128    cx.expect(Token::CloseDelim(delim))?;
129    Ok(r)
130}
131
132pub(crate) fn brackets<R>(
133    cx: &mut ParseCtxt,
134    sep: Token,
135    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
136) -> ParseResult<Vec<R>> {
137    punctuated_delimited(cx, Delimiter::Bracket, sep, parse)
138}
139
140pub(crate) fn parens<R>(
141    cx: &mut ParseCtxt,
142    sep: Token,
143    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
144) -> ParseResult<Vec<R>> {
145    punctuated_delimited(cx, Delimiter::Parenthesis, sep, parse)
146}
147
148pub(crate) fn braces<R>(
149    cx: &mut ParseCtxt,
150    sep: Token,
151    parse: impl FnMut(&mut ParseCtxt) -> ParseResult<R>,
152) -> ParseResult<Vec<R>> {
153    punctuated_delimited(cx, Delimiter::Brace, sep, parse)
154}