diff --git a/src/parser.rs b/src/parser.rs index 34a35ab..42476cf 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -52,7 +52,6 @@ pub enum Token { } impl Token { - #[inline(always)] pub fn get_args(&mut self) -> Option<&mut VecDeque> { match self { @@ -239,7 +238,78 @@ pub enum Operator { Power, Negative, - Factorial + Factorial, +} + +impl Operator { + #[inline(always)] + pub fn is_binary(&self) -> bool { + match self { + Operator::Negative + | Operator::Factorial + => false, + _ => true + } + } + + #[inline(always)] + pub fn is_left_associative(&self) -> bool { + match self { + Operator::Negative + | Operator::Power + => false, + _ => true + } + } + + #[inline(always)] + pub fn into_token(&self, mut args: VecDeque) -> Token { + match self { + Operator::Add => Token::Add(args), + + Operator::Multiply + | Operator::ImplicitMultiply + => Token::Multiply(args), + + Operator::Subtract => { + if args.len() != 2 { panic!() } + let a = args.pop_front().unwrap(); + let b = args.pop_front().unwrap(); + + Token::Add( + VecDeque::from(vec!( + a, + Token::Negative(VecDeque::from(vec!(b))) + ))) + }, + + Operator::Divide => { + if args.len() != 2 { panic!() } + Token::Divide(args) + }, + + Operator::ModuloLong | + Operator::Modulo => { + if args.len() != 2 { panic!() } + Token::Modulo(args) + }, + + Operator::Power => { + if args.len() != 2 { panic!() } + Token::Power(args) + }, + + Operator::Negative => { + if args.len() != 1 { panic!() } + Token::Negative(args) + }, + + Operator::Factorial => { + if args.len() != 1 { panic!() } + Token::Factorial(args) + } + } + } } /// Specifies the location of a token in an input string. diff --git a/src/parser/treeify.rs b/src/parser/treeify.rs index 67c90af..535f220 100644 --- a/src/parser/treeify.rs +++ b/src/parser/treeify.rs @@ -5,35 +5,11 @@ use crate::parser::LineLocation; use crate::parser::ParserError; use crate::parser::Operator; -#[inline(always)] -fn select_op(k: Operator, mut new_token_args: VecDeque) -> Token { - match k { - Operator::Subtract => { - let a = new_token_args.pop_front().unwrap(); - let b = new_token_args.pop_front().unwrap(); - - Token::Add( - VecDeque::from(vec!( - a, - Token::Negative(VecDeque::from(vec!(b))) - ))) - }, - Operator::Add => Token::Add(new_token_args), - Operator::Divide => Token::Divide(new_token_args), - Operator::Multiply => Token::Multiply(new_token_args), - Operator::ImplicitMultiply => Token::Multiply(new_token_args), - Operator::Modulo => Token::Modulo(new_token_args), - Operator::ModuloLong => Token::Modulo(new_token_args), - Operator::Power => Token::Power(new_token_args), - Operator::Negative => Token::Negative(new_token_args), - Operator::Factorial => Token::Factorial(new_token_args) - } -} - fn treeify_binary( mut i: usize, - g_inner: &mut VecDeque -) -> Result { + g_inner: &mut VecDeque, + left_associative: bool +) -> Result<(), (LineLocation, ParserError)> { let this: &Token = &g_inner[i]; @@ -46,49 +22,50 @@ fn treeify_binary( return Err((*l, ParserError::Syntax)); } - let right: &Token = { - if i < g_inner.len()-1 { - &g_inner[i+1] - } else { - let l = match this { - Token::PreOperator(l, _) => l, - _ => panic!() - }; - return Err((*l, ParserError::Syntax)); - } - }; - - - if let Token::PreOperator(l, o) = right { - match o { - // Binary operators - Operator::ModuloLong | - Operator::Subtract | - Operator::Add | - Operator::Divide | - Operator::Multiply | - Operator::ImplicitMultiply | - Operator::Modulo | - Operator::Power | - // Right unary operators - Operator::Factorial - => { - // Binary and right-unary operators cannot - // follow a binary operator. - let tl = *this.get_line_location(); - return Err(( - LineLocation{pos: tl.pos, len: l.pos - tl.pos + l.len}, - ParserError::Syntax - )); - }, - - // Left unary operators - Operator::Negative => { - i += 1; - return Ok(i); + let next: &Token; + if left_associative { + next = { + if i < g_inner.len()-1 { + &g_inner[i+1] + } else { + let l = match this { + Token::PreOperator(l, _) => l, + _ => panic!() + }; + return Err((*l, ParserError::Syntax)); } }; } else { + next = { + if i > 0 { + &g_inner[i-1] + } else { + let l = match this { + Token::PreOperator(l, _) => l, + _ => panic!() + }; + return Err((*l, ParserError::Syntax)); + } + }; + } + + + + if let Token::PreOperator(l, o) = next { + if { + (!o.is_binary()) && + !(o.is_left_associative() && left_associative) + } { + // Only right-associative unary operators can follow a binary operator + return Ok(()); + } else { + let tl = *this.get_line_location(); + return Err(( + LineLocation{pos: tl.pos, len: l.pos - tl.pos + l.len}, + ParserError::Syntax + )); + } + } else { // Precedence of this operator let this_val: isize = match this { @@ -96,7 +73,13 @@ fn treeify_binary( _ => panic!() }; - // Precedence of the operator contesting the right argument. + // Precedence of the operators contesting our arguments + let left_val = if i > 1 { + match &g_inner[i-2] { + Token::PreOperator(_, q) => Some(*q as isize), + _ => panic!() + } + } else { None }; let right_val = if i < g_inner.len()-2 { match &g_inner[i+2] { Token::PreOperator(_, q) => Some(*q as isize), @@ -104,8 +87,10 @@ fn treeify_binary( } } else { None }; - - if right_val.is_none() || this_val > right_val.unwrap() { + if { + (left_val.is_none() || this_val >= left_val.unwrap()) && + (right_val.is_none() || this_val >= right_val.unwrap()) + } { // This operator has higher precedence, it takes both arguments let mut left = g_inner.remove(i-1).unwrap(); let this = g_inner.remove(i-1).unwrap(); @@ -122,140 +107,63 @@ fn treeify_binary( new_token_args.push_back(left); new_token_args.push_back(right); - g_inner.insert(i-1, select_op(k, new_token_args)); + g_inner.insert(i-1, k.into_token(new_token_args)); - if i > 1 { i -= 2; } else { i = 0; } - return Ok(i); + return Ok(()); } else { - // The operator to the right has higher precedence. - // Move on, don't to anything yet. - i += 2; - return Ok(i); + return Ok(()); }; }; } -fn treeify_unaryleft( - mut i: usize, - g_inner: &mut VecDeque -) -> Result { +fn treeify_unary( + i: usize, + g_inner: &mut VecDeque, + left_associative: bool +) -> Result<(), (LineLocation, ParserError)> { let this: &Token = &g_inner[i]; - let right: &Token = { - if i < g_inner.len()-1 { - &g_inner[i+1] - } else { - let l = match this { - Token::PreOperator(l, _) => l, - _ => panic!() - }; - return Err((*l, ParserError::Syntax)); - } - }; - - - if let Token::PreOperator(l, o) = right { - match o { - // Binary operators - Operator::ModuloLong | - Operator::Subtract | - Operator::Add | - Operator::Divide | - Operator::Multiply | - Operator::ImplicitMultiply | - Operator::Modulo | - Operator::Power | - // Right unary operators - Operator::Factorial - => { - // Binary and right-unary operators cannot - // follow a binary operator. - let tl = *this.get_line_location(); - return Err(( - LineLocation{pos: tl.pos, len: l.pos - tl.pos + l.len}, - ParserError::Syntax - )); - }, - - // Left unary operators - Operator::Negative => { - i += 1; - return Ok(i); + let next: &Token; + if left_associative { + next = { + if i > 0 { + &g_inner[i-1] + } else { + let l = match this { + Token::PreOperator(l, _) => l, + _ => panic!() + }; + return Err((*l, ParserError::Syntax)); } }; } else { - - // Precedence of this operator - let this_val: isize = match this { - Token::PreOperator(_, q) => *q as isize, - _ => panic!() - }; - - // Precedence of the operator contesting its argument - let right_val = if i < g_inner.len()-2 { - match &g_inner[i+2] { - Token::PreOperator(_, q) => Some(*q as isize), - _ => panic!() + next = { + if i < g_inner.len()-1 { + &g_inner[i+1] + } else { + let l = match this { + Token::PreOperator(l, _) => l, + _ => panic!() + }; + return Err((*l, ParserError::Syntax)); } - } else { None }; - - - if right_val.is_none() || this_val > right_val.unwrap() { - let this = g_inner.remove(i).unwrap(); - let mut right = g_inner.remove(i).unwrap(); - if let Token::PreGroup(_, _) = right { right = p_treeify(right)?; } - - let k = match this { - Token::PreOperator(_, k) => k, - _ => panic!() - }; - - let mut new_token_args: VecDeque = VecDeque::with_capacity(3); - new_token_args.push_back(right); - - g_inner.insert(i, select_op(k, new_token_args)); - - if i > 0 { i -= 1; } else { i = 0; } - return Ok(i); - } else { - // The operator to the right has higher precedence. - // Move on, don't to anything yet. - i += 2; - return Ok(i); }; - }; -} + } -fn treeify_unaryright( - mut i: usize, - g_inner: &mut VecDeque -) -> Result { - - let this: &Token = &g_inner[i]; - let left: &Token = { - if i > 0 { - &g_inner[i-1] - } else { - let l = match this { - Token::PreOperator(l, _) => l, - _ => panic!() - }; - return Err((*l, ParserError::Syntax)); - } - }; - - - // We need to check the element after unary right operators too. + // We need to check the element after unary operators too. // Bad syntax like `3!3` won't be caught otherwise. - let right: Option<&Token> = { - if i < g_inner.len()-1 { - Some(&g_inner[i+1]) - } else {None} - }; + let prev: Option<&Token>; + if left_associative { + prev = if i < g_inner.len()-1 { Some(&g_inner[i+1]) } else {None}; - if right.is_some() { - if let Token::PreOperator(l, o) = right.unwrap() { + } else { + prev = if i > 0 { Some(&g_inner[i-1]) } else {None}; + + } + + if prev.is_some() { + if let Token::PreOperator(l, o) = prev.unwrap() { match o { // Left unary operators Operator::Negative => { @@ -275,13 +183,14 @@ fn treeify_unaryright( } } - if let Token::PreOperator(l, _) = left { + + + if let Token::PreOperator(l, _) = next { let tl = *this.get_line_location(); return Err(( LineLocation{pos: tl.pos, len: l.pos - tl.pos + l.len}, ParserError::Syntax )); - } else { // Precedence of this operator @@ -290,19 +199,32 @@ fn treeify_unaryright( _ => panic!() }; - // Precedence of the operator contesting its argument. - let left_val = if i >= 2 { - match &g_inner[i-2] { - Token::PreOperator(_, q) => Some(*q as isize), - _ => panic!() - } - } else { None }; + // Precedence of the operator contesting its argument + let next_val = if left_associative { + if i > 1 { + match &g_inner[i-2] { + Token::PreOperator(_, q) => Some(*q as isize), + _ => panic!() + } + } else { None } + } else { + if i < g_inner.len()-2 { + match &g_inner[i+2] { + Token::PreOperator(_, q) => Some(*q as isize), + _ => panic!() + } + } else { None } + }; - - if left_val.is_none() || this_val > left_val.unwrap() { + if next_val.is_none() || this_val > next_val.unwrap() { let this = g_inner.remove(i).unwrap(); - let mut left = g_inner.remove(i-1).unwrap(); - if let Token::PreGroup(_, _) = left { left = p_treeify(left)?; } + let mut next; + if left_associative { + next = g_inner.remove(i-1).unwrap(); + } else { + next = g_inner.remove(i).unwrap(); + } + if let Token::PreGroup(_, _) = next { next = p_treeify(next)?; } let k = match this { Token::PreOperator(_, k) => k, @@ -310,17 +232,19 @@ fn treeify_unaryright( }; let mut new_token_args: VecDeque = VecDeque::with_capacity(3); - new_token_args.push_back(left); + new_token_args.push_back(next); - g_inner.insert(i-1, select_op(k, new_token_args)); + if left_associative { + g_inner.insert(i-1, k.into_token(new_token_args)); + } else { + g_inner.insert(i, k.into_token(new_token_args)); + } - if i > 2 { i -= 2; } else { i = 0; } - return Ok(i); + return Ok(()); } else { // The operator to the right has higher precedence. // Move on, don't to anything yet. - i += 1; - return Ok(i); + return Ok(()); }; }; } @@ -334,37 +258,52 @@ pub fn p_treeify( _ => panic!() }; - let mut i: usize = 0; + let mut left_associative = true; + let mut j: i64 = 0; while g_inner.len() > 1 { + + + if j <= -1 { + left_associative = true; + j = 0; + } else if j >= g_inner.len() as i64 { + left_associative = false; + j = (g_inner.len() - 1) as i64; + } + + let i = j as usize; let this_op = match &g_inner[i] { Token::PreOperator(_, o) => o, - _ => { i+=1; continue; } + _ => { + if left_associative { j += 1 } else { j -= 1 }; + continue; + } }; - match this_op { - Operator::ModuloLong | - Operator::Subtract | - Operator::Add | - Operator::Divide | - Operator::Multiply | - Operator::ImplicitMultiply | - Operator::Modulo | - Operator::Power - => { i = treeify_binary(i, g_inner)?; }, - - Operator::Negative - => { i = treeify_unaryleft(i, g_inner)?; }, - - Operator::Factorial - => { i = treeify_unaryright(i, g_inner)?; } - - }; + if left_associative { + if this_op.is_left_associative() { + if this_op.is_binary() { + treeify_binary(i, g_inner, left_associative)?; + } else { + treeify_unary(i, g_inner, left_associative)?; + } + } + j += 1 + } else { + if !this_op.is_left_associative() { + if this_op.is_binary() { + treeify_binary(i, g_inner, left_associative)?; + } else { + treeify_unary(i, g_inner, left_associative)?; + } + } + j -= 1 + } } g = g_inner.pop_front().unwrap(); - // Catch the edge case where the entire group we're given - // consists of one operator. This is always a syntax error. + // Catch edge cases match g { Token::PreOperator(l, _) => { return Err((l, ParserError::Syntax));