Treeify now handles both left- and right-associative operators

pull/2/head
Mark 2023-03-26 12:13:08 -07:00
parent c92670c918
commit a40ebb7500
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
2 changed files with 239 additions and 230 deletions

View File

@ -52,7 +52,6 @@ pub enum Token {
}
impl Token {
#[inline(always)]
pub fn get_args(&mut self) -> Option<&mut VecDeque<Token>> {
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>) -> 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.

View File

@ -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>) -> 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<Token>
) -> Result<usize, (LineLocation, ParserError)> {
g_inner: &mut VecDeque<Token>,
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<Token>
) -> Result<usize, (LineLocation, ParserError)> {
fn treeify_unary(
i: usize,
g_inner: &mut VecDeque<Token>,
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<Token> = 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<Token>
) -> Result<usize, (LineLocation, ParserError)> {
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<Token> = 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));