Canonicalize user input units

This commit is contained in:
Tiffany Bennett 2016-08-24 15:25:35 -04:00
parent 262ee80a7c
commit 6180935d63

View file

@ -189,6 +189,39 @@ impl Context {
None None
} }
/// Given a unit name, try to return a canonical name (expanding aliases and such)
pub fn canonicalize(&self, name: &str) -> Option<String> {
for k in &self.dimensions {
if name == &***k {
return Some((**k).clone())
}
}
if let Some(v) = self.definitions.get(name) {
if let Expr::Unit(ref name) = *v {
if let Some(r) = self.canonicalize(&*name) {
return Some(r)
} else {
return Some(name.clone())
}
}
// we cannot canonicalize it further
return None
}
if name.ends_with("s") {
if let Some(v) = self.canonicalize(&name[0..name.len()-1]) {
return Some(v)
}
}
for &(ref pre, _) in &self.prefixes {
if name.starts_with(pre) {
if let Some(v) = self.canonicalize(&name[pre.len()..]) {
return Some(format!("{}{}", pre, v))
}
}
}
None
}
/// Describes a value's unit, gives true if the unit is reciprocal /// Describes a value's unit, gives true if the unit is reciprocal
/// (e.g. you should prefix "1.0 / " or replace "multiply" with /// (e.g. you should prefix "1.0 / " or replace "multiply" with
/// "divide" when rendering it). /// "divide" when rendering it).
@ -369,7 +402,7 @@ impl Context {
Expr::Call(_, _) => Err(format!("Calls are not allowed in the right hand side of conversions")), Expr::Call(_, _) => Err(format!("Calls are not allowed in the right hand side of conversions")),
Expr::Unit(ref name) | Expr::Quote(ref name) => { Expr::Unit(ref name) | Expr::Quote(ref name) => {
let mut map = BTreeMap::new(); let mut map = BTreeMap::new();
map.insert(name.clone(), 1); map.insert(self.canonicalize(&**name).unwrap_or_else(|| name.clone()), 1);
Ok(map) Ok(map)
}, },
Expr::Const(ref x, None, None) if x == "1" || x == "-1" => Ok(BTreeMap::new()), Expr::Const(ref x, None, None) if x == "1" || x == "-1" => Ok(BTreeMap::new()),
@ -598,7 +631,8 @@ impl Context {
use std::io::Write; use std::io::Write;
use number; use number;
write!(buf, "{} {}, ", number::to_string(&value).1, name).unwrap(); write!(buf, "{} {}, ", number::to_string(&value).1,
self.canonicalize(name).unwrap_or_else(|| name.clone())).unwrap();
} }
buf.pop(); buf.pop(); buf.pop(); buf.pop();
if let Some(res) = self.aliases.get(&top.1) { if let Some(res) = self.aliases.get(&top.1) {