git
This commit is contained in:
parent
40fef756df
commit
cd758a7fce
|
@ -26,7 +26,11 @@ impl Node for Constant {
|
|||
if self.value.is_zero() {
|
||||
return "0".to_string();
|
||||
}
|
||||
|
||||
|
||||
if self.value < 1. && self.value > 0.001 {
|
||||
return self.value.to_f64().to_string();
|
||||
}
|
||||
|
||||
self.value
|
||||
.to_string_radix(10, Some(8))
|
||||
.trim_end_matches('0')
|
||||
|
|
|
@ -26,8 +26,27 @@ impl Node for Divide {
|
|||
}
|
||||
|
||||
// Zero rule
|
||||
(NodeEnum::Constant(zero), _) if zero.get_value() == &0.0 => {
|
||||
Ok(evaluated_left)
|
||||
(NodeEnum::Constant(zero), _) if zero.get_value() == &0.0 => Ok(evaluated_left),
|
||||
|
||||
// Cancel out symbols and constants
|
||||
(NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => {
|
||||
match (
|
||||
(m1.get_left().as_ref(), m1.get_right().as_ref()),
|
||||
(m2.get_left().as_ref(), m2.get_right().as_ref()),
|
||||
) {
|
||||
((NodeEnum::Symbol(s1), o1), (NodeEnum::Symbol(s2), o2))
|
||||
| ((o1, NodeEnum::Symbol(s1)), (NodeEnum::Symbol(s2), o2))
|
||||
| ((NodeEnum::Symbol(s1), o1), (o2, NodeEnum::Symbol(s2)))
|
||||
| ((o1, NodeEnum::Symbol(s1)), (o2, NodeEnum::Symbol(s2))) => {
|
||||
if s1 == s2 {
|
||||
Divide::new(Rc::new(o1.clone()), Rc::new(o2.clone())).evaluate(env)
|
||||
} else {
|
||||
Ok(Divide::new_rc(evaluated_left, evaluated_right))
|
||||
}
|
||||
}
|
||||
|
||||
_ => Ok(Rc::new(Divide::new(evaluated_left, evaluated_right).into())),
|
||||
}
|
||||
}
|
||||
|
||||
// Constant / Constant = Constant
|
||||
|
|
|
@ -63,6 +63,18 @@ impl Node for Multiply {
|
|||
div.get_right(),
|
||||
)),
|
||||
|
||||
// 0.5*n -> n/2
|
||||
(NodeEnum::Constant(c), _) if c.get_value() == &0.5 => Divide::new(
|
||||
evaluated_right,
|
||||
Rc::new(Constant::new_from_float(2, &env).into()),
|
||||
)
|
||||
.evaluate(env),
|
||||
(_, NodeEnum::Constant(c)) if c.get_value() == &0.5 => Divide::new(
|
||||
evaluated_left,
|
||||
Rc::new(Constant::new_from_float(2, &env).into()),
|
||||
)
|
||||
.evaluate(env),
|
||||
|
||||
// Constant * Constant = Constant
|
||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||
Ok(Rc::new(NodeEnum::from(Constant::new(Float::with_val_64(
|
||||
|
@ -106,10 +118,10 @@ impl Node for Multiply {
|
|||
Ok(Set::new(values))
|
||||
}
|
||||
|
||||
(NodeEnum::Constant(c), NodeEnum::Multiply(m))
|
||||
| (NodeEnum::Multiply(m), NodeEnum::Constant(c)) => {
|
||||
Self::collapse_nested_multiply(c, m, env)?.evaluate(env)
|
||||
}
|
||||
// (NodeEnum::Constant(c), NodeEnum::Multiply(m))
|
||||
// | (NodeEnum::Multiply(m), NodeEnum::Constant(c)) => {
|
||||
// Self::collapse_nested_multiply(c, m, env)?.evaluate(env)
|
||||
// }
|
||||
|
||||
// (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => {
|
||||
// Self::move_constants_to_left(evaluated_left.clone(), evaluated_right.clone())
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
use rug::Float;
|
||||
|
||||
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
||||
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant, multiply::Multiply};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Subtract {
|
||||
|
@ -35,9 +35,63 @@ impl Node for Subtract {
|
|||
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => Ok(Rc::new(
|
||||
Subtract::new(evaluated_right, evaluated_left).into(),
|
||||
)),
|
||||
_ => Ok(Rc::new(
|
||||
Subtract::new(evaluated_left, evaluated_right).into(),
|
||||
)),
|
||||
|
||||
(NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => {
|
||||
match (
|
||||
(m1.get_left().as_ref(), m1.get_right().as_ref()),
|
||||
(m2.get_left().as_ref(), m2.get_right().as_ref()),
|
||||
) {
|
||||
((NodeEnum::Symbol(s1), o1), (NodeEnum::Symbol(s2), o2))
|
||||
| ((o1, NodeEnum::Symbol(s1)), (NodeEnum::Symbol(s2), o2))
|
||||
| ((NodeEnum::Symbol(s1), o1), (o2, NodeEnum::Symbol(s2)))
|
||||
| ((o1, NodeEnum::Symbol(s1)), (o2, NodeEnum::Symbol(s2))) => {
|
||||
if s1 == s2 {
|
||||
Multiply::new_rc(
|
||||
Subtract::new(Rc::new(o1.clone()), Rc::new(o2.clone()))
|
||||
.evaluate(env)?,
|
||||
Rc::new(s1.clone().into()),
|
||||
)
|
||||
.evaluate(env)
|
||||
} else {
|
||||
Ok(Rc::new(
|
||||
Subtract::new(evaluated_left, evaluated_right).into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
((NodeEnum::Exponent(e1), o1), (NodeEnum::Exponent(e2), o2))
|
||||
| ((o1, NodeEnum::Exponent(e1)), (NodeEnum::Exponent(e2), o2))
|
||||
| ((NodeEnum::Exponent(e1), o1), (o2, NodeEnum::Exponent(e2)))
|
||||
| ((o1, NodeEnum::Exponent(e1)), (o2, NodeEnum::Exponent(e2))) => {
|
||||
if e1 == e2 {
|
||||
Multiply::new_rc(
|
||||
Subtract::new(Rc::new(o1.clone()), Rc::new(o2.clone()))
|
||||
.evaluate(env)?,
|
||||
Rc::new(e1.clone().into()),
|
||||
)
|
||||
.evaluate(env)
|
||||
} else {
|
||||
Ok(Rc::new(
|
||||
Subtract::new(evaluated_left, evaluated_right).into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
_ => Ok(Rc::new(
|
||||
Subtract::new(evaluated_left, evaluated_right).into(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
if evaluated_left == evaluated_right {
|
||||
Ok(Rc::new(Constant::new_from_float(0.0, &env).into()))
|
||||
} else {
|
||||
Ok(Rc::new(
|
||||
Subtract::new(evaluated_left, evaluated_right).into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
use std::{iter::Peekable, rc::Rc, str::Chars, vec::IntoIter};
|
||||
use std::{
|
||||
iter::Peekable,
|
||||
rc::Rc,
|
||||
str::{Chars, SplitTerminator},
|
||||
vec::IntoIter,
|
||||
};
|
||||
|
||||
use rug::Float;
|
||||
|
||||
|
@ -63,6 +68,8 @@ pub enum TokenType {
|
|||
|
||||
True,
|
||||
False,
|
||||
|
||||
Terminator,
|
||||
}
|
||||
|
||||
impl TokenType {
|
||||
|
@ -100,6 +107,8 @@ impl TokenType {
|
|||
|
||||
TokenType::True => 4,
|
||||
TokenType::False => 5,
|
||||
|
||||
Self::Terminator => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,6 +249,8 @@ impl<'a> Lexer<'a> {
|
|||
tokens.push(Token(i, TokenType::ColonEquals));
|
||||
}
|
||||
|
||||
';' => tokens.push(Token(i, TokenType::Terminator)),
|
||||
|
||||
'(' => tokens.push(Token(i, TokenType::LParen)),
|
||||
')' => tokens.push(Token(i, TokenType::RParen)),
|
||||
|
||||
|
@ -293,6 +304,7 @@ impl<'a> Lexer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParserError {
|
||||
UnexpectedEndOfTokens(String),
|
||||
UnexpectedToken(usize, usize, String),
|
||||
|
@ -325,8 +337,18 @@ impl<'a> Parser<'a> {
|
|||
pub fn parse(&mut self) -> Result<Vec<Rc<NodeEnum>>, ParserError> {
|
||||
let mut expressions = vec![];
|
||||
|
||||
while self.tokens.peek().is_some() {
|
||||
if self.tokens.len() == 0 {
|
||||
return Ok(expressions);
|
||||
}
|
||||
|
||||
loop {
|
||||
expressions.push(self.expression()?);
|
||||
|
||||
if !self.is_at_end() {
|
||||
self.match_or_err(TokenType::Terminator)?;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(expressions)
|
||||
|
@ -462,16 +484,31 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn factor(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||
let expr = self.unary()?;
|
||||
if let Some(Token(_, TokenType::Star)) = self.tokens.peek() {
|
||||
self.consume();
|
||||
Ok(Rc::new(Multiply::new(expr, self.comparison()?).into()))
|
||||
} else if let Some(Token(_, TokenType::Slash)) = self.tokens.peek() {
|
||||
self.consume();
|
||||
Ok(Rc::new(Divide::new(expr, self.comparison()?).into()))
|
||||
} else {
|
||||
Ok(expr)
|
||||
let mut expr = self.unary()?;
|
||||
// if let Some(Token(_, TokenType::Star)) = self.tokens.peek() {
|
||||
// self.consume();
|
||||
// Ok(Rc::new(Multiply::new(expr, self.comparison()?).into()))
|
||||
// } else if let Some(Token(_, TokenType::Slash)) = self.tokens.peek() {
|
||||
// self.consume();
|
||||
// Ok(Rc::new(Divide::new(expr, self.comparison()?).into()))
|
||||
// } else {
|
||||
// Ok(expr)
|
||||
// }
|
||||
|
||||
loop {
|
||||
if self.match_type(TokenType::Star) {
|
||||
let right = self.unary()?;
|
||||
expr = Multiply::new_rc(expr, right);
|
||||
continue;
|
||||
} else if self.match_type(TokenType::Slash) {
|
||||
let right = self.unary()?;
|
||||
expr = Divide::new_rc(expr, right);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn unary(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||
|
@ -729,7 +766,7 @@ impl<'a> Parser<'a> {
|
|||
));
|
||||
};
|
||||
|
||||
match token {
|
||||
let expr = match token {
|
||||
TokenType::Number(value) => {
|
||||
let value = if let Ok(incomplete) = Float::parse(&value) {
|
||||
Float::with_val_64(self.environment.get_float_precision(), incomplete)
|
||||
|
@ -775,6 +812,25 @@ impl<'a> Parser<'a> {
|
|||
token.len(),
|
||||
format!("Unexpected token {token:?}"),
|
||||
)),
|
||||
};
|
||||
|
||||
// Implicit multiplication
|
||||
if !self.is_at_end() {
|
||||
match self.tokens.peek().unwrap() {
|
||||
Token(_, TokenType::Identifier(_)) | Token(_, TokenType::Number(_)) => {
|
||||
return Ok(Multiply::new_rc(expr?, self.primary()?));
|
||||
}
|
||||
Token(_, TokenType::LParen) if expr.is_ok() => {
|
||||
if let NodeEnum::Symbol(_) = expr.as_ref().unwrap().as_ref() {
|
||||
return expr;
|
||||
}
|
||||
|
||||
return Ok(Multiply::new_rc(expr?, self.primary()?));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue