refactor: abstract indent/dedent handling to macros

This commit is contained in:
Araozu 2024-06-05 20:45:22 -05:00
parent 457c8f23bb
commit 9685c132c5
3 changed files with 50 additions and 47 deletions

View File

@ -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))
}

View File

@ -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>;

View File

@ -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;
}
};
}