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

TyRoXx / NonlocalityOS / 14818974370

04 May 2025 07:28AM UTC coverage: 73.132% (+0.1%) from 72.986%
14818974370

Pull #236

github

web-flow
Merge 9862ccdec into 1d7c2410e
Pull Request #236: Introduce an AST to the parser

57 of 65 new or added lines in 5 files covered. (87.69%)

7 existing lines in 3 files now uncovered.

3073 of 4202 relevant lines covered (73.13%)

2258.38 hits per line

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

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

35
    return token;
65✔
36
}
37

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

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

78
fn expect_fat_arrow(tokens: &mut std::iter::Peekable<std::slice::Iter<'_, Token>>) {
10✔
79
    match pop_next_non_whitespace_token(tokens) {
10✔
80
        Some(non_whitespace) => match &non_whitespace.content {
10✔
81
            TokenContent::Whitespace => todo!(),
82
            TokenContent::Identifier(_) => todo!(),
83
            TokenContent::Assign => todo!(),
84
            TokenContent::LeftParenthesis => todo!(),
85
            TokenContent::RightParenthesis => todo!(),
86
            TokenContent::Dot => todo!(),
87
            TokenContent::Quotes(_) => todo!(),
88
            TokenContent::FatArrow => {}
10✔
89
        },
90
        None => todo!(),
91
    }
92
}
93

94
fn parse_expression_start<'t>(
25✔
95
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
96
    local_namespace: &NamespaceId,
97
) -> ParserResult<ast::Expression> {
98
    match pop_next_non_whitespace_token(tokens) {
25✔
99
        Some(non_whitespace) => match &non_whitespace.content {
24✔
100
            TokenContent::Whitespace => todo!(),
101
            TokenContent::Identifier(identifier) => Ok(ast::Expression::Identifier(Name::new(
11✔
102
                *local_namespace,
11✔
103
                identifier.clone(),
11✔
104
            ))),
105
            TokenContent::Assign => todo!(),
106
            TokenContent::LeftParenthesis => parse_lambda(tokens, local_namespace),
10✔
107
            TokenContent::RightParenthesis => Err(ParserError::new(
1✔
108
                "Expected expression, found right parenthesis.".to_string(),
1✔
109
            )),
110
            TokenContent::Dot => todo!(),
111
            TokenContent::Quotes(content) => Ok(ast::Expression::StringLiteral(content.clone())),
2✔
112
            TokenContent::FatArrow => todo!(),
113
        },
114
        None => Err(ParserError::new(
1✔
115
            "Expected expression, got EOF.".to_string(),
1✔
116
        )),
117
    }
118
}
119

120
pub fn parse_expression<'t>(
25✔
121
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
122
    local_namespace: &NamespaceId,
123
) -> ParserResult<ast::Expression> {
124
    let start = parse_expression_start(tokens, local_namespace)?;
50✔
UNCOV
125
    match peek_next_non_whitespace_token(tokens) {
×
126
        Some(more) => match &more.content {
11✔
127
            TokenContent::Whitespace => unreachable!(),
128
            TokenContent::Identifier(_) => Ok(start),
×
129
            TokenContent::Assign => Ok(start),
×
130
            TokenContent::LeftParenthesis => {
×
131
                tokens.next();
5✔
132
                let argument = parse_expression(tokens, local_namespace)?;
10✔
133
                expect_right_parenthesis(tokens);
×
NEW
134
                Ok(ast::Expression::Apply {
×
NEW
135
                    callee: Box::new(start),
×
NEW
136
                    argument: Box::new(argument),
×
137
                })
138
            }
139
            TokenContent::RightParenthesis => Ok(start),
6✔
140
            TokenContent::Dot => todo!(),
141
            TokenContent::Quotes(_) => todo!(),
142
            TokenContent::FatArrow => todo!(),
143
        },
144
        None => Ok(start),
11✔
145
    }
146
}
147

148
fn parse_lambda<'t>(
10✔
149
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
150
    local_namespace: &NamespaceId,
151
) -> ParserResult<ast::Expression> {
152
    let parameter_name: Name = Name::new(
153
        *local_namespace,
10✔
154
        match pop_next_non_whitespace_token(tokens) {
10✔
155
            Some(non_whitespace) => match &non_whitespace.content {
10✔
156
                TokenContent::Whitespace => todo!(),
×
157
                TokenContent::Identifier(identifier) => identifier.clone(),
10✔
158
                TokenContent::Assign => todo!(),
×
159
                TokenContent::LeftParenthesis => todo!(),
×
160
                TokenContent::RightParenthesis => todo!(),
×
161
                TokenContent::Dot => todo!(),
×
162
                TokenContent::Quotes(_) => todo!(),
×
163
                TokenContent::FatArrow => todo!(),
×
164
            },
165
            None => todo!(),
×
166
        },
167
    );
168
    expect_right_parenthesis(tokens);
10✔
169
    expect_fat_arrow(tokens);
10✔
170
    let body = parse_expression(tokens, local_namespace)?;
20✔
NEW
171
    Ok(ast::Expression::Lambda {
×
NEW
172
        parameter_name: parameter_name,
×
NEW
173
        body: Box::new(body),
×
174
    })
175
}
176

177
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
178
pub struct ParserOutput {
179
    pub entry_point: Option<ast::Expression>,
180
    pub errors: Vec<CompilerError>,
181
}
182

183
impl ParserOutput {
184
    pub fn new(entry_point: Option<ast::Expression>, errors: Vec<CompilerError>) -> ParserOutput {
8✔
185
        ParserOutput {
186
            entry_point: entry_point,
187
            errors: errors,
188
        }
189
    }
190
}
191

192
pub fn parse_expression_tolerantly<'t>(
7✔
193
    tokens: &mut std::iter::Peekable<std::slice::Iter<'t, Token>>,
194
    local_namespace: &NamespaceId,
195
) -> ParserOutput {
196
    let mut errors = Vec::new();
7✔
197
    let entry_point_result = parse_expression(tokens, local_namespace);
7✔
198
    match entry_point_result {
7✔
199
        Ok(entry_point) => ParserOutput::new(Some(entry_point), errors),
5✔
200
        Err(error) => {
2✔
201
            errors.push(CompilerError::new(
2✔
202
                format!("Parser error: {}", &error),
2✔
203
                SourceLocation::new(0, 0),
2✔
204
            ));
205
            ParserOutput::new(None, errors)
2✔
206
        }
207
    }
208
}
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