mirror of
https://github.com/tiffany352/rink-rs
synced 2024-11-10 13:44:15 +00:00
Add a conversion operator with conformance errors
This commit is contained in:
parent
2a241a36cf
commit
3e6fe01923
2 changed files with 120 additions and 5 deletions
103
src/eval.rs
103
src/eval.rs
|
@ -123,6 +123,8 @@ impl Context {
|
|||
}
|
||||
if let Some(name) = self.aliases.get(&value.1) {
|
||||
write!(out, " ({})", name).unwrap();
|
||||
} else if value.1.len() == 1 {
|
||||
write!(out, " ({})", self.dimensions[*value.1.iter().next().unwrap().0]).unwrap();
|
||||
}
|
||||
String::from_utf8(out).unwrap()
|
||||
}
|
||||
|
@ -154,6 +156,61 @@ impl Context {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn describe_unit(&self, value: &Value) -> (bool, String) {
|
||||
use std::io::Write;
|
||||
|
||||
let mut buf = vec![];
|
||||
let mut recip = false;
|
||||
if let Some(name) = self.aliases.get(&value.1) {
|
||||
write!(buf, "{}", name).unwrap();
|
||||
} else {
|
||||
let mut frac = vec![];
|
||||
let mut found = false;
|
||||
for (&dim, &pow) in &value.1 {
|
||||
if pow < 0 {
|
||||
frac.push((dim, -pow));
|
||||
} else {
|
||||
found = true;
|
||||
let mut map = Unit::new();
|
||||
map.insert(dim, pow);
|
||||
if let Some(name) = self.aliases.get(&map) {
|
||||
write!(buf, " {}", name).unwrap();
|
||||
} else {
|
||||
let mut map = Unit::new();
|
||||
map.insert(dim, 1);
|
||||
write!(buf, " {}", self.aliases[&map]).unwrap();
|
||||
if pow != 1 {
|
||||
write!(buf, "^{}", pow).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if frac.len() > 0 {
|
||||
if !found {
|
||||
recip = true;
|
||||
} else {
|
||||
write!(buf, " /").unwrap();
|
||||
}
|
||||
for (dim, pow) in frac {
|
||||
let mut map = Unit::new();
|
||||
map.insert(dim, pow);
|
||||
if let Some(name) = self.aliases.get(&map) {
|
||||
write!(buf, " {}", name).unwrap();
|
||||
} else {
|
||||
let mut map = Unit::new();
|
||||
map.insert(dim, 1);
|
||||
write!(buf, " {}", self.aliases[&map]).unwrap();
|
||||
if pow != 1 {
|
||||
write!(buf, "^{}", pow).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(recip, String::from_utf8(buf).unwrap())
|
||||
}
|
||||
|
||||
pub fn eval(&self, expr: &::unit_defs::Expr) -> Result<Value, String> {
|
||||
use unit_defs::Expr;
|
||||
|
||||
|
@ -170,6 +227,44 @@ impl Context {
|
|||
(Err(e), _) => Err(e),
|
||||
(_, Err(e)) => Err(e),
|
||||
},
|
||||
Expr::Convert(ref top, ref bottom) => match (self.eval(&**top), self.eval(&**bottom)) {
|
||||
(Ok(top), Ok(bottom)) => {
|
||||
if top.1 != bottom.1 {
|
||||
use std::io::Write;
|
||||
|
||||
let mut buf = vec![];
|
||||
let width = 12;
|
||||
writeln!(buf, "Conformance error").unwrap();
|
||||
let mut topu = top.clone();
|
||||
topu.0 = 1.0;
|
||||
let mut bottomu = bottom.clone();
|
||||
bottomu.0 = 1.0;
|
||||
writeln!(buf, "{:>width$}: {}", "Left side", self.show(&topu), width=width).unwrap();
|
||||
writeln!(buf, "{:>width$}: {}", "Right side", self.show(&bottomu), width=width).unwrap();
|
||||
let diff = topu.mul(&bottomu.invert());
|
||||
let (recip, desc) = self.describe_unit(&diff.invert());
|
||||
let word = match recip {
|
||||
false => "multiply",
|
||||
true => "divide"
|
||||
};
|
||||
writeln!(buf, "{:>width$}: {word} left side by {}", "Suggestion",
|
||||
desc.trim(), width=width, word=word).unwrap();
|
||||
let (recip, desc) = self.describe_unit(&diff);
|
||||
let word = match recip {
|
||||
false => "multiply",
|
||||
true => "divide"
|
||||
};
|
||||
writeln!(buf, "{:>width$} {word} right side by {}", "",
|
||||
desc.trim(), width=width, word=word).unwrap();
|
||||
|
||||
Err(String::from_utf8(buf).unwrap())
|
||||
} else {
|
||||
Ok(top.mul(&bottom.invert()))
|
||||
}
|
||||
},
|
||||
(Err(e), _) => Err(e),
|
||||
(_, Err(e)) => Err(e),
|
||||
},
|
||||
Expr::Mul(ref args) => args.iter().fold(Ok(Value::new(1.0)), |a, b| {
|
||||
a.and_then(|a| {
|
||||
let b = try!(self.eval(b));
|
||||
|
@ -207,8 +302,12 @@ impl Context {
|
|||
|
||||
for (name, def) in defs.defs {
|
||||
match *def {
|
||||
Def::Dimension(ref name) => {
|
||||
ctx.dimensions.push(name.clone());
|
||||
Def::Dimension(ref dname) => {
|
||||
let i = ctx.dimensions.len();
|
||||
ctx.dimensions.push(dname.clone());
|
||||
let mut map = Unit::new();
|
||||
map.insert(i, 1);
|
||||
ctx.aliases.insert(map, name.clone());
|
||||
},
|
||||
Def::Unit(ref expr) => match ctx.eval(expr) {
|
||||
Ok(v) => {
|
||||
|
|
|
@ -26,6 +26,7 @@ pub enum Token {
|
|||
Plus,
|
||||
Minus,
|
||||
Asterisk,
|
||||
DashArrow,
|
||||
ImaginaryUnit,
|
||||
Error(String),
|
||||
}
|
||||
|
@ -56,7 +57,13 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||
'(' => Token::LPar,
|
||||
')' => Token::RPar,
|
||||
'+' => Token::Plus,
|
||||
'-' => Token::Minus,
|
||||
'-' => match self.0.peek().cloned().unwrap() {
|
||||
'>' => {
|
||||
self.0.next();
|
||||
Token::DashArrow
|
||||
},
|
||||
_ => Token::Minus
|
||||
},
|
||||
'*' => Token::Asterisk,
|
||||
'/' => match self.0.peek() {
|
||||
Some(&'/') => loop {
|
||||
|
@ -190,6 +197,7 @@ pub enum Expr {
|
|||
Pow(Box<Expr>, Box<Expr>),
|
||||
Neg(Box<Expr>),
|
||||
Plus(Box<Expr>),
|
||||
Convert(Box<Expr>, Box<Expr>),
|
||||
Error(String),
|
||||
}
|
||||
|
||||
|
@ -242,7 +250,7 @@ fn parse_pow(mut iter: &mut Iter) -> Expr {
|
|||
fn parse_mul(mut iter: &mut Iter) -> Expr {
|
||||
let mut terms = vec![parse_pow(iter)];
|
||||
loop { match *iter.peek().unwrap() {
|
||||
Token::TriplePipe | Token::RPar | Token::Newline | Token::Comment(_) |
|
||||
Token::DashArrow | Token::TriplePipe | Token::RPar | Token::Newline | Token::Comment(_) |
|
||||
Token::Eof => break,
|
||||
Token::Slash => {
|
||||
iter.next();
|
||||
|
@ -267,7 +275,15 @@ fn parse_mul(mut iter: &mut Iter) -> Expr {
|
|||
}
|
||||
|
||||
pub fn parse_expr(mut iter: &mut Iter) -> Expr {
|
||||
parse_mul(iter)
|
||||
let left = parse_mul(iter);
|
||||
match iter.peek().cloned().unwrap() {
|
||||
Token::DashArrow => {
|
||||
iter.next();
|
||||
let right = parse_mul(iter);
|
||||
Expr::Convert(Box::new(left), Box::new(right))
|
||||
},
|
||||
_ => left
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_unknown(mut iter: &mut Iter) {
|
||||
|
|
Loading…
Reference in a new issue