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 { impl Token {
#[inline(always)] #[inline(always)]
pub fn get_args(&mut self) -> Option<&mut VecDeque<Token>> { pub fn get_args(&mut self) -> Option<&mut VecDeque<Token>> {
match self { match self {
@ -239,7 +238,78 @@ pub enum Operator {
Power, Power,
Negative, 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. /// 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::ParserError;
use crate::parser::Operator; 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( fn treeify_binary(
mut i: usize, mut i: usize,
g_inner: &mut VecDeque<Token> g_inner: &mut VecDeque<Token>,
) -> Result<usize, (LineLocation, ParserError)> { left_associative: bool
) -> Result<(), (LineLocation, ParserError)> {
let this: &Token = &g_inner[i]; let this: &Token = &g_inner[i];
@ -46,49 +22,50 @@ fn treeify_binary(
return Err((*l, ParserError::Syntax)); return Err((*l, ParserError::Syntax));
} }
let right: &Token = { let next: &Token;
if i < g_inner.len()-1 { if left_associative {
&g_inner[i+1] next = {
} else { if i < g_inner.len()-1 {
let l = match this { &g_inner[i+1]
Token::PreOperator(l, _) => l, } else {
_ => panic!() let l = match this {
}; Token::PreOperator(l, _) => l,
return Err((*l, ParserError::Syntax)); _ => 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);
} }
}; };
} else { } 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 // Precedence of this operator
let this_val: isize = match this { let this_val: isize = match this {
@ -96,7 +73,13 @@ fn treeify_binary(
_ => panic!() _ => 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 { let right_val = if i < g_inner.len()-2 {
match &g_inner[i+2] { match &g_inner[i+2] {
Token::PreOperator(_, q) => Some(*q as isize), Token::PreOperator(_, q) => Some(*q as isize),
@ -104,8 +87,10 @@ fn treeify_binary(
} }
} else { None }; } else { None };
if {
if right_val.is_none() || this_val > right_val.unwrap() { (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 // This operator has higher precedence, it takes both arguments
let mut left = g_inner.remove(i-1).unwrap(); let mut left = g_inner.remove(i-1).unwrap();
let this = 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(left);
new_token_args.push_back(right); 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(());
return Ok(i);
} else { } else {
// The operator to the right has higher precedence. return Ok(());
// Move on, don't to anything yet.
i += 2;
return Ok(i);
}; };
}; };
} }
fn treeify_unaryleft( fn treeify_unary(
mut i: usize, i: usize,
g_inner: &mut VecDeque<Token> g_inner: &mut VecDeque<Token>,
) -> Result<usize, (LineLocation, ParserError)> { left_associative: bool
) -> Result<(), (LineLocation, ParserError)> {
let this: &Token = &g_inner[i]; let this: &Token = &g_inner[i];
let right: &Token = { let next: &Token;
if i < g_inner.len()-1 { if left_associative {
&g_inner[i+1] next = {
} else { if i > 0 {
let l = match this { &g_inner[i-1]
Token::PreOperator(l, _) => l, } else {
_ => panic!() let l = match this {
}; Token::PreOperator(l, _) => l,
return Err((*l, ParserError::Syntax)); _ => 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);
} }
}; };
} else { } else {
next = {
// Precedence of this operator if i < g_inner.len()-1 {
let this_val: isize = match this { &g_inner[i+1]
Token::PreOperator(_, q) => *q as isize, } else {
_ => panic!() let l = match this {
}; Token::PreOperator(l, _) => l,
_ => panic!()
// Precedence of the operator contesting its argument };
let right_val = if i < g_inner.len()-2 { return Err((*l, ParserError::Syntax));
match &g_inner[i+2] {
Token::PreOperator(_, q) => Some(*q as isize),
_ => panic!()
} }
} 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( // We need to check the element after unary operators too.
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.
// Bad syntax like `3!3` won't be caught otherwise. // Bad syntax like `3!3` won't be caught otherwise.
let right: Option<&Token> = { let prev: Option<&Token>;
if i < g_inner.len()-1 { if left_associative {
Some(&g_inner[i+1]) prev = if i < g_inner.len()-1 { Some(&g_inner[i+1]) } else {None};
} else {None}
};
if right.is_some() { } else {
if let Token::PreOperator(l, o) = right.unwrap() { 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 { match o {
// Left unary operators // Left unary operators
Operator::Negative => { 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(); let tl = *this.get_line_location();
return Err(( return Err((
LineLocation{pos: tl.pos, len: l.pos - tl.pos + l.len}, LineLocation{pos: tl.pos, len: l.pos - tl.pos + l.len},
ParserError::Syntax ParserError::Syntax
)); ));
} else { } else {
// Precedence of this operator // Precedence of this operator
@ -290,19 +199,32 @@ fn treeify_unaryright(
_ => panic!() _ => panic!()
}; };
// Precedence of the operator contesting its argument. // Precedence of the operator contesting its argument
let left_val = if i >= 2 { let next_val = if left_associative {
match &g_inner[i-2] { if i > 1 {
Token::PreOperator(_, q) => Some(*q as isize), match &g_inner[i-2] {
_ => panic!() Token::PreOperator(_, q) => Some(*q as isize),
} _ => panic!()
} else { None }; }
} 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 next_val.is_none() || this_val > next_val.unwrap() {
if left_val.is_none() || this_val > left_val.unwrap() {
let this = g_inner.remove(i).unwrap(); let this = g_inner.remove(i).unwrap();
let mut left = g_inner.remove(i-1).unwrap(); let mut next;
if let Token::PreGroup(_, _) = left { left = p_treeify(left)?; } 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 { let k = match this {
Token::PreOperator(_, k) => k, Token::PreOperator(_, k) => k,
@ -310,17 +232,19 @@ fn treeify_unaryright(
}; };
let mut new_token_args: VecDeque<Token> = VecDeque::with_capacity(3); 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(());
return Ok(i);
} else { } else {
// The operator to the right has higher precedence. // The operator to the right has higher precedence.
// Move on, don't to anything yet. // Move on, don't to anything yet.
i += 1; return Ok(());
return Ok(i);
}; };
}; };
} }
@ -334,37 +258,52 @@ pub fn p_treeify(
_ => panic!() _ => panic!()
}; };
let mut i: usize = 0; let mut left_associative = true;
let mut j: i64 = 0;
while g_inner.len() > 1 { 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] { let this_op = match &g_inner[i] {
Token::PreOperator(_, o) => o, Token::PreOperator(_, o) => o,
_ => { i+=1; continue; } _ => {
if left_associative { j += 1 } else { j -= 1 };
continue;
}
}; };
match this_op { if left_associative {
Operator::ModuloLong | if this_op.is_left_associative() {
Operator::Subtract | if this_op.is_binary() {
Operator::Add | treeify_binary(i, g_inner, left_associative)?;
Operator::Divide | } else {
Operator::Multiply | treeify_unary(i, g_inner, left_associative)?;
Operator::ImplicitMultiply | }
Operator::Modulo | }
Operator::Power j += 1
=> { i = treeify_binary(i, g_inner)?; }, } else {
if !this_op.is_left_associative() {
Operator::Negative if this_op.is_binary() {
=> { i = treeify_unaryleft(i, g_inner)?; }, treeify_binary(i, g_inner, left_associative)?;
} else {
Operator::Factorial treeify_unary(i, g_inner, left_associative)?;
=> { i = treeify_unaryright(i, g_inner)?; } }
}
}; j -= 1
}
} }
g = g_inner.pop_front().unwrap(); g = g_inner.pop_front().unwrap();
// Catch the edge case where the entire group we're given // Catch edge cases
// consists of one operator. This is always a syntax error.
match g { match g {
Token::PreOperator(l, _) => { Token::PreOperator(l, _) => {
return Err((l, ParserError::Syntax)); return Err((l, ParserError::Syntax));