Skip to content

Commit 4ec7a0b

Browse files
committed
add if parser
1 parent 7244b40 commit 4ec7a0b

File tree

2 files changed

+144
-18
lines changed

2 files changed

+144
-18
lines changed

src/lexer.rs

Lines changed: 87 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,33 @@ pub enum Token<'src> {
2121
Else,
2222

2323
// Control symbols
24+
/// `->``
2425
Arrow,
26+
/// `:`
2527
Colon,
28+
/// `;`
2629
Semi,
30+
/// `,`
2731
Comma,
32+
/// `=`
2833
Eq,
34+
/// `=>`
2935
FatArrow,
36+
/// `(`
3037
LParen,
38+
/// `)`
3139
RParen,
40+
/// `[`
3241
LBracket,
42+
/// `]`
3343
RBracket,
44+
/// `{`
3445
LBrace,
46+
/// `}`
3547
RBrace,
48+
/// `<`
3649
LAngle,
50+
/// `>`
3751
RAngle,
3852

3953
// Number literals
@@ -257,29 +271,86 @@ mod tests {
257271
(tokens, errors)
258272
}
259273

274+
/// Helper function to get the variant name of a token
275+
fn variant_name(token: &Token) -> &'static str {
276+
match token {
277+
Token::Fn => "Fn",
278+
Token::Let => "Let",
279+
Token::Type => "Type",
280+
Token::Mod => "Mod",
281+
Token::Const => "Const",
282+
Token::Match => "Match",
283+
Token::If => "If",
284+
Token::Else => "Else",
285+
Token::Arrow => "Arrow",
286+
Token::Colon => "Colon",
287+
Token::Semi => "Semi",
288+
Token::Comma => "Comma",
289+
Token::Eq => "Eq",
290+
Token::FatArrow => "FatArrow",
291+
Token::LParen => "LParen",
292+
Token::RParen => "RParen",
293+
Token::LBracket => "LBracket",
294+
Token::RBracket => "RBracket",
295+
Token::LBrace => "LBrace",
296+
Token::RBrace => "RBrace",
297+
Token::LAngle => "LAngle",
298+
Token::RAngle => "RAngle",
299+
Token::DecLiteral(_) => "DecLiteral",
300+
Token::HexLiteral(_) => "HexLiteral",
301+
Token::BinLiteral(_) => "BinLiteral",
302+
Token::Bool(_) => "Bool",
303+
Token::Ident(_) => "Ident",
304+
Token::Jet(_) => "Jet",
305+
Token::Witness(_) => "Witness",
306+
Token::Param(_) => "Param",
307+
Token::Macro(_) => "Macro",
308+
Token::Comment => "Comment",
309+
Token::BlockComment => "BlockComment",
310+
}
311+
}
312+
313+
/// Macro to assert that a sequence of tokens matches the expected variant types
314+
macro_rules! assert_tokens_match {
315+
($tokens:expr, $($expected:ident),* $(,)?) => {
316+
{
317+
let tokens = $tokens.as_ref().expect("Expected Some tokens");
318+
let expected_variants = vec![$( stringify!($expected) ),*];
319+
320+
assert_eq!(
321+
tokens.len(),
322+
expected_variants.len(),
323+
"Expected {} tokens, got {}.\nTokens: {:?}",
324+
expected_variants.len(),
325+
tokens.len(),
326+
tokens
327+
);
328+
329+
for (idx, (token, expected_variant)) in tokens.iter().zip(expected_variants.iter()).enumerate() {
330+
let actual_variant = variant_name(token);
331+
assert_eq!(
332+
actual_variant,
333+
*expected_variant,
334+
"Token at index {} does not match: expected {}, got {} (token: {:?})",
335+
idx,
336+
expected_variant,
337+
actual_variant,
338+
token
339+
);
340+
}
341+
}
342+
};
343+
}
344+
260345
#[test]
261346
fn test_if_statement() {
262347
let input = "if true {0} else {1};";
263348
let (tokens, errors) = lex(input);
264349
assert!(errors.is_empty(), "Expected no errors, found: {:?}", errors);
265350

266-
assert_eq!(
267-
tokens,
268-
Some(vec![
269-
Token::If,
270-
Token::Bool(true,),
271-
Token::LBrace,
272-
Token::DecLiteral(Decimal(Arc::new("0"))),
273-
Token::RBrace,
274-
Token::Else,
275-
Token::LBrace,
276-
Token::DecLiteral(Decimal(Arc::new("1"))),
277-
Token::RBrace,
278-
Token::Semi,
279-
])
351+
assert_tokens_match!(
352+
tokens, If, Bool, LBrace, DecLiteral, RBrace, Else, LBrace, DecLiteral, RBrace, Semi,
280353
);
281-
dbg!(tokens);
282-
todo!("Finish");
283354
}
284355

285356
#[test]

src/parse.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,6 +1642,8 @@ impl SingleExpression {
16421642

16431643
let match_expr = Match::parser(expr.clone()).map(SingleExpressionInner::Match);
16441644

1645+
let if_expr = If::parser(expr.clone()).map(SingleExpressionInner::If);
1646+
16451647
let variable = Identifier::parser().map(SingleExpressionInner::Variable);
16461648

16471649
// Expression delimeted by parentheses
@@ -1651,8 +1653,8 @@ impl SingleExpression {
16511653
.map(|es| SingleExpressionInner::Expression(Arc::from(es)));
16521654

16531655
choice((
1654-
left, right, some, none, boolean, match_expr, expression, list, array, tuple, call,
1655-
literal, variable,
1656+
left, right, some, none, boolean, match_expr, if_expr, expression, list, array, tuple,
1657+
call, literal, variable,
16561658
))
16571659
.map_with(|inner, e| Self {
16581660
inner,
@@ -1816,6 +1818,35 @@ impl Match {
18161818
}
18171819
}
18181820

1821+
impl If {
1822+
fn parser<'tokens, 'src: 'tokens, I, E>(
1823+
expr: E,
1824+
) -> impl Parser<'tokens, I, Self, ParseError<'src>> + Clone
1825+
where
1826+
I: ValueInput<'tokens, Token = Token<'src>, Span = Span>,
1827+
E: Parser<'tokens, I, Expression, ParseError<'src>> + Clone + 'tokens,
1828+
{
1829+
let scrutinee = expr.clone().map(Arc::new);
1830+
1831+
let true_arm = expr.clone().map(Arc::new);
1832+
let false_arm = expr.clone().map(Arc::new);
1833+
// let true_arm = delimited_with_recovery(Expression::parser, Token::LBrace, Token::RBrace, |_| None);
1834+
// let false_arm = delimited_with_recovery(Expression::parser, Token::LBrace, Token::RBrace, |_| None);
1835+
1836+
just(Token::If)
1837+
.ignore_then(scrutinee)
1838+
.then(true_arm)
1839+
.then_ignore(just(Token::Else))
1840+
.then(false_arm)
1841+
.map_with(|((s, t), el), extra| Self {
1842+
scrutinee: s,
1843+
then_arm: t,
1844+
else_arm: el,
1845+
span: extra.span(),
1846+
})
1847+
}
1848+
}
1849+
18191850
impl ChumskyParse for ModuleItem {
18201851
fn parser<'tokens, 'src: 'tokens, I>() -> impl Parser<'tokens, I, Self, ParseError<'src>> + Clone
18211852
where
@@ -2212,3 +2243,27 @@ impl crate::ArbitraryRec for Match {
22122243
})
22132244
}
22142245
}
2246+
2247+
#[cfg(test)]
2248+
mod test {
2249+
2250+
use super::*;
2251+
#[test]
2252+
fn test_if_statement_parse() {
2253+
// let input: Arc<str> = "if true {0} else {1};".into();
2254+
let input = "if true {0} else {1}";
2255+
2256+
let statement = Expression::parse_from_str(input).expect("Error");
2257+
2258+
match &statement.inner() {
2259+
ExpressionInner::Single(se) => match se.inner() {
2260+
SingleExpressionInner::If(if_) => {
2261+
dbg!(if_);
2262+
// pass
2263+
}
2264+
_ => panic!("Did not find if statement correctly"),
2265+
},
2266+
_ => panic!("Did not parse correctly"),
2267+
}
2268+
}
2269+
}

0 commit comments

Comments
 (0)