refactor: new strategy to handle indentation around binary op
This commit is contained in:
parent
56ea63cf8c
commit
d08019c010
@ -1,4 +1,5 @@
|
||||
use crate::lexic::token::TokenType;
|
||||
use crate::syntax::parsers::expression::utils::try_binary_op;
|
||||
use crate::{
|
||||
handle_dedentation, handle_indentation,
|
||||
lexic::token::Token,
|
||||
@ -27,33 +28,21 @@ fn parse_many<'a>(
|
||||
) -> ParsingResult<'a, Expression<'a>> {
|
||||
// term = factor, (("-" | "+"), factor)*;
|
||||
|
||||
let mut indent_count: u32 = 0;
|
||||
let mut next_pos = pos;
|
||||
let (token, next_pos, indent_count) =
|
||||
match try_binary_op(tokens, pos, vec!["+", "-"], indentation_level) {
|
||||
Some(t) => t,
|
||||
None => return Ok((prev_expr, 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) if token.value == "+" || token.value == "-" => {
|
||||
next_pos += 1;
|
||||
|
||||
// Handle possible indentation after binary operator
|
||||
handle_indentation!(tokens, next_pos, indent_count, indentation_level);
|
||||
|
||||
match super::factor::try_parse(tokens, next_pos) {
|
||||
// Parse the next factor
|
||||
let result = match super::factor::try_parse(tokens, next_pos) {
|
||||
Ok((expr, next_pos)) => {
|
||||
let expr = Expression::BinaryOperator(
|
||||
Box::new(prev_expr),
|
||||
Box::new(expr),
|
||||
&token.value,
|
||||
);
|
||||
let expr =
|
||||
Expression::BinaryOperator(Box::new(prev_expr), Box::new(expr), &token.value);
|
||||
|
||||
parse_many(tokens, next_pos, expr, indentation_level + indent_count)
|
||||
}
|
||||
_ => return Err(ParsingError::Unmatched),
|
||||
}
|
||||
}
|
||||
_ => return Ok((prev_expr, pos)),
|
||||
};
|
||||
|
||||
let (new_expr, mut next_pos) = match result {
|
||||
|
@ -1,3 +1,57 @@
|
||||
use crate::lexic::token::Token;
|
||||
use crate::lexic::token::TokenType::{NewLine, INDENT};
|
||||
|
||||
/// Attempts to parse a binary operator and handles indentation
|
||||
///
|
||||
/// Binary operators may be in a new line as long as they are indented.
|
||||
/// The new line may be before or after the operator.
|
||||
///
|
||||
/// Once an operator is indented, all following operators completely disregard newline/indentation
|
||||
/// until a matching dedent is found.
|
||||
pub fn try_binary_op<'a>(
|
||||
tokens: &'a Vec<Token>,
|
||||
pos: usize,
|
||||
operators: Vec<&str>,
|
||||
indentation_level: u32,
|
||||
) -> Option<(&'a Token, usize, u32)> {
|
||||
let mut indent_count = 0;
|
||||
|
||||
// handle possible opening indentation
|
||||
let pos = match (tokens.get(pos), tokens.get(pos + 1)) {
|
||||
// New indentation level
|
||||
(Some(t1), Some(t2)) if t1.token_type == NewLine && t2.token_type == INDENT => {
|
||||
indent_count += 1;
|
||||
pos + 2
|
||||
}
|
||||
// when indented, ignore newlines
|
||||
(Some(t), _) if t.token_type == NewLine && indentation_level > 0 => pos + 1,
|
||||
// let other handlers handle this
|
||||
_ => pos,
|
||||
};
|
||||
|
||||
// try to parse binary operator
|
||||
let (matched_token, pos) = match tokens.get(pos) {
|
||||
Some(token) if operators.contains(&token.value.as_str()) => (token, pos + 1),
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
// handle possible closing indentation
|
||||
let pos = match (tokens.get(pos), tokens.get(pos + 1)) {
|
||||
// New indentation level
|
||||
(Some(t1), Some(t2)) if t1.token_type == NewLine && t2.token_type == INDENT => {
|
||||
indent_count += 1;
|
||||
pos + 2
|
||||
}
|
||||
// when indented, ignore newlines
|
||||
(Some(t), _) if t.token_type == NewLine && indentation_level > 0 => pos + 1,
|
||||
// let other handlers handle this
|
||||
_ => pos,
|
||||
};
|
||||
|
||||
// return the matched token, next position and new indentation level
|
||||
Some((matched_token, pos, indent_count))
|
||||
}
|
||||
|
||||
/// macro for handling indentation in expressions
|
||||
#[macro_export]
|
||||
macro_rules! handle_indentation {
|
||||
|
@ -31,6 +31,7 @@ impl Tokenizer for Vec<Token> {
|
||||
}
|
||||
}
|
||||
|
||||
// unused? remove?
|
||||
fn get_indented<'a>(&'a self, index: usize, indented: bool) -> (Option<&'a Token>, usize) {
|
||||
if !indented {
|
||||
return (self.get(index), index + 1);
|
||||
|
Loading…
Reference in New Issue
Block a user