2023-03-21 19:37:02 -07:00
|
|
|
|
use std::collections::VecDeque;
|
2023-03-20 11:36:43 -07:00
|
|
|
|
|
|
|
|
|
|
2023-03-27 09:47:02 -07:00
|
|
|
|
/// Specifies the location of a token in an input string.
|
|
|
|
|
/// Used to locate ParserErrors.
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
|
pub struct LineLocation {
|
|
|
|
|
pub pos: usize,
|
|
|
|
|
pub len: usize
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-22 10:53:38 -07:00
|
|
|
|
/// Tokens represent logical objects in an expession.
|
|
|
|
|
///
|
|
|
|
|
/// Tokens starting with `Pre*` are intermediate tokens, and
|
|
|
|
|
/// will never show up in a fully-parsed expression tree.
|
2023-03-21 19:37:02 -07:00
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub enum Token {
|
2023-03-22 10:53:38 -07:00
|
|
|
|
Number(LineLocation, f64),
|
2023-03-24 20:21:48 -07:00
|
|
|
|
Constant(LineLocation, f64, String),
|
|
|
|
|
|
2023-03-27 21:22:29 -07:00
|
|
|
|
Operator(
|
|
|
|
|
LineLocation,
|
|
|
|
|
Operator,
|
|
|
|
|
VecDeque<Token>
|
|
|
|
|
),
|
2023-03-21 19:37:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-24 20:21:48 -07:00
|
|
|
|
impl Token {
|
2023-03-25 09:40:08 -07:00
|
|
|
|
#[inline(always)]
|
|
|
|
|
pub fn get_args(&mut self) -> Option<&mut VecDeque<Token>> {
|
|
|
|
|
match self {
|
2023-03-27 21:22:29 -07:00
|
|
|
|
Token::Operator(_, _, ref mut a)
|
|
|
|
|
=> Some(a),
|
2023-03-25 09:40:08 -07:00
|
|
|
|
_ => None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
pub fn get_line_location(&self) -> &LineLocation {
|
|
|
|
|
match self {
|
2023-03-27 21:22:29 -07:00
|
|
|
|
Token::Number(l, _)
|
|
|
|
|
| Token::Operator(l, _, _)
|
|
|
|
|
| Token::Constant(l, _, _)
|
2023-03-25 09:40:08 -07:00
|
|
|
|
=> l,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-25 09:27:15 -07:00
|
|
|
|
#[inline(always)]
|
2023-03-24 20:21:48 -07:00
|
|
|
|
fn as_number(&self) -> Token {
|
|
|
|
|
match self {
|
|
|
|
|
Token::Number(l,v) => {
|
|
|
|
|
Token::Number(*l, *v)
|
|
|
|
|
},
|
|
|
|
|
Token::Constant(l,v,_) => {
|
|
|
|
|
Token::Number(*l, *v)
|
|
|
|
|
},
|
|
|
|
|
_ => panic!()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn eval(&self) -> Token {
|
2023-03-27 21:22:29 -07:00
|
|
|
|
let (o, v) = match self {
|
|
|
|
|
Token::Operator(_, o, v) => (o, v),
|
|
|
|
|
Token::Number(l, v) => { return Token::Number(*l, *v); },
|
|
|
|
|
_ => panic!()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match o {
|
|
|
|
|
Operator::Negative => {
|
2023-03-24 13:16:58 -07:00
|
|
|
|
if v.len() != 1 {panic!()};
|
2023-03-24 20:21:48 -07:00
|
|
|
|
let v = v[0].as_number();
|
2023-03-24 13:16:58 -07:00
|
|
|
|
|
2023-03-24 20:21:48 -07:00
|
|
|
|
if let Token::Number(l, v) = v {
|
2023-03-24 13:16:58 -07:00
|
|
|
|
Token::Number(l, -v)
|
|
|
|
|
} else { panic!(); }
|
|
|
|
|
},
|
|
|
|
|
|
2023-03-27 21:22:29 -07:00
|
|
|
|
Operator::Add => {
|
2023-03-24 13:16:58 -07:00
|
|
|
|
let mut sum: f64 = 0f64;
|
|
|
|
|
let mut new_pos: usize = 0;
|
|
|
|
|
let mut new_len: usize = 0;
|
|
|
|
|
for i in v.iter() {
|
2023-03-24 20:21:48 -07:00
|
|
|
|
let j = i.as_number();
|
|
|
|
|
if let Token::Number(l, v) = j {
|
2023-03-25 09:54:07 -07:00
|
|
|
|
if new_pos == 0 {new_pos = l.pos};
|
|
|
|
|
new_len = new_len + l.len;
|
2023-03-24 13:16:58 -07:00
|
|
|
|
sum += v;
|
|
|
|
|
} else {
|
|
|
|
|
panic!();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Token::Number(
|
|
|
|
|
LineLocation { pos: new_pos, len: new_len },
|
|
|
|
|
sum
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
|
2023-03-27 21:22:29 -07:00
|
|
|
|
Operator::ImplicitMultiply |
|
|
|
|
|
Operator::Multiply => {
|
2023-03-24 13:16:58 -07:00
|
|
|
|
let mut prod: f64 = 1f64;
|
|
|
|
|
let mut new_pos: usize = 0;
|
|
|
|
|
let mut new_len: usize = 0;
|
|
|
|
|
for i in v.iter() {
|
2023-03-24 20:21:48 -07:00
|
|
|
|
let j = i.as_number();
|
|
|
|
|
if let Token::Number(l, v) = j {
|
2023-03-25 09:54:07 -07:00
|
|
|
|
if new_pos == 0 {new_pos = l.pos};
|
|
|
|
|
new_len = new_len + l.len;
|
2023-03-24 13:16:58 -07:00
|
|
|
|
prod *= v;
|
|
|
|
|
} else {
|
|
|
|
|
panic!();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Token::Number(
|
|
|
|
|
LineLocation { pos: new_pos, len: new_len },
|
|
|
|
|
prod
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
|
2023-03-27 21:22:29 -07:00
|
|
|
|
Operator::Divide => {
|
2023-03-24 13:16:58 -07:00
|
|
|
|
if v.len() != 2 {panic!()};
|
2023-03-24 20:21:48 -07:00
|
|
|
|
let a = v[0].as_number();
|
|
|
|
|
let b = v[1].as_number();
|
2023-03-24 13:16:58 -07:00
|
|
|
|
|
|
|
|
|
if let Token::Number(la, va) = a {
|
|
|
|
|
if let Token::Number(lb, vb) = b {
|
|
|
|
|
Token::Number(
|
2023-03-25 09:54:07 -07:00
|
|
|
|
LineLocation { pos: la.pos, len: lb.pos - la.pos + lb.len },
|
2023-03-24 13:16:58 -07:00
|
|
|
|
va/vb
|
|
|
|
|
)
|
|
|
|
|
} else { panic!(); }
|
|
|
|
|
} else { panic!(); }
|
|
|
|
|
},
|
|
|
|
|
|
2023-03-27 21:22:29 -07:00
|
|
|
|
Operator::ModuloLong |
|
|
|
|
|
Operator::Modulo => {
|
2023-03-24 13:16:58 -07:00
|
|
|
|
if v.len() != 2 {panic!()};
|
2023-03-24 20:21:48 -07:00
|
|
|
|
let a = v[0].as_number();
|
|
|
|
|
let b = v[1].as_number();
|
2023-03-24 13:16:58 -07:00
|
|
|
|
|
|
|
|
|
if let Token::Number(la, va) = a {
|
|
|
|
|
if let Token::Number(lb, vb) = b {
|
|
|
|
|
Token::Number(
|
2023-03-25 09:54:07 -07:00
|
|
|
|
LineLocation { pos: la.pos, len: lb.pos - la.pos + lb.len },
|
2023-03-24 13:16:58 -07:00
|
|
|
|
va%vb
|
|
|
|
|
)
|
|
|
|
|
} else { panic!(); }
|
|
|
|
|
} else { panic!(); }
|
|
|
|
|
},
|
|
|
|
|
|
2023-03-27 21:22:29 -07:00
|
|
|
|
Operator::Power => {
|
2023-03-24 13:16:58 -07:00
|
|
|
|
if v.len() != 2 {panic!()};
|
2023-03-24 20:21:48 -07:00
|
|
|
|
let a = v[0].as_number();
|
|
|
|
|
let b = v[1].as_number();
|
2023-03-24 13:16:58 -07:00
|
|
|
|
|
|
|
|
|
if let Token::Number(la, va) = a {
|
|
|
|
|
if let Token::Number(lb, vb) = b {
|
|
|
|
|
Token::Number(
|
2023-03-25 09:54:07 -07:00
|
|
|
|
LineLocation { pos: la.pos, len: lb.pos - la.pos + lb.len },
|
2023-03-24 20:21:48 -07:00
|
|
|
|
va.powf(vb)
|
2023-03-24 13:16:58 -07:00
|
|
|
|
)
|
|
|
|
|
} else { panic!(); }
|
|
|
|
|
} else { panic!(); }
|
|
|
|
|
},
|
|
|
|
|
|
2023-03-27 21:22:29 -07:00
|
|
|
|
Operator::Factorial => { todo!() },
|
|
|
|
|
Operator::Subtract => { panic!() }
|
2023-03-24 13:16:58 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-22 10:53:38 -07:00
|
|
|
|
/// Operator types, in order of increasing priority.
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
#[derive(Copy, Clone)]
|
2023-03-24 20:21:48 -07:00
|
|
|
|
pub enum Operator {
|
2023-03-22 22:51:48 -07:00
|
|
|
|
ModuloLong = 0, // Mod invoked with "mod"
|
2023-03-22 10:53:38 -07:00
|
|
|
|
Subtract,
|
|
|
|
|
Add,
|
|
|
|
|
Divide,
|
|
|
|
|
Multiply,
|
|
|
|
|
ImplicitMultiply,
|
|
|
|
|
Modulo, // Mod invoked with %
|
2023-03-27 10:54:57 -07:00
|
|
|
|
Negative,
|
|
|
|
|
|
|
|
|
|
|
2023-03-22 22:51:48 -07:00
|
|
|
|
Power,
|
|
|
|
|
|
2023-03-26 12:13:08 -07:00
|
|
|
|
Factorial,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Operator {
|
2023-03-27 21:22:29 -07:00
|
|
|
|
#[inline(always)]
|
|
|
|
|
pub fn into_token(self, l: LineLocation, mut args: VecDeque<Token>) -> Token {
|
|
|
|
|
match self {
|
|
|
|
|
Operator::Subtract => {
|
|
|
|
|
if args.len() != 2 { panic!() }
|
|
|
|
|
let a = args.pop_front().unwrap();
|
|
|
|
|
let b = args.pop_front().unwrap();
|
|
|
|
|
let b = Token::Operator(l, Operator::Negative, VecDeque::from(vec!(b)));
|
|
|
|
|
|
|
|
|
|
Token::Operator(
|
|
|
|
|
l, Operator::Add,
|
|
|
|
|
VecDeque::from(vec!(a,b))
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
Operator::Factorial
|
|
|
|
|
| Operator::Negative
|
|
|
|
|
=> {
|
|
|
|
|
if args.len() != 1 { panic!() }
|
|
|
|
|
Token::Operator(l, self, args)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
Operator::Modulo
|
|
|
|
|
| Operator::ModuloLong
|
|
|
|
|
| Operator::Divide
|
|
|
|
|
| Operator::Power
|
|
|
|
|
=> {
|
|
|
|
|
if args.len() != 2 { panic!() }
|
|
|
|
|
Token::Operator(l, self, args)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
Operator::Add
|
|
|
|
|
| Operator::Multiply
|
|
|
|
|
| Operator::ImplicitMultiply
|
|
|
|
|
=> Token::Operator(l, self, args)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
pub fn from_string(s: &str) -> Option<Operator> {
|
|
|
|
|
match s {
|
2023-03-27 21:25:16 -07:00
|
|
|
|
"+" => {Some( Operator::Add )},
|
|
|
|
|
"-" => {Some( Operator::Subtract )},
|
|
|
|
|
"neg" => {Some( Operator::Negative )},
|
|
|
|
|
"*"|"×" => {Some( Operator::Multiply )},
|
|
|
|
|
"/"|"÷" => {Some( Operator::Divide )},
|
|
|
|
|
"i*" => {Some( Operator::ImplicitMultiply )},
|
|
|
|
|
"%" => {Some( Operator::Modulo )},
|
|
|
|
|
"mod" => {Some( Operator::ModuloLong )},
|
|
|
|
|
"^"|"**" => {Some( Operator::Power )},
|
|
|
|
|
"!" => {Some( Operator::Factorial )},
|
2023-03-27 21:22:29 -07:00
|
|
|
|
_ => None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-26 12:13:08 -07:00
|
|
|
|
#[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
|
|
|
|
|
=> false,
|
|
|
|
|
_ => true
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-27 21:22:29 -07:00
|
|
|
|
}
|