Introduce quantity syntax to gnu units definitions

This commit is contained in:
Tiffany Bennett 2016-08-21 10:50:26 -04:00
parent ef2362f6bc
commit 920fffe9ca
6 changed files with 94 additions and 98 deletions

View file

@ -476,30 +476,30 @@ Hz hertz
# "You want:" prompt to tell the user the dimension of the unit. # "You want:" prompt to tell the user the dimension of the unit.
# #
LENGTH meter length ? meter
AREA LENGTH^2 area ? length^2
VOLUME LENGTH^3 volume ? length^3
MASS kilogram mass ? kilogram
CURRENT ampere current ? ampere
AMOUNT mole amount ? mole
ANGLE radian angle ? radian
SOLID_ANGLE steradian solid_angle ? steradian
MONEY US$ money ? US$
FORCE newton force ? newton
PRESSURE FORCE / AREA pressure ? force / area
STRESS FORCE / AREA stress ? force / area
CHARGE coulomb charge ? coulomb
CAPACITANCE farad capacitance ? farad
RESISTANCE ohm resistance ? ohm
CONDUCTANCE siemens conductance ? siemens
INDUCTANCE henry inductance ? henry
FREQUENCY hertz frequency ? hertz
VELOCITY LENGTH / TIME velocity ? length / time
ACCELERATION VELOCITY / TIME acceleration ? velocity / time
DENSITY MASS / VOLUME density ? mass / volume
LINEAR_DENSITY MASS / LENGTH linear_density ? mass / length
VISCOSITY FORCE TIME / AREA viscosity ? force time / area
KINEMATIC_VISCOSITY VISCOSITY / DENSITY kinematic_viscosity ? viscosity / density
# #
@ -737,8 +737,8 @@ fine 1|1000 # Measure of gold purity
# with "temp". # with "temp".
# #
TEMPERATURE kelvin temperature ? kelvin
TEMPERATURE_DIFFERENCE kelvin temperature_difference kelvin
# In 1741 Anders Celsius introduced a temperature scale with water boiling at # In 1741 Anders Celsius introduced a temperature scale with water boiling at
# 0 degrees and freezing at 100 degrees at standard pressure. After his death # 0 degrees and freezing at 100 degrees at standard pressure. After his death
@ -1260,11 +1260,10 @@ ozcu ouncecopper # in circuitboard fabrication
# Photometric units # Photometric units
# #
LUMINOUS_INTENSITY candela luminous_intensity ? candela
LUMINOUS_FLUX lumen luminous_flux ? lumen
LUMINOUS_ENERGY talbot luminous_energy ? talbot
ILLUMINANCE lux illuminance ? lux
EXITANCE lux
candle 1.02 candela # Standard unit for luminous intensity candle 1.02 candela # Standard unit for luminous intensity
hefnerunit 0.9 candle # in use before candela hefnerunit 0.9 candle # in use before candela
@ -1300,7 +1299,7 @@ skot 1e-3 apostilb # measurements relating to dark adapted
# eyes. # eyes.
# Luminance measures # Luminance measures
LUMINANCE nit luminance ? nit
nit cd/m^2 # Luminance: the intensity per projected nit cd/m^2 # Luminance: the intensity per projected
stilb cd / cm^2 # area of an extended luminous source. stilb cd / cm^2 # area of an extended luminous source.
@ -1579,7 +1578,7 @@ C_illum C_apex1961
# and a description of how to compute the correction to mean time. # and a description of how to compute the correction to mean time.
# #
TIME second time ? second
anomalisticyear 365.2596 days # The time between successive anomalisticyear 365.2596 days # The time between successive
# perihelion passages of the # perihelion passages of the
@ -2895,8 +2894,7 @@ count /pound # For measuring the size of shrimp
# Other units of work, energy, power, etc # Other units of work, energy, power, etc
# #
ENERGY joule energy ? joule
WORK joule
# Calories: energy to raise a gram of water one degree celsius # Calories: energy to raise a gram of water one degree celsius
@ -3085,7 +3083,7 @@ uranium_natural 0.7% uranium_pure # Natural uranium: 0.7% U-235
celsiusheatunit cal lb K / gram K celsiusheatunit cal lb K / gram K
chu celsiusheatunit chu celsiusheatunit
POWER watt power ? watt
# "Apparent" average power in an AC circuit, the product of rms voltage # "Apparent" average power in an AC circuit, the product of rms voltage
# and rms current, equal to the true power in watts when voltage and # and rms current, equal to the true power in watts when voltage and
@ -3119,24 +3117,24 @@ chevalvapeur metrichorsepower
# cross sectional area, t is the time, and L is the length (thickness). # cross sectional area, t is the time, and L is the length (thickness).
# Thermal conductivity is a material property. # Thermal conductivity is a material property.
THERMAL_CONDUCTIVITY POWER / AREA (TEMPERATURE_DIFFERENCE/LENGTH) thermal_conductivity ? power / area (temperature_difference/length)
THERMAL_RESISTIVITY 1/THERMAL_CONDUCTIVITY thermal_resistivity ? 1/thermal_conductivity
# Thermal conductance is the rate at which heat flows across a given # Thermal conductance is the rate at which heat flows across a given
# object, so the area and thickness have been fixed. It depends on # object, so the area and thickness have been fixed. It depends on
# the size of the object and is hence not a material property. # the size of the object and is hence not a material property.
THERMAL_CONDUCTANCE POWER / TEMPERATURE_DIFFERENCE thermal_conductance ? power / temperature_difference
THERMAL_RESISTANCE 1/THERMAL_CONDUCTANCE thermal_resistance ? 1/thermal_conductance
# Thermal admittance is the rate of heat flow per area across an # Thermal admittance is the rate of heat flow per area across an
# object whose thickness has been fixed. Its reciprocal, thermal # object whose thickness has been fixed. Its reciprocal, thermal
# insulation, is used to for measuring the heat transfer per area # insulation, is used to for measuring the heat transfer per area
# of sheets of insulation or cloth that are of specified thickness. # of sheets of insulation or cloth that are of specified thickness.
THERMAL_ADMITTANCE THERMAL_CONDUCTIVITY / LENGTH thermal_admittance ? thermal_conductivity / length
THERMAL_INSULANCE THERMAL_RESISTIVITY LENGTH thermal_insulance ? thermal_resistivity length
THERMAL_INSULATION THERMAL_RESISTIVITY LENGTH thermal_insulation ? thermal_resistivity length
Rvalue degR ft^2 hr / btu Rvalue degR ft^2 hr / btu
Uvalue 1/Rvalue Uvalue 1/Rvalue
@ -3202,7 +3200,7 @@ tog 0.1 K m^2 / W # Also used for clothing.
# Misc other measures # Misc other measures
ENTROPY ENERGY / TEMPERATURE entropy ? energy / temperature
clausius 1e3 cal/K # A unit of physical entropy clausius 1e3 cal/K # A unit of physical entropy
langley thermcalorie/cm^2 # Used in radiation theory langley thermcalorie/cm^2 # Used in radiation theory
poncelet 100 kg force m / s poncelet 100 kg force m / s
@ -3563,7 +3561,7 @@ grobe_sabon 84 didotpoint
# to measure information and as a physical quantity. # to measure information and as a physical quantity.
# #
INFORMATION bit information ? bit
#nat (1/ln(2)) bits # Entropy measured base e #nat (1/ln(2)) bits # Entropy measured base e
#hartley log2(10) bits # Entropy of a uniformly #hartley log2(10) bits # Entropy of a uniformly
@ -3678,7 +3676,7 @@ semitone octave^(1|12)
# #
wholenote ! wholenote !
MUSICAL_NOTE_LENGTH wholenote musical_note_length ? wholenote
halfnote 1|2 wholenote halfnote 1|2 wholenote
quarternote 1|4 wholenote quarternote 1|4 wholenote
eighthnote 1|8 wholenote eighthnote 1|8 wholenote
@ -3965,7 +3963,7 @@ lbcut poundcut
# Gas and Liquid flow units # Gas and Liquid flow units
# #
FLUID_FLOW VOLUME / TIME #FLUID_FLOW VOLUME / TIME
# Some obvious volumetric gas flow units (cu is short for cubic) # Some obvious volumetric gas flow units (cu is short for cubic)
@ -4025,7 +4023,7 @@ sverdrup 1e6 m^3 / sec # Used to express flow of ocean
# of gas molecules per unit time, and hence to the mass flow if the # of gas molecules per unit time, and hence to the mass flow if the
# molecular mass is known. # molecular mass is known.
GAS_FLOW PRESSURE FLUID_FLOW #GAS_FLOW PRESSURE FLUID_FLOW
sccm atm cc/min # 's' is for "standard" to indicate sccm atm cc/min # 's' is for "standard" to indicate
sccs atm cc/sec # flow at standard pressure sccs atm cc/sec # flow at standard pressure
@ -4751,7 +4749,7 @@ Ci curie # emitted by the amount of radon that is
# in equilibrium with 1 gram of radium. # in equilibrium with 1 gram of radium.
rutherford 1e6 Bq # rutherford 1e6 Bq #
RADIATION_DOSE gray radiation_dose ? gray
gray J/kg # Absorbed dose of radiation gray J/kg # Absorbed dose of radiation
Gy gray # Gy gray #
rad 1e-2 Gy # From Radiation Absorbed Dose rad 1e-2 Gy # From Radiation Absorbed Dose

View file

@ -64,6 +64,7 @@ pub enum Def {
Prefix(Expr), Prefix(Expr),
SPrefix(Expr), SPrefix(Expr),
Unit(Expr), Unit(Expr),
Quantity(Expr),
DatePattern(Vec<DatePattern>), DatePattern(Vec<DatePattern>),
Error(String), Error(String),
} }
@ -71,5 +72,4 @@ pub enum Def {
#[derive(Debug)] #[derive(Debug)]
pub struct Defs { pub struct Defs {
pub defs: Vec<(String, Rc<Def>)>, pub defs: Vec<(String, Rc<Def>)>,
pub aliases: Vec<(Expr, String)>,
} }

View file

@ -37,6 +37,7 @@ fn main() {
Token::Plus => print!("+"), Token::Plus => print!("+"),
Token::Dash => print!("-"), Token::Dash => print!("-"),
Token::Asterisk => print!("*"), Token::Asterisk => print!("*"),
Token::Question => print!("?"),
Token::Error(e) => print!("<error: {}>", e), Token::Error(e) => print!("<error: {}>", e),
} }
} }

View file

@ -160,26 +160,27 @@ impl Context {
return Some(Number::one_unit(k.to_owned())) return Some(Number::one_unit(k.to_owned()))
} }
} }
self.units.get(name).cloned().or_else(|| { if let Some(v) = self.units.get(name).cloned() {
if name.ends_with("s") { return Some(v)
if let Some(v) = self.lookup(&name[0..name.len()-1]) { }
return Some(v) for (unit, alias) in &self.aliases {
if name == alias {
return Some(Number(Number::one().0, unit.clone()))
}
}
if name.ends_with("s") {
if let Some(v) = self.lookup(&name[0..name.len()-1]) {
return Some(v)
}
}
for &(ref pre, ref value) in &self.prefixes {
if name.starts_with(pre) {
if let Some(v) = self.lookup(&name[pre.len()..]) {
return Some((&v * &value).unwrap())
} }
} }
for &(ref pre, ref value) in &self.prefixes { }
if name.starts_with(pre) { None
if let Some(v) = self.lookup(&name[pre.len()..]) {
return Some((&v * &value).unwrap())
}
}
}
for (unit, alias) in &self.aliases {
if name == alias {
return Some(Number(Number::one().0, unit.clone()))
}
}
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
@ -621,6 +622,7 @@ impl Context {
enum Name { enum Name {
Unit(Rc<String>), Unit(Rc<String>),
Prefix(Rc<String>), Prefix(Rc<String>),
Quantity(Rc<String>),
} }
struct Resolver { struct Resolver {
@ -653,6 +655,11 @@ impl Context {
self.visit(&unit); self.visit(&unit);
return Some(()) return Some(())
} }
let unit = Name::Quantity(name.clone());
if self.input.get(&unit).is_some() {
self.visit(&unit);
return Some(())
}
if name.ends_with("s") { if name.ends_with("s") {
let v = Rc::new(name[0..name.len()-1].to_owned()); let v = Rc::new(name[0..name.len()-1].to_owned());
if let Some(()) = self.lookup(&v) { if let Some(()) = self.lookup(&v) {
@ -710,7 +717,8 @@ impl Context {
self.temp_marks.insert(name.clone()); self.temp_marks.insert(name.clone());
if let Some(v) = self.input.get(name).cloned() { if let Some(v) = self.input.get(name).cloned() {
match *v { match *v {
Def::Prefix(ref e) | Def::SPrefix(ref e) | Def::Unit(ref e) => Def::Prefix(ref e) | Def::SPrefix(ref e) | Def::Unit(ref e) |
Def::Quantity(ref e) =>
self.eval(e), self.eval(e),
_ => (), _ => (),
} }
@ -733,6 +741,7 @@ impl Context {
let name = resolver.intern(&name); let name = resolver.intern(&name);
let unit = match *def { let unit = match *def {
Def::Prefix(_) | Def::SPrefix(_) => Name::Prefix(name), Def::Prefix(_) | Def::SPrefix(_) => Name::Prefix(name),
Def::Quantity(_) => Name::Quantity(name),
_ => Name::Unit(name) _ => Name::Unit(name)
}; };
resolver.input.insert(unit.clone(), def); resolver.input.insert(unit.clone(), def);
@ -754,6 +763,7 @@ impl Context {
let name = match name { let name = match name {
Name::Unit(name) => (*name).clone(), Name::Unit(name) => (*name).clone(),
Name::Prefix(name) => (*name).clone(), Name::Prefix(name) => (*name).clone(),
Name::Quantity(name) => (*name).clone(),
}; };
match *def { match *def {
Def::Dimension(ref dname) => { Def::Dimension(ref dname) => {
@ -785,21 +795,19 @@ impl Context {
Ok(_) => println!("Prefix {} is not a number", name), Ok(_) => println!("Prefix {} is not a number", name),
Err(e) => println!("Prefix {} is malformed: {}", name, e) Err(e) => println!("Prefix {} is malformed: {}", name, e)
}, },
Def::Quantity(ref expr) => match ctx.eval(expr) {
Ok(Value::Number(v)) => {
println!("Added {}", name);
ctx.aliases.insert(v.1, name.clone());
},
Ok(_) => println!("Quantity {} is not a number", name),
Err(e) => println!("Quantity {} is malformed: {}", name, e)
},
Def::DatePattern(ref pat) => ctx.datepatterns.push(pat.clone()), Def::DatePattern(ref pat) => ctx.datepatterns.push(pat.clone()),
Def::Error(ref err) => println!("Def {}: {}", name, err), Def::Error(ref err) => println!("Def {}: {}", name, err),
}; };
} }
for (expr, name) in defs.aliases {
match ctx.eval(&expr) {
Ok(Value::Number(v)) => {
ctx.aliases.insert(v.1, name);
},
Ok(_) => println!("Alias {} is not a number", name),
Err(e) => println!("Alias {}: {}", name, e)
}
}
ctx ctx
} }
} }

View file

@ -18,6 +18,7 @@ pub enum Token {
Plus, Plus,
Dash, Dash,
Asterisk, Asterisk,
Question,
Error(String), Error(String),
} }
@ -58,6 +59,7 @@ impl<'a> Iterator for TokenIterator<'a> {
'-' => Token::Dash, '-' => Token::Dash,
'+' => Token::Plus, '+' => Token::Plus,
'*' => Token::Asterisk, '*' => Token::Asterisk,
'?' => Token::Question,
'\\' => match self.0.next() { '\\' => match self.0.next() {
Some('\n') => self.next().unwrap(), Some('\n') => self.next().unwrap(),
Some(x) => Token::Error(format!("Invalid escape: \\{}", x)), Some(x) => Token::Error(format!("Invalid escape: \\{}", x)),
@ -244,16 +246,8 @@ pub fn parse_expr(mut iter: &mut Iter) -> Expr {
parse_add(iter) parse_add(iter)
} }
fn is_uppercase(name: &str) -> bool {
name.len() > 1 && name.find(|c| match c {
'A'...'Z' | '_' => false,
_ => true
}).is_none()
}
pub fn parse(mut iter: &mut Iter) -> Defs { pub fn parse(mut iter: &mut Iter) -> Defs {
let mut map = vec![]; let mut map = vec![];
let mut aliases = vec![];
let mut line = 1; let mut line = 1;
loop { loop {
match iter.next().unwrap() { match iter.next().unwrap() {
@ -266,13 +260,6 @@ pub fn parse(mut iter: &mut Iter) -> Defs {
} }
}, },
Token::Ident(name) => { Token::Ident(name) => {
if is_uppercase(&*name) {
// alias
let mut copy = iter.clone();
let expr = parse_expr(&mut copy);
aliases.push((expr, name.to_lowercase()));
}
if name.ends_with("-") { if name.ends_with("-") {
// prefix // prefix
let expr = parse_expr(iter); let expr = parse_expr(iter);
@ -297,6 +284,11 @@ pub fn parse(mut iter: &mut Iter) -> Defs {
} else { } else {
map.push((name.clone(), Rc::new(Def::Dimension(name)))); map.push((name.clone(), Rc::new(Def::Dimension(name))));
} }
} else if let Some(&Token::Question) = iter.peek() {
// quantity
iter.next();
let expr = parse_expr(iter);
map.push((name, Rc::new(Def::Quantity(expr))));
} else { } else {
// derived // derived
let expr = parse_expr(iter); let expr = parse_expr(iter);
@ -309,7 +301,6 @@ pub fn parse(mut iter: &mut Iter) -> Defs {
} }
Defs { Defs {
defs: map, defs: map,
aliases: aliases,
} }
} }

View file

@ -523,12 +523,11 @@ fn parse_datepattern(mut iter: &mut Iter) -> Vec<DatePattern> {
pub fn parse(mut iter: &mut Iter) -> Defs { pub fn parse(mut iter: &mut Iter) -> Defs {
let mut map = vec![]; let mut map = vec![];
let mut aliases = vec![];
let mut line = 1; let mut line = 1;
loop { loop {
let mut copy = iter.clone(); let mut copy = iter.clone();
if let Some(a) = parse_alias(&mut copy) { if let Some(a) = parse_alias(&mut copy) {
aliases.push(a); map.push((a.1, Rc::new(Def::Quantity(a.0))));
*iter = copy; *iter = copy;
continue continue
} }
@ -588,7 +587,6 @@ pub fn parse(mut iter: &mut Iter) -> Defs {
} }
Defs { Defs {
defs: map, defs: map,
aliases: aliases,
} }
} }