This commit is contained in:
Snorre 2025-02-24 17:13:40 +01:00
parent 40fef756df
commit cd758a7fce
5 changed files with 168 additions and 23 deletions

View file

@ -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')

View file

@ -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

View file

@ -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())

View file

@ -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(),
))
}
}
}
}

View file

@ -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
}
}