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

TyRoXx / NonlocalityOS / 14826269493

04 May 2025 11:33PM UTC coverage: 73.084% (-0.05%) from 73.132%
14826269493

push

github

TyRoXx
Test nested tree construction

3109 of 4254 relevant lines covered (73.08%)

2284.6 hits per line

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

67.69
/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
    return 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.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>(
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✔
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>(
87✔
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)?;
174✔
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),
43✔
227
    }
228
}
229

230
fn parse_lambda<'t>(
14✔
231
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
232
    local_namespace: &NamespaceId,
233
) -> ParserResult<ast::Expression> {
234
    let parameter_name: Name = Name::new(
235
        *local_namespace,
14✔
236
        match pop_next_non_whitespace_token(tokens) {
14✔
237
            Some(non_whitespace) => match &non_whitespace.content {
14✔
238
                TokenContent::Whitespace => todo!(),
×
239
                TokenContent::Identifier(identifier) => identifier.clone(),
14✔
240
                TokenContent::Assign => todo!(),
×
241
                TokenContent::LeftParenthesis => todo!(),
×
242
                TokenContent::RightParenthesis => todo!(),
×
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 => todo!(),
×
251
        },
252
    );
253
    expect_right_parenthesis(tokens);
14✔
254
    expect_fat_arrow(tokens);
14✔
255
    let body = parse_expression(tokens, local_namespace)?;
28✔
256
    Ok(ast::Expression::Lambda {
×
257
        parameter_name: parameter_name,
×
258
        body: Box::new(body),
×
259
    })
260
}
261

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

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

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