• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TyRoXx / NonlocalityOS / 14944764296

10 May 2025 11:08AM UTC coverage: 71.718% (+0.2%) from 71.537%
14944764296

Pull #243

github

web-flow
Merge 91ab88454 into edd1eca2a
Pull Request #243: GH-242: Enforce code style with cargo clippy

128 of 191 new or added lines in 25 files covered. (67.02%)

3 existing lines in 3 files now uncovered.

3076 of 4289 relevant lines covered (71.72%)

2265.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.22
/lambda_compiler/src/parsing.rs
1
use crate::{
2
    ast,
3
    compilation::{CompilerError, SourceLocation},
4
    tokenization::{Token, TokenContent},
5
};
6
use lambda::name::{Name, NamespaceId};
7

8
#[derive(Debug)]
9
pub struct ParserError {
10
    pub message: String,
11
}
12

13
impl ParserError {
14
    pub fn new(message: String) -> Self {
2✔
15
        Self { message }
16
    }
17
}
18

19
impl std::fmt::Display for ParserError {
20
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2✔
21
        write!(f, "{}", &self.message)
2✔
22
    }
23
}
24

25
pub type ParserResult<T> = std::result::Result<T, ParserError>;
26

27
pub fn pop_next_non_whitespace_token<'t>(
163✔
28
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
29
) -> Option<&'t Token> {
30
    let token = peek_next_non_whitespace_token(tokens);
163✔
31
    if token.is_some() {
316✔
32
        tokens.next();
153✔
33
    }
34

35
    token
163✔
36
}
37

38
pub fn peek_next_non_whitespace_token<'t>(
351✔
39
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
40
) -> Option<&'t Token> {
41
    loop {
×
42
        let next = tokens.peek();
429✔
43
        match next {
429✔
44
            Some(token) => match token.content {
376✔
45
                TokenContent::Whitespace => {
×
46
                    tokens.next();
78✔
47
                    continue;
78✔
48
                }
49
                TokenContent::Identifier(_)
×
50
                | TokenContent::Assign
×
51
                | TokenContent::LeftParenthesis
×
52
                | TokenContent::RightParenthesis
×
53
                | TokenContent::LeftBracket
×
54
                | TokenContent::RightBracket
×
55
                | TokenContent::Dot
×
56
                | TokenContent::Quotes(_)
×
57
                | TokenContent::FatArrow
×
58
                | TokenContent::Comma => return Some(token),
298✔
59
            },
60
            None => return None,
53✔
61
        }
62
    }
63
}
64

65
fn expect_right_parenthesis(tokens: &mut std::iter::Peekable<std::slice::Iter<'_, Token>>) {
17✔
66
    match pop_next_non_whitespace_token(tokens) {
17✔
67
        Some(non_whitespace) => match &non_whitespace.content {
17✔
68
            TokenContent::Whitespace => todo!(),
69
            TokenContent::Identifier(_) => todo!(),
70
            TokenContent::Assign => todo!(),
71
            TokenContent::LeftParenthesis => todo!(),
72
            TokenContent::RightParenthesis => {}
17✔
73
            TokenContent::LeftBracket => todo!(),
74
            TokenContent::RightBracket => todo!(),
75
            TokenContent::Dot => todo!(),
76
            TokenContent::Quotes(_) => todo!(),
77
            TokenContent::FatArrow => todo!(),
78
            TokenContent::Comma => todo!(),
79
        },
80
        None => todo!(),
81
    }
82
}
83

84
fn expect_fat_arrow(tokens: &mut std::iter::Peekable<std::slice::Iter<'_, Token>>) {
14✔
85
    match pop_next_non_whitespace_token(tokens) {
14✔
86
        Some(non_whitespace) => match &non_whitespace.content {
14✔
87
            TokenContent::Whitespace => todo!(),
88
            TokenContent::Identifier(_) => todo!(),
89
            TokenContent::Assign => todo!(),
90
            TokenContent::LeftParenthesis => todo!(),
91
            TokenContent::RightParenthesis => todo!(),
92
            TokenContent::LeftBracket => todo!(),
93
            TokenContent::RightBracket => todo!(),
94
            TokenContent::Dot => todo!(),
95
            TokenContent::Quotes(_) => todo!(),
96
            TokenContent::FatArrow => {}
14✔
97
            TokenContent::Comma => todo!(),
98
        },
99
        None => todo!(),
100
    }
101
}
102

103
fn expect_comma(tokens: &mut std::iter::Peekable<std::slice::Iter<'_, Token>>) {
21✔
104
    match pop_next_non_whitespace_token(tokens) {
21✔
105
        Some(non_whitespace) => match &non_whitespace.content {
21✔
106
            TokenContent::Whitespace => todo!(),
107
            TokenContent::Identifier(_) => todo!(),
108
            TokenContent::Assign => todo!(),
109
            TokenContent::LeftParenthesis => todo!(),
110
            TokenContent::RightParenthesis => todo!(),
111
            TokenContent::LeftBracket => todo!(),
112
            TokenContent::RightBracket => todo!(),
113
            TokenContent::Dot => todo!(),
114
            TokenContent::Quotes(_) => todo!(),
115
            TokenContent::FatArrow => todo!(),
116
            TokenContent::Comma => {}
21✔
117
        },
118
        None => todo!(),
119
    }
120
}
121

122
fn skip_right_bracket(tokens: &mut std::iter::Peekable<std::slice::Iter<'_, Token>>) -> bool {
104✔
123
    let maybe_right_bracket = peek_next_non_whitespace_token(tokens);
104✔
124
    match maybe_right_bracket {
104✔
125
        Some(token) => match &token.content {
104✔
126
            TokenContent::Whitespace => unreachable!(),
127
            TokenContent::Identifier(_) => false,
43✔
128
            TokenContent::Assign => false,
×
129
            TokenContent::LeftParenthesis => false,
×
130
            TokenContent::RightParenthesis => false,
×
131
            TokenContent::LeftBracket => false,
2✔
132
            TokenContent::RightBracket => {
133
                tokens.next();
29✔
134
                true
29✔
135
            }
136
            TokenContent::Dot => false,
×
137
            TokenContent::Quotes(_) => false,
9✔
138
            TokenContent::FatArrow => false,
×
139
            TokenContent::Comma => false,
21✔
140
        },
141
        None => false,
×
142
    }
143
}
144

145
fn parse_tree_construction(
29✔
146
    tokens: &mut std::iter::Peekable<std::slice::Iter<'_, Token>>,
147
    local_namespace: &NamespaceId,
148
) -> ParserResult<ast::Expression> {
149
    let mut elements = Vec::new();
29✔
150
    loop {
151
        if skip_right_bracket(tokens) {
61✔
152
            break;
18✔
153
        }
154
        if !elements.is_empty() {
64✔
155
            expect_comma(tokens);
21✔
156
        }
157
        if skip_right_bracket(tokens) {
158
            break;
11✔
159
        }
160
        let element = parse_expression(tokens, local_namespace)?;
32✔
161
        elements.push(element);
162
    }
163
    Ok(ast::Expression::ConstructTree(elements))
29✔
164
}
165

166
fn parse_expression_start<'t>(
87✔
167
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
168
    local_namespace: &NamespaceId,
169
) -> ParserResult<ast::Expression> {
170
    match pop_next_non_whitespace_token(tokens) {
87✔
171
        Some(non_whitespace) => match &non_whitespace.content {
86✔
172
            TokenContent::Whitespace => todo!(),
173
            TokenContent::Identifier(identifier) => Ok(ast::Expression::Identifier(Name::new(
36✔
174
                *local_namespace,
36✔
175
                identifier.clone(),
36✔
176
            ))),
177
            TokenContent::Assign => todo!(),
178
            TokenContent::LeftParenthesis => parse_lambda(tokens, local_namespace),
14✔
179
            TokenContent::RightParenthesis => Err(ParserError::new(
1✔
180
                "Expected expression, found right parenthesis.".to_string(),
1✔
181
            )),
182
            TokenContent::LeftBracket => parse_tree_construction(tokens, local_namespace),
29✔
NEW
183
            TokenContent::RightBracket => Err(ParserError::new(
×
NEW
184
                "Expected expression, found right bracket.".to_string(),
×
185
            )),
186
            TokenContent::Dot => todo!(),
187
            TokenContent::Quotes(content) => Ok(ast::Expression::StringLiteral(content.clone())),
6✔
188
            TokenContent::FatArrow => todo!(),
189
            TokenContent::Comma => todo!(),
190
        },
191
        None => Err(ParserError::new(
1✔
192
            "Expected expression, got EOF.".to_string(),
1✔
193
        )),
194
    }
195
}
196

197
pub fn parse_expression<'t>(
87✔
198
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
199
    local_namespace: &NamespaceId,
200
) -> ParserResult<ast::Expression> {
201
    let start = parse_expression_start(tokens, local_namespace)?;
174✔
202
    match peek_next_non_whitespace_token(tokens) {
×
203
        Some(more) => match &more.content {
41✔
204
            TokenContent::Whitespace => unreachable!(),
205
            TokenContent::Identifier(_) => Ok(start),
×
206
            TokenContent::Assign => Ok(start),
×
207
            TokenContent::LeftParenthesis => {
×
208
                tokens.next();
4✔
209
                let argument = parse_expression(tokens, local_namespace)?;
8✔
210
                expect_right_parenthesis(tokens);
×
211
                Ok(ast::Expression::Apply {
×
212
                    callee: Box::new(start),
×
213
                    argument: Box::new(argument),
×
214
                })
215
            }
216
            TokenContent::RightParenthesis => Ok(start),
5✔
217
            TokenContent::LeftBracket => todo!(),
218
            TokenContent::RightBracket => Ok(start),
11✔
219
            TokenContent::Dot => todo!(),
220
            TokenContent::Quotes(_) => todo!(),
221
            TokenContent::FatArrow => todo!(),
222
            TokenContent::Comma => Ok(start),
21✔
223
        },
224
        None => Ok(start),
43✔
225
    }
226
}
227

228
fn parse_lambda<'t>(
14✔
229
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
230
    local_namespace: &NamespaceId,
231
) -> ParserResult<ast::Expression> {
232
    let parameter_name: Name = Name::new(
233
        *local_namespace,
14✔
234
        match pop_next_non_whitespace_token(tokens) {
14✔
235
            Some(non_whitespace) => match &non_whitespace.content {
14✔
236
                TokenContent::Whitespace => todo!(),
×
237
                TokenContent::Identifier(identifier) => identifier.clone(),
14✔
238
                TokenContent::Assign => todo!(),
×
239
                TokenContent::LeftParenthesis => todo!(),
×
240
                TokenContent::RightParenthesis => todo!(),
×
241
                TokenContent::LeftBracket => todo!(),
×
242
                TokenContent::RightBracket => todo!(),
×
243
                TokenContent::Dot => todo!(),
×
244
                TokenContent::Quotes(_) => todo!(),
×
245
                TokenContent::FatArrow => todo!(),
×
246
                TokenContent::Comma => todo!(),
×
247
            },
248
            None => todo!(),
×
249
        },
250
    );
251
    expect_right_parenthesis(tokens);
14✔
252
    expect_fat_arrow(tokens);
14✔
253
    let body = parse_expression(tokens, local_namespace)?;
28✔
254
    Ok(ast::Expression::Lambda {
×
NEW
255
        parameter_name,
×
256
        body: Box::new(body),
×
257
    })
258
}
259

260
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
261
pub struct ParserOutput {
262
    pub entry_point: Option<ast::Expression>,
263
    pub errors: Vec<CompilerError>,
264
}
265

266
impl ParserOutput {
267
    pub fn new(entry_point: Option<ast::Expression>, errors: Vec<CompilerError>) -> ParserOutput {
12✔
268
        ParserOutput {
269
            entry_point,
270
            errors,
271
        }
272
    }
273
}
274

275
pub fn parse_expression_tolerantly<'t>(
11✔
276
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
277
    local_namespace: &NamespaceId,
278
) -> ParserOutput {
279
    let mut errors = Vec::new();
11✔
280
    let entry_point_result = parse_expression(tokens, local_namespace);
11✔
281
    match entry_point_result {
11✔
282
        Ok(entry_point) => ParserOutput::new(Some(entry_point), errors),
9✔
283
        Err(error) => {
2✔
284
            errors.push(CompilerError::new(
2✔
285
                format!("Parser error: {}", &error),
2✔
286
                SourceLocation::new(0, 0),
2✔
287
            ));
288
            ParserOutput::new(None, errors)
2✔
289
        }
290
    }
291
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc