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

TyRoXx / NonlocalityOS / 14945234271

10 May 2025 12:15PM UTC coverage: 71.79% (+0.2%) from 71.585%
14945234271

push

github

TyRoXx
GH-242: Enforce code style with cargo clippy

129 of 193 new or added lines in 25 files covered. (66.84%)

4 existing lines in 4 files now uncovered.

3097 of 4314 relevant lines covered (71.79%)

2252.93 hits per line

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

68.42
/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>(
168✔
28
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
29
) -> Option<&'t Token> {
30
    let token = peek_next_non_whitespace_token(tokens);
168✔
31
    if token.is_some() {
326✔
32
        tokens.next();
158✔
33
    }
34

35
    token
168✔
36
}
37

38
pub fn peek_next_non_whitespace_token<'t>(
387✔
39
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
40
) -> Option<&'t Token> {
41
    loop {
×
42
        let next = tokens.peek();
470✔
43
        match next {
470✔
44
            Some(token) => match token.content {
413✔
45
                TokenContent::Whitespace => {
×
46
                    tokens.next();
83✔
47
                    continue;
83✔
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),
330✔
59
            },
60
            None => return None,
57✔
61
        }
62
    }
63
}
64

65
fn expect_right_parenthesis(tokens: &mut std::iter::Peekable<std::slice::Iter<'_, Token>>) {
19✔
66
    match pop_next_non_whitespace_token(tokens) {
19✔
67
        Some(non_whitespace) => match &non_whitespace.content {
19✔
68
            TokenContent::Whitespace => todo!(),
69
            TokenContent::Identifier(_) => todo!(),
70
            TokenContent::Assign => todo!(),
71
            TokenContent::LeftParenthesis => todo!(),
72
            TokenContent::RightParenthesis => {}
19✔
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>>) {
16✔
85
    match pop_next_non_whitespace_token(tokens) {
16✔
86
        Some(non_whitespace) => match &non_whitespace.content {
16✔
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 => {}
16✔
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>(
91✔
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) {
91✔
171
        Some(non_whitespace) => match &non_whitespace.content {
90✔
172
            TokenContent::Whitespace => todo!(),
173
            TokenContent::Identifier(identifier) => Ok(ast::Expression::Identifier(Name::new(
38✔
174
                *local_namespace,
38✔
175
                identifier.clone(),
38✔
176
            ))),
177
            TokenContent::Assign => todo!(),
178
            TokenContent::LeftParenthesis => parse_lambda(tokens, local_namespace),
16✔
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>(
91✔
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)?;
182✔
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),
47✔
225
    }
226
}
227

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

265
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
266
pub struct ParserOutput {
267
    pub entry_point: Option<ast::Expression>,
268
    pub errors: Vec<CompilerError>,
269
}
270

271
impl ParserOutput {
272
    pub fn new(entry_point: Option<ast::Expression>, errors: Vec<CompilerError>) -> ParserOutput {
12✔
273
        ParserOutput {
274
            entry_point,
275
            errors,
276
        }
277
    }
278
}
279

280
pub fn parse_expression_tolerantly<'t>(
11✔
281
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
282
    local_namespace: &NamespaceId,
283
) -> ParserOutput {
284
    let mut errors = Vec::new();
11✔
285
    let entry_point_result = parse_expression(tokens, local_namespace);
11✔
286
    match entry_point_result {
11✔
287
        Ok(entry_point) => ParserOutput::new(Some(entry_point), errors),
9✔
288
        Err(error) => {
2✔
289
            errors.push(CompilerError::new(
2✔
290
                format!("Parser error: {}", &error),
2✔
291
                SourceLocation::new(0, 0),
2✔
292
            ));
293
            ParserOutput::new(None, errors)
2✔
294
        }
295
    }
296
}
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