feat: handle indent/dedent in == parsing

master
Araozu 2024-06-05 12:05:32 -05:00
parent d568114349
commit 4d9c7fae3e
1 changed files with 58 additions and 34 deletions

View File

@ -15,17 +15,19 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
_ => return Err(ParsingError::Unmatched), _ => return Err(ParsingError::Unmatched),
}; };
parse_many(tokens, next_pos, comparison) parse_many(tokens, next_pos, comparison, 0)
} }
fn parse_many<'a>( fn parse_many<'a>(
tokens: &'a Vec<Token>, tokens: &'a Vec<Token>,
pos: usize, pos: usize,
prev_expr: Expression<'a>, prev_expr: Expression<'a>,
indentation_level: u32,
) -> ParsingResult<'a, Expression<'a>> { ) -> ParsingResult<'a, Expression<'a>> {
// equality = comparison, (("==" | "!="), comparison )*; // equality = comparison, (("==" | "!="), comparison )*;
match tokens.get(pos) { let mut indented = false;
let result = match tokens.get(pos) {
Some(token) if token.value == "==" || token.value == "!=" => { Some(token) if token.value == "==" || token.value == "!=" => {
match super::comparison::try_parse(tokens, pos + 1) { match super::comparison::try_parse(tokens, pos + 1) {
Ok((expr, next_pos)) => { Ok((expr, next_pos)) => {
@ -35,42 +37,49 @@ fn parse_many<'a>(
&token.value, &token.value,
); );
parse_many(tokens, next_pos, expr) parse_many(tokens, next_pos, expr, indentation_level)
} }
_ => Err(ParsingError::Unmatched), _ => return Err(ParsingError::Unmatched),
} }
} }
// If token is a newline: check if the following token is INDENT. // Handle indentation
// If so, ignore those 2 and continue parsing
// Then, we should find a DEDENT token to finish this expression?
Some(token) if token.token_type == TokenType::NewLine => { Some(token) if token.token_type == TokenType::NewLine => {
match tokens.get(pos + 1) { let next_tok = match tokens.get(pos + 1) {
Some(t) if t.token_type == TokenType::INDENT => { Some(t) => t,
// Ignore indentation and continue parsing None => return Ok((prev_expr, pos)),
let result = parse_many(tokens, pos + 2, prev_expr); };
// Expect a DEDENT token let next_is_indent = next_tok.token_type == TokenType::INDENT;
match result {
Ok((expr, next)) => { if next_is_indent {
match tokens.get(next) { // increase indentation level and continue parsing
Some(t) if t.token_type == TokenType::DEDENT => { indented = true;
Ok((expr, next + 1)) parse_many(tokens, pos + 2, prev_expr, indentation_level + 1)
} } else if indentation_level > 0 {
_ => unreachable!("Invalid parser state: expected a DEDENT after parsing an indented expression") // ignore the newline, as we are indented
} parse_many(tokens, pos + 1, prev_expr, indentation_level)
} } else {
_ => result Ok((prev_expr, pos))
}
}
_ => {
// Return current parsed value
return Ok((prev_expr, pos));
}
} }
} }
_ => Ok((prev_expr, pos)), _ => Ok((prev_expr, pos)),
};
let (new_expr, next_pos) = match result {
Ok((e, n)) => (e, n),
_ => return result,
};
// Here expect dedents if there are any
if indented {
match tokens.get(next_pos) {
Some(t) if t.token_type == TokenType::DEDENT => return Ok((new_expr, next_pos + 1)),
_ => panic!("Expected DEDENT"),
} }
} }
Ok((new_expr, next_pos))
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -123,8 +132,8 @@ mod tests {
match result { match result {
Expression::BinaryOperator(_, _, op) => { Expression::BinaryOperator(_, _, op) => {
assert_eq!(op, "==") assert_eq!(op, "==")
}, }
_ => panic!("Expected a binary operator") _ => panic!("Expected a binary operator"),
} }
} }
@ -140,8 +149,8 @@ mod tests {
match result { match result {
Expression::BinaryOperator(_, _, op) => { Expression::BinaryOperator(_, _, op) => {
assert_eq!(op, "==") assert_eq!(op, "==")
}, }
_ => panic!("Expected a binary operator") _ => panic!("Expected a binary operator"),
} }
} }
@ -156,9 +165,24 @@ mod tests {
match result { match result {
Expression::BinaryOperator(_, _, op) => { Expression::BinaryOperator(_, _, op) => {
assert_eq!(op, "==") assert_eq!(op, "==")
}, }
_ => panic!("Expected a binary operator") _ => panic!("Expected a binary operator"),
} }
} }
#[test]
fn should_parse_indented_4() {
let tokens = get_tokens(&String::from("a\n == b\n == c")).unwrap();
let (result, next) = try_parse(&tokens, 0).unwrap();
assert_eq!(tokens[8].token_type, TokenType::DEDENT);
assert_eq!(next, 9);
match result {
Expression::BinaryOperator(_, _, op) => {
assert_eq!(op, "==")
}
_ => panic!("Expected a binary operator"),
}
}
} }