refactor: parse indentation on comparison

master
Araozu 2024-06-15 16:28:23 -05:00
parent be8c16ccf0
commit fa14439507
4 changed files with 115 additions and 11 deletions

View File

@ -31,6 +31,7 @@
- [x] Begin work on a formal grammar - [x] Begin work on a formal grammar
- [x] Simplify/rewrite AST - [x] Simplify/rewrite AST
- [ ] Properly parse expression indentation/dedentation
- [x] Define the top level constructs - [x] Define the top level constructs
- [ ] Include the original tokens in the AST - [ ] Include the original tokens in the AST
- [ ] Finish the workflow for a hello world - [ ] Finish the workflow for a hello world

View File

@ -1,4 +1,6 @@
use crate::lexic::token::TokenType;
use crate::{ use crate::{
handle_dedentation, handle_indentation,
lexic::token::Token, lexic::token::Token,
syntax::{ast::Expression, ParsingError, ParsingResult}, syntax::{ast::Expression, ParsingError, ParsingResult},
}; };
@ -14,24 +16,36 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
_ => return Err(ParsingError::Unmatched), _ => return Err(ParsingError::Unmatched),
}; };
parse_many(tokens, next_pos, term) parse_many(tokens, next_pos, term, 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>> {
// comparison = term, ((">" | ">=" | "<" | "<="), term)*; // comparison = term, ((">" | ">=" | "<" | "<="), term)*;
match tokens.get(pos) { let mut indent_count: u32 = 0;
let mut next_pos = pos;
// Handle possible indentation before binary operator
handle_indentation!(tokens, next_pos, indent_count, indentation_level);
let result = match tokens.get(next_pos) {
Some(token) Some(token)
if token.value == "<" if token.value == "<"
|| token.value == "<=" || token.value == "<="
|| token.value == ">" || token.value == ">"
|| token.value == ">=" => || token.value == ">=" =>
{ {
match super::term::try_parse(tokens, pos + 1) { next_pos += 1;
// Handle possible indentation after binary operator
handle_indentation!(tokens, next_pos, indent_count, indentation_level);
match super::term::try_parse(tokens, next_pos) {
Ok((expr, next_pos)) => { Ok((expr, next_pos)) => {
let expr = Expression::BinaryOperator( let expr = Expression::BinaryOperator(
Box::new(prev_expr), Box::new(prev_expr),
@ -39,13 +53,22 @@ fn parse_many<'a>(
&token.value, &token.value,
); );
parse_many(tokens, next_pos, expr) parse_many(tokens, next_pos, expr, indentation_level + indent_count)
} }
_ => Err(ParsingError::Unmatched), _ => return Err(ParsingError::Unmatched),
} }
} }
_ => Ok((prev_expr, pos)), _ => return Ok((prev_expr, pos)),
} };
let (new_expr, mut next_pos) = match result {
Ok((e, n)) => (e, n),
_ => return result,
};
handle_dedentation!(tokens, next_pos, indent_count);
Ok((new_expr, next_pos))
} }
#[cfg(test)] #[cfg(test)]
@ -88,4 +111,80 @@ mod tests {
_ => panic!("Expected an Unmatched error"), _ => panic!("Expected an Unmatched error"),
} }
} }
#[test]
fn should_parse_indented_1() {
let tokens = get_tokens(&String::from("a\n >= b")).unwrap();
let (result, next) = try_parse(&tokens, 0).unwrap();
assert_eq!(tokens[5].token_type, TokenType::DEDENT);
assert_eq!(next, 6);
match result {
Expression::BinaryOperator(_, _, op) => {
assert_eq!(op, ">=")
}
_ => panic!("Expected a binary operator"),
}
}
#[test]
fn should_parse_indented_2() {
let tokens = get_tokens(&String::from("a\n <= b\n <= c")).unwrap();
let (result, next) = try_parse(&tokens, 0).unwrap();
assert_eq!(next, 11);
match result {
Expression::BinaryOperator(_, _, op) => {
assert_eq!(op, "<=")
}
_ => panic!("Expected a binary operator"),
}
}
#[test]
fn should_parse_indented_3() {
let tokens = get_tokens(&String::from("a\n <= b <= c")).unwrap();
let (result, next) = try_parse(&tokens, 0).unwrap();
assert_eq!(tokens[7].token_type, TokenType::DEDENT);
assert_eq!(next, 8);
match result {
Expression::BinaryOperator(_, _, op) => {
assert_eq!(op, "<=")
}
_ => 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!(next, 9);
match result {
Expression::BinaryOperator(_, _, op) => {
assert_eq!(op, "<=")
}
_ => panic!("Expected a binary operator"),
}
}
#[test]
fn should_parse_indented_5() {
let tokens = get_tokens(&String::from("a >=\n b")).unwrap();
let (result, next) = try_parse(&tokens, 0).unwrap();
assert_eq!(next, 6);
match result {
Expression::BinaryOperator(_, _, op) => {
assert_eq!(op, ">=")
}
_ => panic!("Expected a binary operator"),
}
}
} }

View File

@ -1,5 +1,7 @@
use crate::{ use crate::{
handle_dedentation, handle_indentation, lexic::token::{Token, TokenType}, syntax::{ast::Expression, ParsingError, ParsingResult} handle_dedentation, handle_indentation,
lexic::token::{Token, TokenType},
syntax::{ast::Expression, ParsingError, ParsingResult},
}; };
/// Parses a factor expression. /// Parses a factor expression.
@ -33,7 +35,7 @@ fn parse_many<'a>(
let result = match tokens.get(next_pos) { let result = match tokens.get(next_pos) {
Some(token) if token.value == "==" || token.value == "!=" => { Some(token) if token.value == "==" || token.value == "!=" => {
next_pos += 1; next_pos += 1;
// Handle possible indentation after binary operator // Handle possible indentation after binary operator
handle_indentation!(tokens, next_pos, indent_count, indentation_level); handle_indentation!(tokens, next_pos, indent_count, indentation_level);
@ -52,7 +54,7 @@ fn parse_many<'a>(
} }
_ => return Ok((prev_expr, pos)), _ => return Ok((prev_expr, pos)),
}; };
let (new_expr, mut next_pos) = match result { let (new_expr, mut next_pos) = match result {
Ok((e, n)) => (e, n), Ok((e, n)) => (e, n),
_ => return result, _ => return result,

View File

@ -1,5 +1,7 @@
use crate::{ use crate::{
handle_dedentation, handle_indentation, lexic::token::{Token, TokenType}, syntax::{ast::Expression, ParsingError, ParsingResult} handle_dedentation, handle_indentation,
lexic::token::{Token, TokenType},
syntax::{ast::Expression, ParsingError, ParsingResult},
}; };
/// Parses a factor expression. /// Parses a factor expression.