Skip to content

Commit

Permalink
Merge branch 'equality-check'
Browse files Browse the repository at this point in the history
  • Loading branch information
printfn committed Mar 5, 2024
2 parents 7dce963 + 842a769 commit 6750d5f
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 12 deletions.
26 changes: 25 additions & 1 deletion core/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl fmt::Display for Bop {
}
}

#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum Expr {
Literal(Value),
Ident(Ident),
Expand All @@ -122,6 +122,7 @@ pub(crate) enum Expr {
Of(Ident, Box<Expr>),

Assign(Ident, Box<Expr>),
Equality(bool, Box<Expr>, Box<Expr>),
Statements(Box<Expr>, Box<Expr>),
}

Expand Down Expand Up @@ -202,6 +203,12 @@ impl Expr {
a.serialize(write)?;
b.serialize(write)?;
}
Self::Equality(is_equals, a, b) => {
16u8.serialize(write)?;
is_equals.serialize(write)?;
a.serialize(write)?;
b.serialize(write)?;
}
}
Ok(())
}
Expand Down Expand Up @@ -252,6 +259,11 @@ impl Expr {
Box::new(Self::deserialize(read)?),
Box::new(Self::deserialize(read)?),
),
16 => Self::Equality(
bool::deserialize(read)?,
Box::new(Self::deserialize(read)?),
Box::new(Self::deserialize(read)?),
),
_ => return Err(FendError::DeserializationError),
})
}
Expand Down Expand Up @@ -309,6 +321,12 @@ impl Expr {
a.format(attrs, ctx, int)?,
b.format(attrs, ctx, int)?
),
Self::Equality(is_equals, a, b) => format!(
"{} {} {}",
a.format(attrs, ctx, int)?,
if *is_equals { "==" } else { "!=" },
b.format(attrs, ctx, int)?
),
})
}
}
Expand Down Expand Up @@ -452,6 +470,12 @@ pub(crate) fn evaluate<I: Interrupt>(
let _lhs = evaluate(*a, scope.clone(), attrs, context, int)?;
evaluate(*b, scope, attrs, context, int)?
}
Expr::Equality(is_equals, a, b) => {
let lhs = evaluate(*a, scope.clone(), attrs, context, int)?;
let rhs = evaluate(*b, scope.clone(), attrs, context, int)?;

Value::Bool(if is_equals { lhs == rhs } else { lhs != rhs })
}
})
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
serialize::{Deserialize, Serialize},
};

#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct Ident(Cow<'static, str>);

impl Ident {
Expand Down
16 changes: 14 additions & 2 deletions core/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ pub(crate) enum Symbol {
ShiftLeft,
ShiftRight,
Semicolon,
Equals, // used for assignment
Equals, // used for assignment
DoubleEquals, // used for equality
NotEquals,
Combination,
Permutation,
}
Expand Down Expand Up @@ -65,6 +67,8 @@ impl fmt::Display for Symbol {
Self::ShiftRight => ">>",
Self::Semicolon => ";",
Self::Equals => "=",
Self::DoubleEquals => "==",
Self::NotEquals => "!=",
Self::Combination => "nCr",
Self::Permutation => "nPr",
};
Expand Down Expand Up @@ -505,7 +509,13 @@ fn parse_symbol(ch: char, input: &mut &str) -> FResult<Token> {
'(' => Symbol::OpenParens,
')' => Symbol::CloseParens,
'+' => Symbol::Add,
'!' => Symbol::Factorial,
'!' => {
if test_next('=') {
Symbol::NotEquals
} else {
Symbol::Factorial
}
}
// unicode minus sign
'-' | '\u{2212}' => Symbol::Sub,
'*' | '\u{d7}' | '\u{2715}' => {
Expand All @@ -523,6 +533,8 @@ fn parse_symbol(ch: char, input: &mut &str) -> FResult<Token> {
'=' => {
if test_next('>') {
Symbol::Fn
} else if test_next('=') {
Symbol::DoubleEquals
} else {
Symbol::Equals
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/num/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::{fmt, io};
use super::real::Real;
use super::{Base, Exact, FormattingStyle};

#[derive(Clone)]
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct Dist {
// invariant: probabilities must sum to 1
parts: HashMap<Complex, BigRat>,
Expand Down
19 changes: 17 additions & 2 deletions core/src/num/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::scope::Scope;
use crate::serialize::{Deserialize, Serialize};
use crate::units::{lookup_default_unit, query_unit_static};
use crate::{ast, ident::Ident};
use crate::{Attrs, Span, SpanKind};
use crate::{interrupt::Never, Attrs, Span, SpanKind};
use std::borrow::Cow;
use std::collections::HashMap;
use std::ops::Neg;
Expand Down Expand Up @@ -37,6 +37,20 @@ pub(crate) struct Value {
simplifiable: bool,
}

impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
if self.value == other.value && self.unit == other.unit {
return true;
}
match self.clone().sub(other.clone(), &Never) {
Err(_) => false,
Ok(result) => result.is_zero(),
}
}
}

impl Eq for Value {}

impl Value {
pub(crate) fn serialize(&self, write: &mut impl io::Write) -> FResult<()> {
self.value.serialize(write)?;
Expand Down Expand Up @@ -982,7 +996,8 @@ impl fmt::Display for FormattedValue {
}
}

#[derive(Clone)]
// TODO: equality comparisons should not depend on order
#[derive(Clone, PartialEq, Eq)]
struct Unit {
components: Vec<UnitExponent>,
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/num/unit/unit_exponent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::Interrupt;

use super::{base_unit::BaseUnit, named_unit::NamedUnit};

#[derive(Clone)]
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct UnitExponent {
pub(crate) unit: NamedUnit,
pub(crate) exponent: Complex,
Expand Down
21 changes: 20 additions & 1 deletion core/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,8 +464,27 @@ fn parse_function(input: &[Token]) -> ParseResult<'_> {
Ok((lhs, input))
}

fn parse_assignment(input: &[Token]) -> ParseResult<'_> {
fn parse_equality(input: &[Token]) -> ParseResult<'_> {
let (lhs, input) = parse_function(input)?;
if let Ok(((), remaining)) = parse_fixed_symbol(input, Symbol::DoubleEquals) {
let (rhs, remaining) = parse_function(remaining)?;
Ok((
Expr::Equality(true, Box::new(lhs), Box::new(rhs)),
remaining,
))
} else if let Ok(((), remaining)) = parse_fixed_symbol(input, Symbol::NotEquals) {
let (rhs, remaining) = parse_function(remaining)?;
Ok((
Expr::Equality(false, Box::new(lhs), Box::new(rhs)),
remaining,
))
} else {
Ok((lhs, input))
}
}

fn parse_assignment(input: &[Token]) -> ParseResult<'_> {
let (lhs, input) = parse_equality(input)?;
if let Ok(((), remaining)) = parse_fixed_symbol(input, Symbol::Equals) {
if let Expr::Ident(s) = lhs {
let (rhs, remaining) = parse_assignment(remaining)?;
Expand Down
4 changes: 2 additions & 2 deletions core/src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{ast::Expr, error::Interrupt};
use std::io;
use std::sync::Arc;

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
enum ScopeValue {
//Variable(Value),
LazyVariable(Expr, Option<Arc<Scope>>),
Expand Down Expand Up @@ -55,7 +55,7 @@ impl ScopeValue {
}
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct Scope {
ident: Ident,
value: ScopeValue,
Expand Down
2 changes: 1 addition & 1 deletion core/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub(crate) mod built_in_function;

use built_in_function::BuiltInFunction;

#[derive(Clone)]
#[derive(Clone, PartialEq, Eq)]
pub(crate) enum Value {
Num(Box<Number>),
BuiltInFunction(BuiltInFunction),
Expand Down
13 changes: 13 additions & 0 deletions core/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5873,3 +5873,16 @@ fn test_superscript() {
test_eval("200²", "40000");
test_eval("13¹³ days", "302875106592253 days");
}

#[test]
fn test_equality() {
test_eval("1 + 2 == 3", "true");
test_eval("1 + 2 != 4", "true");
test_eval("true == false", "false");
test_eval("true != false", "true");
test_eval("2m == 200cm", "true");
test_eval("2kg == 200cm", "false");
test_eval("2kg == true", "false");
test_eval("2.010m == 200cm", "false");
test_eval("2.000m == approx. 200cm", "true");
}

0 comments on commit 6750d5f

Please sign in to comment.