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

TyRoXx / NonlocalityOS / 14944765145

10 May 2025 11:08AM UTC coverage: 71.585% (+0.05%) from 71.537%
14944765145

push

github

TyRoXx
GH-239: Update cargo-tarpaulin to 0.32.5

3129 of 4371 relevant lines covered (71.59%)

2223.52 hits per line

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

67.91
/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
    return 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.len() > 0 {
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
    return 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✔
183
            TokenContent::RightBracket => {
×
184
                return Err(ParserError::new(
×
185
                    "Expected expression, found right bracket.".to_string(),
×
186
                ))
187
            }
188
            TokenContent::Dot => todo!(),
189
            TokenContent::Quotes(content) => Ok(ast::Expression::StringLiteral(content.clone())),
6✔
190
            TokenContent::FatArrow => todo!(),
191
            TokenContent::Comma => todo!(),
192
        },
193
        None => Err(ParserError::new(
1✔
194
            "Expected expression, got EOF.".to_string(),
1✔
195
        )),
196
    }
197
}
198

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

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

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

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

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