Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions server/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ version = "0.1.0"
edition = "2021"

[dependencies]
lazy_static = "1.4.0"
bigdecimal = "0.3.0"
num-bigint = "0.4.3"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can remove that



chrono = "0.4.19"
log = "0.4.17"
ron = "0.7.0"
serde = "1.0.136"
simplelog = "0.12.0"
websocket = { version = "0.26.4", features = ["sync"] }
parser_combinator = { git = "https://github.com/ekinimo/Kirby", branch = 'main' }
parser_combinator = { git = "https://github.com/ekinimo/Kirby", branch = 'main' }
273 changes: 263 additions & 10 deletions server/src/ast/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
use std::fmt::{Display, Formatter};
#![feature(map_first_last)]
Copy link
Collaborator Author

@ekinimo ekinimo Jun 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can also remove that


use bigdecimal::BigDecimal;
use bigdecimal::One;
use bigdecimal::Zero;

use std::collections::BTreeMap;
use std::fmt::{Display, Formatter};
use std::ops::*;
//use bigint::{BigInt,Sign,BigUInt};
pub mod parser;

#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
Expand Down Expand Up @@ -34,15 +40,262 @@ pub enum SyntaxTree {
}

// TODO check whether necessary
// pub enum Values {
// Variable(String),
// Number(BigDecimal),
// Sum(Vec<Values>),
// Product(Vec<Values>),
// Exponent(Vec<Values>),
// AddInv(Box<Values>),
// MulInv(Box<Values>),
// }

#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum Values {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

possible introduce a reference to LocalizedSyntaxNode/Values and indicating how it got introduced

Number(BigDecimal),
Variable(String),
Sum(BigDecimal, BTreeMap<Values, BigDecimal>),
Product(BigDecimal, BTreeMap<Values, BigDecimal>),
Exponent(Box<(Values, Values)>),
}

impl From<LocalizedSyntaxNode> for Values {
fn from(node: LocalizedSyntaxNode) -> Values {
match node.tree {
SyntaxTree::Variable(value) => Values::Variable(value),
SyntaxTree::Number(value) => Values::Number(value),
SyntaxTree::Sum(box left, box right) => Values::from(left).add(right.into()),
SyntaxTree::Product(box left, box right) => Values::from(left).mul(right.into()),
SyntaxTree::Exponent(box left, box right) => Values::from(left).exp(right.into()),
SyntaxTree::Subtraction(box left, box right) => Values::from(left)
.add(Values::from(right))
.mul(Values::Number(BigDecimal::from(-1))),
SyntaxTree::Division(box left, box right) => Values::from(left)
.mul(Values::from(right).exp(Values::Number(BigDecimal::from(-1)))),
SyntaxTree::Negation(box value) => {
Values::from(value).mul(Values::Number(BigDecimal::from(-1)))
}
}
}
}

impl Display for Values {
Copy link
Collaborator Author

@ekinimo ekinimo Jun 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs a biit of rework. 2x will displayed as 0 + 2x

fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Values::Variable(value) => write!(f, "{}", value),
Values::Number(value) => write!(f, "{}", value),
Values::Sum(constant, vmap) => {
write!(f, "( {constant} ").unwrap();
for (k, v) in vmap {
write!(f, "+ {v} * {k} ").unwrap();
}
write!(f, ")")
}
Values::Product(constant, vmap) => {
write!(f, "( {constant} ").unwrap();
for (k, v) in vmap {
write!(f, "* {k} ^ {v} ").unwrap();
}
write!(f, ")")
}
Values::Exponent(box (left, right)) => write!(f, "({} ^ {})", left, right),
}
}
}
//const one : BigDecimal = BigDecimal::from(1);

//const two : BigDecimal = BigDecimal::from(2);

fn exponantiate(mut x: BigDecimal, mut y: BigDecimal) -> BigDecimal {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need figure smthng out for rational powers

if (&y).is_integer() {
if (&y).rem(BigDecimal::from(2)) == BigDecimal::zero() {
let n = y.half();

while (&y) > &n {
x = x.square();
y -= BigDecimal::one();
}
x
} else {
let n = (y.clone() - BigDecimal::one()).half();
let m = x.clone();
while (&y) > &n {
x = x.square();
y -= BigDecimal::one();
}
x * m
}
} else {
panic!("not implemented yet")
}
}

impl Values {
// fn entry_adder(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should come back. i had a brain fart

// mut map: BTreeMap<Values, BigDecimal>,
// pair: (&Values, &BigDecimal),
// ) -> BTreeMap<Values, BigDecimal> {
// let (key, value) = pair;
// map.entry(key.to_owned())
// .and_modify(|x| *x += value)
// .or_insert(value.to_owned());
// map
// }

fn entry_adder<F>(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is unnecessarily general. i had a brain fart. commented out one should work

mut map: BTreeMap<Values, BigDecimal>,
pair: (&Values, &BigDecimal),
fun: F,
) -> BTreeMap<Values, BigDecimal>
where
F: Fn(&mut BigDecimal, BigDecimal),
{
let (key, value) = pair;
map.entry(key.to_owned())
.and_modify(|x| fun(x, value.to_owned()))
.or_insert(value.to_owned());
map
}

fn const_folder<F>(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we dont need this any more

mut map: BTreeMap<Values, BigDecimal>,
value: BigDecimal,
fun: F,
) -> BTreeMap<Values, BigDecimal>
where
F: Fn(BigDecimal, BigDecimal) -> BigDecimal,
{
match map.pop_first().unwrap() {
(Values::Number(v1), v2) => map.insert(Values::Number(fun(v1, value)), v2),
(v1, v2) => map.insert(v1, v2),
};
map
}

fn add(self, other: Values) -> Values {
let zero: BigDecimal = BigDecimal::from(0);
let one: BigDecimal = BigDecimal::from(1);
let two: BigDecimal = BigDecimal::from(2);
match (self, other) {
(Values::Number(x), other) | (other, Values::Number(x)) if x == zero => other,
(Values::Number(x), Values::Number(y)) => Values::Number(x + y),
(Values::Sum(cx, x), Values::Number(y)) | (Values::Number(y), Values::Sum(cx, x)) => {
Values::Sum(cx + y, x)
}

(Values::Sum(cx, x), Values::Sum(cy, y)) => Values::Sum(
cx + cy,
x.iter().chain(y.iter()).fold(BTreeMap::new(), |a, b| {
Self::entry_adder(a, b, BigDecimal::add_assign)
}),
),
(Values::Sum(cx, x), Values::Product(cy, y))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this arm needs rework

| (Values::Product(cy, y), Values::Sum(cx, x)) => Values::Sum(
cx,
Self::entry_adder(
x,
(&Values::Product(BigDecimal::one(), y), &cy),
BigDecimal::add_assign,
),
),

(Values::Sum(cx, x), other) | (other, Values::Sum(cx, x)) => Values::Sum(
cx,
Self::entry_adder(x, (&other, &one), BigDecimal::add_assign),
),

(otherleft, otherright) if otherleft == otherright => {
Values::Sum(BigDecimal::zero(), BTreeMap::from([(otherleft, two)]))
}
(otherleft, otherright) => Values::Sum(
BigDecimal::zero(),
BTreeMap::from([(otherleft, one.clone()), (otherright, one)]),
),
}
}
fn mul(self, other: Values) -> Values {
let zero: BigDecimal = BigDecimal::from(0);
let one: BigDecimal = BigDecimal::from(1);
let two: BigDecimal = BigDecimal::from(2);
//todo!();
match (self, other) {
(Values::Number(x), _other) | (_other, Values::Number(x)) if x == zero => {
Values::Number(zero)
}
(Values::Number(x), other) | (other, Values::Number(x)) if x == one => other,
(Values::Number(x), Values::Product(xz, z))
| (Values::Product(xz, z), Values::Number(x)) => Values::Product(xz * x, z),
(Values::Number(x), Values::Number(y)) => Values::Number(x * y),
(Values::Number(x), other) | (other, Values::Number(x)) => {
Values::Product(x, BTreeMap::from([(other, one.clone())]))
}

(Values::Exponent(box (a, b)), Values::Exponent(box (c, d))) => {
if a == c {
a.exp(b.add(d))
} else if b == d {
a.mul(c).exp(d)
} else {
Values::Product(
BigDecimal::one(),
BTreeMap::from([(a.exp(b), one.clone()), (c.exp(d), one)]),
)
}
}
(z, Values::Exponent(box (x, y))) | (Values::Exponent(box (x, y)), z) => {
if x == z {
x.exp(y.add(Values::Number(one)))
} else {
Values::Product(
BigDecimal::one(),
BTreeMap::from([(z, one.clone()), (x.exp(y), one)]),
)
}
}

(Values::Sum(cx, x), Values::Sum(cy, y)) => y
.iter()
.flat_map(|(y_val, y_key)| {
x.iter().map(move |(x_val, x_key)| {
x_val
.clone()
.mul(y_val.clone())
.mul(Values::Number(x_key * y_key.clone()))
})
})
.fold(Values::Number(cx * cy), |x: Values, y: Values| x.add(y)),
(Values::Sum(cx, x), other) | (other, Values::Sum(cx, x)) => {
let mut ret = Values::Number(cx);
for (k, v) in x {
ret = ret.add(k.mul(other.clone()).mul(Values::Number(v)));
}
ret
}
(Values::Product(cx, x), Values::Product(cy, y)) => Values::Product(
cx * cy,
x.iter().chain(y.iter()).fold(BTreeMap::new(), |a, b| {
Self::entry_adder(a, b, BigDecimal::mul_assign)
}),
),
(Values::Product(cx, x), other) | (other, Values::Product(cx, x)) => Values::Product(
cx,
Self::entry_adder(x, (&other, &one), BigDecimal::mul_assign),
),

(otherleft, otherright) => {
if otherleft == otherright {
Values::Product(BigDecimal::one(), BTreeMap::from([(otherleft, two)]))
} else {
Values::Product(
BigDecimal::one(),
BTreeMap::from([(otherleft, one.clone()), (otherright, one)]),
)
}
}
}
}
fn exp(self, other: Values) -> Values {
match (self, other) {
(Values::Number(x), _) if x == BigDecimal::zero() => Values::Number(BigDecimal::zero()),
(_, Values::Number(x)) if x == BigDecimal::zero() => Values::Number(BigDecimal::one()),
(Values::Number(x), _) if x == BigDecimal::one() => Values::Number(BigDecimal::one()),
(other, Values::Number(x)) if x == BigDecimal::one() => other,
(Values::Number(x), Values::Number(y)) => Values::Number(exponantiate(x, y)),
(otherleft, otherright) => Values::Exponent(Box::new((otherleft, otherright))),
}
}
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LocalizedSyntaxNode {
Expand Down
24 changes: 22 additions & 2 deletions server/src/ast/parser/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ mod atoms {
use crate::ast::parser::parse;
use crate::ast::parser::tests::number;
use crate::ast::Localization;

#[test]
fn integer() {
let result = parse("123;".to_string());
Expand Down Expand Up @@ -169,7 +169,8 @@ mod add {
use crate::ast::parser::parse;
use crate::ast::parser::tests::number;
use crate::ast::Localization;

use crate::ast::Values;
use std::fmt::Write;
#[test]
fn add_two_integers() {
let result = parse("123 + 456".to_string());
Expand All @@ -179,6 +180,16 @@ mod add {
expected.assert_matches(result);
}

#[test]
fn add_two_variables_and_convert_to_values() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at least the tests are easier to write

let result : Values = parse("x + x".to_string()).unwrap().pop().unwrap().into();

let expected = "( 0 + 2 * x )";
let mut result_text = String::new();
write!(result_text, "{result}").unwrap();
assert_eq!(expected,result_text)
}

#[test]
fn add_three_integers() {
let result = parse("123 + 456 + 789".to_string());
Expand All @@ -187,6 +198,15 @@ mod add {

expected.assert_matches(result);
}
#[test]
fn add_two_variables_and_convert_to_values2() {
let result : Values = parse("(x+y)*(x-y) ".to_string()).unwrap().pop().unwrap().into();

let expected = "( 0 + x + x ^ 2 )";
let mut result_text = String::new();
write!(result_text, "{result}").unwrap();
assert_eq!(expected,result_text)
}

#[test]
fn add_with_missing_first_summand() {
Expand Down
3 changes: 3 additions & 0 deletions server/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#![feature(map_first_last)]
#![feature(box_patterns)]
#![feature(type_ascription)]
use std::fs::File;
use std::thread;
use std::thread::sleep;
Expand Down