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

TyRoXx / NonlocalityOS / 14825942646

04 May 2025 10:48PM UTC coverage: 73.166% (+0.03%) from 73.132%
14825942646

Pull #237

github

web-flow
Merge adddf5a39 into 34f1d88fd
Pull Request #237: Tree literal

30 of 35 new or added lines in 3 files covered. (85.71%)

15 existing lines in 1 file now uncovered.

3092 of 4226 relevant lines covered (73.17%)

2252.58 hits per line

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

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

35
    return token;
76✔
36
}
37

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

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

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

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

118
fn parse_tree_construction(
3✔
119
    tokens: &mut std::iter::Peekable<std::slice::Iter<'_, Token>>,
120
    local_namespace: &NamespaceId,
121
) -> ParserResult<ast::Expression> {
122
    let mut elements = Vec::new();
3✔
123
    let element = parse_expression(tokens, local_namespace)?;
6✔
124
    elements.push(element);
125
    expect_right_bracket(tokens);
126
    Ok(ast::Expression::ConstructTree(elements))
127
}
128

129
fn parse_expression_start<'t>(
30✔
130
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
131
    local_namespace: &NamespaceId,
132
) -> ParserResult<ast::Expression> {
133
    match pop_next_non_whitespace_token(tokens) {
30✔
134
        Some(non_whitespace) => match &non_whitespace.content {
29✔
135
            TokenContent::Whitespace => todo!(),
136
            TokenContent::Identifier(identifier) => Ok(ast::Expression::Identifier(Name::new(
11✔
137
                *local_namespace,
11✔
138
                identifier.clone(),
11✔
139
            ))),
140
            TokenContent::Assign => todo!(),
141
            TokenContent::LeftParenthesis => parse_lambda(tokens, local_namespace),
11✔
142
            TokenContent::RightParenthesis => Err(ParserError::new(
1✔
143
                "Expected expression, found right parenthesis.".to_string(),
1✔
144
            )),
145
            TokenContent::LeftBracket => parse_tree_construction(tokens, local_namespace),
3✔
146
            TokenContent::RightBracket => todo!(),
147
            TokenContent::Dot => todo!(),
148
            TokenContent::Quotes(content) => Ok(ast::Expression::StringLiteral(content.clone())),
3✔
149
            TokenContent::FatArrow => todo!(),
150
        },
151
        None => Err(ParserError::new(
1✔
152
            "Expected expression, got EOF.".to_string(),
1✔
153
        )),
154
    }
155
}
156

157
pub fn parse_expression<'t>(
30✔
158
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
159
    local_namespace: &NamespaceId,
160
) -> ParserResult<ast::Expression> {
161
    let start = parse_expression_start(tokens, local_namespace)?;
60✔
162
    match peek_next_non_whitespace_token(tokens) {
×
163
        Some(more) => match &more.content {
12✔
164
            TokenContent::Whitespace => unreachable!(),
165
            TokenContent::Identifier(_) => Ok(start),
×
UNCOV
166
            TokenContent::Assign => Ok(start),
×
UNCOV
167
            TokenContent::LeftParenthesis => {
×
168
                tokens.next();
4✔
169
                let argument = parse_expression(tokens, local_namespace)?;
8✔
UNCOV
170
                expect_right_parenthesis(tokens);
×
UNCOV
171
                Ok(ast::Expression::Apply {
×
UNCOV
172
                    callee: Box::new(start),
×
UNCOV
173
                    argument: Box::new(argument),
×
174
                })
175
            }
176
            TokenContent::RightParenthesis => Ok(start),
5✔
177
            TokenContent::LeftBracket => todo!(),
178
            TokenContent::RightBracket => Ok(start),
3✔
179
            TokenContent::Dot => todo!(),
180
            TokenContent::Quotes(_) => todo!(),
181
            TokenContent::FatArrow => todo!(),
182
        },
183
        None => Ok(start),
15✔
184
    }
185
}
186

187
fn parse_lambda<'t>(
11✔
188
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
189
    local_namespace: &NamespaceId,
190
) -> ParserResult<ast::Expression> {
191
    let parameter_name: Name = Name::new(
192
        *local_namespace,
11✔
193
        match pop_next_non_whitespace_token(tokens) {
11✔
194
            Some(non_whitespace) => match &non_whitespace.content {
11✔
UNCOV
195
                TokenContent::Whitespace => todo!(),
×
196
                TokenContent::Identifier(identifier) => identifier.clone(),
11✔
UNCOV
197
                TokenContent::Assign => todo!(),
×
UNCOV
198
                TokenContent::LeftParenthesis => todo!(),
×
UNCOV
199
                TokenContent::RightParenthesis => todo!(),
×
NEW
UNCOV
200
                TokenContent::LeftBracket => todo!(),
×
NEW
UNCOV
201
                TokenContent::RightBracket => todo!(),
×
UNCOV
202
                TokenContent::Dot => todo!(),
×
UNCOV
203
                TokenContent::Quotes(_) => todo!(),
×
204
                TokenContent::FatArrow => todo!(),
×
205
            },
UNCOV
206
            None => todo!(),
×
207
        },
208
    );
209
    expect_right_parenthesis(tokens);
11✔
210
    expect_fat_arrow(tokens);
11✔
211
    let body = parse_expression(tokens, local_namespace)?;
22✔
212
    Ok(ast::Expression::Lambda {
×
213
        parameter_name: parameter_name,
×
214
        body: Box::new(body),
×
215
    })
216
}
217

218
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
219
pub struct ParserOutput {
220
    pub entry_point: Option<ast::Expression>,
221
    pub errors: Vec<CompilerError>,
222
}
223

224
impl ParserOutput {
225
    pub fn new(entry_point: Option<ast::Expression>, errors: Vec<CompilerError>) -> ParserOutput {
9✔
226
        ParserOutput {
227
            entry_point: entry_point,
228
            errors: errors,
229
        }
230
    }
231
}
232

233
pub fn parse_expression_tolerantly<'t>(
8✔
234
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
235
    local_namespace: &NamespaceId,
236
) -> ParserOutput {
237
    let mut errors = Vec::new();
8✔
238
    let entry_point_result = parse_expression(tokens, local_namespace);
8✔
239
    match entry_point_result {
8✔
240
        Ok(entry_point) => ParserOutput::new(Some(entry_point), errors),
6✔
241
        Err(error) => {
2✔
242
            errors.push(CompilerError::new(
2✔
243
                format!("Parser error: {}", &error),
2✔
244
                SourceLocation::new(0, 0),
2✔
245
            ));
246
            ParserOutput::new(None, errors)
2✔
247
        }
248
    }
249
}
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