From 9685c132c5d68f41172c6f80563fb4f994cf67fc Mon Sep 17 00:00:00 2001 From: Araozu Date: Wed, 5 Jun 2024 20:45:22 -0500 Subject: [PATCH] refactor: abstract indent/dedent handling to macros --- src/syntax/parsers/expression/factor.rs | 53 +++---------------------- src/syntax/parsers/expression/mod.rs | 1 + src/syntax/parsers/expression/utils.rs | 43 ++++++++++++++++++++ 3 files changed, 50 insertions(+), 47 deletions(-) create mode 100644 src/syntax/parsers/expression/utils.rs diff --git a/src/syntax/parsers/expression/factor.rs b/src/syntax/parsers/expression/factor.rs index ac0b3b2..1ab51cc 100644 --- a/src/syntax/parsers/expression/factor.rs +++ b/src/syntax/parsers/expression/factor.rs @@ -1,6 +1,5 @@ use crate::{ - lexic::token::{Token, TokenType}, - syntax::{ast::Expression, utils::Tokenizer, ParsingError, ParsingResult}, + handle_dedentation, handle_indentation, lexic::token::{Token, TokenType}, syntax::{ast::Expression, ParsingError, ParsingResult} }; /// Parses a factor expression. @@ -27,47 +26,17 @@ fn parse_many<'a>( let mut indent_count: u32 = 0; - // Handle possible indentation before binary operator let mut next_pos = pos; - match (tokens.get(next_pos), tokens.get(next_pos + 1)) { - // New indentation level - (Some(t1), Some(t2)) - if t1.token_type == TokenType::NewLine && t2.token_type == TokenType::INDENT => - { - // set indentation - next_pos += 2; - indent_count += 1; - } - // we are indented, ignore newlines - (Some(t), _) if t.token_type == TokenType::NewLine && indentation_level > 0 => { - next_pos += 1; - } - // let other handlers handle this - _ => {} - }; + + // Handle possible indentation before binary operator + handle_indentation!(tokens, next_pos, indent_count, indentation_level); let result = match tokens.get(next_pos) { Some(token) if token.value == "/" || token.value == "*" => { next_pos += 1; // Handle possible indentation after binary operator - match (tokens.get(next_pos), tokens.get(next_pos + 1)) { - // New indentation level - (Some(t1), Some(t2)) - if t1.token_type == TokenType::NewLine - && t2.token_type == TokenType::INDENT => - { - // set indentation - next_pos += 2; - indent_count += 1; - } - // we are indented, ignore newlines - (Some(t), _) if t.token_type == TokenType::NewLine && indentation_level > 0 => { - next_pos += 1; - } - // let other handlers handle this - _ => {} - }; + handle_indentation!(tokens, next_pos, indent_count, indentation_level); match super::unary::try_parse(tokens, next_pos) { Ok((expr, next_pos)) => { @@ -90,17 +59,7 @@ fn parse_many<'a>( _ => return result, }; - for _ in 0..indent_count { - // Expect a DEDENT for each indentation matched - match tokens.get(next_pos) { - // continue - Some(t) if t.token_type == TokenType::DEDENT => {} - // This should be unreachable, as the lexer always emits a DEDENT for each INDENT - _ => unreachable!("Illegal parser state: Expected DEDENT (count: {})", indent_count), - }; - - next_pos += 1; - } + handle_dedentation!(tokens, next_pos, indent_count); Ok((new_expr, next_pos)) } diff --git a/src/syntax/parsers/expression/mod.rs b/src/syntax/parsers/expression/mod.rs index fccf8b8..d3b1923 100644 --- a/src/syntax/parsers/expression/mod.rs +++ b/src/syntax/parsers/expression/mod.rs @@ -8,6 +8,7 @@ pub mod function_call_expr; mod primary; mod term; mod unary; +mod utils; impl<'a> Parseable<'a> for Expression<'a> { type Item = Expression<'a>; diff --git a/src/syntax/parsers/expression/utils.rs b/src/syntax/parsers/expression/utils.rs new file mode 100644 index 0000000..38b99d8 --- /dev/null +++ b/src/syntax/parsers/expression/utils.rs @@ -0,0 +1,43 @@ +/// macro for handling indentation in expressions +#[macro_export] +macro_rules! handle_indentation { + ($tokens: ident, $next_pos: ident, $indent_count: ident, $indentation_level: ident) => { + match ($tokens.get($next_pos), $tokens.get($next_pos + 1)) { + // New indentation level + (Some(t1), Some(t2)) + if t1.token_type == TokenType::NewLine && t2.token_type == TokenType::INDENT => + { + // set indentation + $next_pos += 2; + $indent_count += 1; + } + // we are indented, ignore newlines + (Some(t), _) if t.token_type == TokenType::NewLine && $indentation_level > 0 => { + $next_pos += 1; + } + // let other handlers handle this + _ => {} + }; + }; +} + +/// macro for handling dedentation in expressions +#[macro_export] +macro_rules! handle_dedentation { + ($tokens: ident, $next_pos: ident, $indent_count: ident) => { + for _ in 0..$indent_count { + // Expect a DEDENT for each indentation matched + match $tokens.get($next_pos) { + // continue + Some(t) if t.token_type == TokenType::DEDENT => {} + // This should be unreachable, as the lexer always emits a DEDENT for each INDENT + _ => unreachable!( + "Illegal parser state: Expected DEDENT (count: {})", + $indent_count + ), + }; + + $next_pos += 1; + } + }; +}