git
This commit is contained in:
parent
40fef756df
commit
cd758a7fce
|
@ -26,7 +26,11 @@ impl Node for Constant {
|
||||||
if self.value.is_zero() {
|
if self.value.is_zero() {
|
||||||
return "0".to_string();
|
return "0".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.value < 1. && self.value > 0.001 {
|
||||||
|
return self.value.to_f64().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
self.value
|
self.value
|
||||||
.to_string_radix(10, Some(8))
|
.to_string_radix(10, Some(8))
|
||||||
.trim_end_matches('0')
|
.trim_end_matches('0')
|
||||||
|
|
|
@ -26,8 +26,27 @@ impl Node for Divide {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero rule
|
// Zero rule
|
||||||
(NodeEnum::Constant(zero), _) if zero.get_value() == &0.0 => {
|
(NodeEnum::Constant(zero), _) if zero.get_value() == &0.0 => Ok(evaluated_left),
|
||||||
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
|
// Constant / Constant = Constant
|
||||||
|
|
|
@ -63,6 +63,18 @@ impl Node for Multiply {
|
||||||
div.get_right(),
|
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
|
// Constant * Constant = Constant
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||||
Ok(Rc::new(NodeEnum::from(Constant::new(Float::with_val_64(
|
Ok(Rc::new(NodeEnum::from(Constant::new(Float::with_val_64(
|
||||||
|
@ -106,10 +118,10 @@ impl Node for Multiply {
|
||||||
Ok(Set::new(values))
|
Ok(Set::new(values))
|
||||||
}
|
}
|
||||||
|
|
||||||
(NodeEnum::Constant(c), NodeEnum::Multiply(m))
|
// (NodeEnum::Constant(c), NodeEnum::Multiply(m))
|
||||||
| (NodeEnum::Multiply(m), NodeEnum::Constant(c)) => {
|
// | (NodeEnum::Multiply(m), NodeEnum::Constant(c)) => {
|
||||||
Self::collapse_nested_multiply(c, m, env)?.evaluate(env)
|
// Self::collapse_nested_multiply(c, m, env)?.evaluate(env)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => {
|
// (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => {
|
||||||
// Self::move_constants_to_left(evaluated_left.clone(), evaluated_right.clone())
|
// Self::move_constants_to_left(evaluated_left.clone(), evaluated_right.clone())
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use rug::Float;
|
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)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
pub struct Subtract {
|
pub struct Subtract {
|
||||||
|
@ -35,9 +35,63 @@ impl Node for Subtract {
|
||||||
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => Ok(Rc::new(
|
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => Ok(Rc::new(
|
||||||
Subtract::new(evaluated_right, evaluated_left).into(),
|
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;
|
use rug::Float;
|
||||||
|
|
||||||
|
@ -63,6 +68,8 @@ pub enum TokenType {
|
||||||
|
|
||||||
True,
|
True,
|
||||||
False,
|
False,
|
||||||
|
|
||||||
|
Terminator,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenType {
|
impl TokenType {
|
||||||
|
@ -100,6 +107,8 @@ impl TokenType {
|
||||||
|
|
||||||
TokenType::True => 4,
|
TokenType::True => 4,
|
||||||
TokenType::False => 5,
|
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::ColonEquals));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
';' => tokens.push(Token(i, TokenType::Terminator)),
|
||||||
|
|
||||||
'(' => tokens.push(Token(i, TokenType::LParen)),
|
'(' => tokens.push(Token(i, TokenType::LParen)),
|
||||||
')' => tokens.push(Token(i, TokenType::RParen)),
|
')' => tokens.push(Token(i, TokenType::RParen)),
|
||||||
|
|
||||||
|
@ -293,6 +304,7 @@ impl<'a> Lexer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ParserError {
|
pub enum ParserError {
|
||||||
UnexpectedEndOfTokens(String),
|
UnexpectedEndOfTokens(String),
|
||||||
UnexpectedToken(usize, usize, String),
|
UnexpectedToken(usize, usize, String),
|
||||||
|
@ -325,8 +337,18 @@ impl<'a> Parser<'a> {
|
||||||
pub fn parse(&mut self) -> Result<Vec<Rc<NodeEnum>>, ParserError> {
|
pub fn parse(&mut self) -> Result<Vec<Rc<NodeEnum>>, ParserError> {
|
||||||
let mut expressions = vec![];
|
let mut expressions = vec![];
|
||||||
|
|
||||||
while self.tokens.peek().is_some() {
|
if self.tokens.len() == 0 {
|
||||||
|
return Ok(expressions);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
expressions.push(self.expression()?);
|
expressions.push(self.expression()?);
|
||||||
|
|
||||||
|
if !self.is_at_end() {
|
||||||
|
self.match_or_err(TokenType::Terminator)?;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expressions)
|
Ok(expressions)
|
||||||
|
@ -462,16 +484,31 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn factor(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
fn factor(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
let expr = self.unary()?;
|
let mut expr = self.unary()?;
|
||||||
if let Some(Token(_, TokenType::Star)) = self.tokens.peek() {
|
// if let Some(Token(_, TokenType::Star)) = self.tokens.peek() {
|
||||||
self.consume();
|
// self.consume();
|
||||||
Ok(Rc::new(Multiply::new(expr, self.comparison()?).into()))
|
// Ok(Rc::new(Multiply::new(expr, self.comparison()?).into()))
|
||||||
} else if let Some(Token(_, TokenType::Slash)) = self.tokens.peek() {
|
// } else if let Some(Token(_, TokenType::Slash)) = self.tokens.peek() {
|
||||||
self.consume();
|
// self.consume();
|
||||||
Ok(Rc::new(Divide::new(expr, self.comparison()?).into()))
|
// Ok(Rc::new(Divide::new(expr, self.comparison()?).into()))
|
||||||
} else {
|
// } else {
|
||||||
Ok(expr)
|
// 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> {
|
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) => {
|
TokenType::Number(value) => {
|
||||||
let value = if let Ok(incomplete) = Float::parse(&value) {
|
let value = if let Ok(incomplete) = Float::parse(&value) {
|
||||||
Float::with_val_64(self.environment.get_float_precision(), incomplete)
|
Float::with_val_64(self.environment.get_float_precision(), incomplete)
|
||||||
|
@ -775,6 +812,25 @@ impl<'a> Parser<'a> {
|
||||||
token.len(),
|
token.len(),
|
||||||
format!("Unexpected token {token:?}"),
|
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