mirror of
https://github.com/tiffany352/rink-rs
synced 2024-09-20 22:21:57 +00:00
Implement gnu units parser
This commit is contained in:
parent
8db988c589
commit
24f510f1f4
2 changed files with 73 additions and 207 deletions
264
src/gnu_units.rs
264
src/gnu_units.rs
|
@ -156,14 +156,15 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||
|
||||
pub type Iter<'a> = Peekable<TokenIterator<'a>>;
|
||||
|
||||
/*fn parse_term(mut iter: &mut Iter) -> Expr {
|
||||
fn parse_term(mut iter: &mut Iter) -> Expr {
|
||||
match iter.next().unwrap() {
|
||||
Token::Ident(name) => Expr::Unit(name),
|
||||
Token::Number(num, frac, exp) => Expr::Const(num, frac, exp),
|
||||
Token::Plus => Expr::Plus(Box::new(parse_term(iter))),
|
||||
Token::Minus => Expr::Neg(Box::new(parse_term(iter))),
|
||||
// NYI: Imaginary numbers
|
||||
Token::ImaginaryUnit => Expr::Const("0".to_owned(), None, None),
|
||||
Token::Dash => Expr::Neg(Box::new(parse_term(iter))),
|
||||
Token::Slash => Expr::Frac(
|
||||
Box::new(Expr::Const("1".to_owned(), None, None)),
|
||||
Box::new(parse_term(iter))),
|
||||
Token::LPar => {
|
||||
let res = parse_expr(iter);
|
||||
match iter.next().unwrap() {
|
||||
|
@ -171,19 +172,6 @@ pub type Iter<'a> = Peekable<TokenIterator<'a>>;
|
|||
x => Expr::Error(format!("Expected ), got {:?}", x))
|
||||
}
|
||||
},
|
||||
Token::Hash => {
|
||||
let mut out = vec![];
|
||||
loop {
|
||||
match iter.next().unwrap() {
|
||||
Token::Hash => break,
|
||||
Token::Eof | Token::Comment(_) | Token::Newline =>
|
||||
return Expr::Error(format!("Unterminated date literal")),
|
||||
x => out.push(x),
|
||||
}
|
||||
}
|
||||
unimplemented!()
|
||||
//Expr::Date(out)
|
||||
},
|
||||
x => Expr::Error(format!("Expected term, got {:?}", x))
|
||||
}
|
||||
}
|
||||
|
@ -191,11 +179,16 @@ pub type Iter<'a> = Peekable<TokenIterator<'a>>;
|
|||
fn parse_pow(mut iter: &mut Iter) -> Expr {
|
||||
let left = parse_term(iter);
|
||||
match *iter.peek().unwrap() {
|
||||
Token::Carot => {
|
||||
Token::Caret => {
|
||||
iter.next();
|
||||
let right = parse_pow(iter);
|
||||
Expr::Pow(Box::new(left), Box::new(right))
|
||||
},
|
||||
Token::Pipe => {
|
||||
iter.next();
|
||||
let right = parse_pow(iter);
|
||||
Expr::Frac(Box::new(left), Box::new(right))
|
||||
},
|
||||
_ => left
|
||||
}
|
||||
}
|
||||
|
@ -203,9 +196,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().cloned().unwrap() {
|
||||
Token::DegC | Token::DegF | Token::DegRe | Token::DegRo | Token::DegDe | Token::DegN |
|
||||
Token::Comma | Token::Equals | Token::Plus | Token::Minus | Token::DashArrow |
|
||||
Token::TriplePipe | Token::RPar | Token::Newline | Token::Comment(_) | Token::Eof => break,
|
||||
Token::Plus | Token::Dash | Token::RPar | Token::Newline | Token::Eof => break,
|
||||
Token::Slash => {
|
||||
iter.next();
|
||||
let right = parse_pow(iter);
|
||||
|
@ -228,146 +219,32 @@ fn parse_mul(mut iter: &mut Iter) -> Expr {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_suffix(mut iter: &mut Iter) -> Expr {
|
||||
let left = parse_mul(iter);
|
||||
match iter.peek().cloned().unwrap() {
|
||||
Token::DegC => {
|
||||
iter.next();
|
||||
Expr::Suffix(SuffixOp::Celsius, Box::new(left))
|
||||
},
|
||||
Token::DegF => {
|
||||
iter.next();
|
||||
Expr::Suffix(SuffixOp::Fahrenheit, Box::new(left))
|
||||
},
|
||||
Token::DegRe => {
|
||||
iter.next();
|
||||
Expr::Suffix(SuffixOp::Reaumur, Box::new(left))
|
||||
},
|
||||
Token::DegRo => {
|
||||
iter.next();
|
||||
Expr::Suffix(SuffixOp::Romer, Box::new(left))
|
||||
},
|
||||
Token::DegDe => {
|
||||
iter.next();
|
||||
Expr::Suffix(SuffixOp::Delisle, Box::new(left))
|
||||
},
|
||||
Token::DegN => {
|
||||
iter.next();
|
||||
Expr::Suffix(SuffixOp::Newton, Box::new(left))
|
||||
},
|
||||
_ => left
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_add(mut iter: &mut Iter) -> Expr {
|
||||
let left = parse_suffix(iter);
|
||||
let left = parse_mul(iter);
|
||||
match *iter.peek().unwrap() {
|
||||
Token::Plus => {
|
||||
iter.next();
|
||||
let right = parse_suffix(iter);
|
||||
let right = parse_add(iter);
|
||||
Expr::Add(Box::new(left), Box::new(right))
|
||||
},
|
||||
Token::Minus => {
|
||||
Token::Dash => {
|
||||
iter.next();
|
||||
let right = parse_suffix(iter);
|
||||
let right = parse_add(iter);
|
||||
Expr::Sub(Box::new(left), Box::new(right))
|
||||
},
|
||||
_ => left
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_eq(mut iter: &mut Iter) -> Expr {
|
||||
let left = parse_add(iter);
|
||||
match iter.peek().cloned().unwrap() {
|
||||
Token::Equals => {
|
||||
iter.next();
|
||||
let right = parse_add(iter);
|
||||
Expr::Equals(Box::new(left), Box::new(right))
|
||||
},
|
||||
_ => left
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_expr(mut iter: &mut Iter) -> Expr {
|
||||
match iter.peek().cloned() {
|
||||
Some(Token::Ident(ref s)) if s == "factorize" => {
|
||||
iter.next();
|
||||
return Expr::Factorize(Box::new(parse_eq(iter)))
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
let left = parse_eq(iter);
|
||||
match iter.peek().cloned().unwrap() {
|
||||
Token::DashArrow => {
|
||||
iter.next();
|
||||
let right = match iter.peek().cloned().unwrap() {
|
||||
Token::DegC => Expr::DegC,
|
||||
Token::DegF => Expr::DegF,
|
||||
Token::DegRe => Expr::DegRe,
|
||||
Token::DegRo => Expr::DegRo,
|
||||
Token::DegDe => Expr::DegDe,
|
||||
Token::DegN => Expr::DegN,
|
||||
_ => parse_eq(iter)
|
||||
};
|
||||
Expr::Convert(Box::new(left), Box::new(right))
|
||||
},
|
||||
_ => left
|
||||
}
|
||||
parse_add(iter)
|
||||
}
|
||||
|
||||
fn parse_unknown(mut iter: &mut Iter) {
|
||||
loop {
|
||||
match iter.peek().cloned().unwrap() {
|
||||
Token::Newline | Token::Comment(_) | Token::Eof => break,
|
||||
_ => iter.next()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_alias(mut iter: &mut Iter) -> Option<(Expr, String)> {
|
||||
match *iter.peek().unwrap() {
|
||||
Token::Newline | Token::Comment(_) | Token::Eof => return None,
|
||||
_ => ()
|
||||
}
|
||||
let expr = parse_expr(iter);
|
||||
match iter.next().unwrap() {
|
||||
Token::TriplePipe => (),
|
||||
_ => return None
|
||||
};
|
||||
let name = match iter.next().unwrap() {
|
||||
Token::Ident(name) => name,
|
||||
_ => return None
|
||||
};
|
||||
match iter.peek().cloned().unwrap() {
|
||||
Token::Newline | Token::Comment(_) | Token::Eof => (),
|
||||
_ => return None
|
||||
};
|
||||
Some((expr, name))
|
||||
}
|
||||
|
||||
fn parse_datepattern(mut iter: &mut Iter) -> Vec<DatePattern> {
|
||||
let mut out = vec![];
|
||||
loop {
|
||||
match iter.peek().cloned().unwrap() {
|
||||
Token::Newline | Token::Comment(_) | Token::Eof | Token::RBrack => break,
|
||||
Token::Ident(name) => out.push(DatePattern::Match(name)),
|
||||
Token::Quote(name) => out.push(DatePattern::Literal(name)),
|
||||
Token::Minus => out.push(DatePattern::Dash),
|
||||
Token::Colon => out.push(DatePattern::Colon),
|
||||
Token::LBrack => {
|
||||
iter.next();
|
||||
let res = DatePattern::Optional(parse_datepattern(iter));
|
||||
let res = match iter.next().unwrap() {
|
||||
Token::RBrack => res,
|
||||
x => DatePattern::Error(format!("Expected ], got {:?}", x))
|
||||
};
|
||||
out.push(res)
|
||||
},
|
||||
x => out.push(DatePattern::Error(format!("Unexpected token {:?} in date pattern", x)))
|
||||
}
|
||||
iter.next();
|
||||
}
|
||||
out
|
||||
fn is_uppercase(name: &str) -> bool {
|
||||
name.find(|c| match c {
|
||||
'A'...'Z' | '_' => false,
|
||||
_ => true
|
||||
}).is_none()
|
||||
}
|
||||
|
||||
pub fn parse(mut iter: &mut Iter) -> Defs {
|
||||
|
@ -375,64 +252,51 @@ pub fn parse(mut iter: &mut Iter) -> Defs {
|
|||
let mut aliases = vec![];
|
||||
let mut line = 1;
|
||||
loop {
|
||||
let mut copy = iter.clone();
|
||||
if let Some(a) = parse_alias(&mut copy) {
|
||||
aliases.push(a);
|
||||
*iter = copy;
|
||||
continue
|
||||
}
|
||||
match iter.next().unwrap() {
|
||||
Token::Newline => line += 1,
|
||||
Token::Comment(lines) => line += lines,
|
||||
Token::Eof => break,
|
||||
Token::Ident(ref name) if name == "datepattern" =>
|
||||
map.push((name.clone(), Rc::new(Def::DatePattern(parse_datepattern(iter))))),
|
||||
Token::Ident(name) => {
|
||||
let def = match iter.next().unwrap() {
|
||||
Token::ColonDash => {
|
||||
let expr = parse_expr(iter);
|
||||
Def::Prefix(expr)
|
||||
},
|
||||
Token::DColonDash => {
|
||||
let expr = parse_expr(iter);
|
||||
Def::SPrefix(expr)
|
||||
},
|
||||
Token::EqBangEq => match iter.next().unwrap() {
|
||||
Token::Ident(val) => Def::Dimension(val),
|
||||
_ => Def::Error(format!("Line {}: Malformed dimensionless unit", line))
|
||||
},
|
||||
Token::ColonEq => Def::Unit(parse_expr(iter)),
|
||||
Token::LBrack => {
|
||||
// NYI
|
||||
let mut n = 0;
|
||||
let mut first = true;
|
||||
loop {
|
||||
match iter.peek().cloned().unwrap() {
|
||||
Token::LBrace => n += 1,
|
||||
Token::RBrace if n == 1 => {
|
||||
iter.next();
|
||||
break
|
||||
},
|
||||
Token::RBrace => n -= 1,
|
||||
Token::Newline | Token::Comment(_) if !first && n == 0 => break,
|
||||
Token::Newline if first => first = false,
|
||||
Token::Eof => break,
|
||||
Token::Comment(lines) => line += lines,
|
||||
_ => ()
|
||||
}
|
||||
iter.next();
|
||||
}
|
||||
continue
|
||||
//Def::Error(format!("NYI: functions"))
|
||||
}
|
||||
_ => {
|
||||
parse_unknown(iter);
|
||||
Def::Error(format!("Line {}: Unknown definition", line))
|
||||
}
|
||||
};
|
||||
map.push((name.clone(), Rc::new(def)));
|
||||
Token::Bang => loop {
|
||||
match iter.next().unwrap() {
|
||||
Token::Eof | Token::Newline => break,
|
||||
_ => ()
|
||||
}
|
||||
},
|
||||
_ => parse_unknown(iter)
|
||||
Token::Ident(name) => {
|
||||
if is_uppercase(&*name) {
|
||||
// alias
|
||||
let mut copy = iter.clone();
|
||||
let expr = parse_expr(&mut copy);
|
||||
aliases.push((expr, name.clone()));
|
||||
}
|
||||
|
||||
if name.ends_with("-") {
|
||||
// prefix
|
||||
let expr = parse_expr(iter);
|
||||
let mut name = name;
|
||||
name.pop();
|
||||
map.push((name, Rc::new(Def::SPrefix(expr))));
|
||||
} else {
|
||||
// unit
|
||||
if let Some(&Token::Bang) = iter.peek() {
|
||||
// dimension
|
||||
iter.next();
|
||||
if let Some(Token::Ident(ref _n)) = iter.peek().cloned() {
|
||||
iter.next();
|
||||
// dimensionless primitive unit
|
||||
// not sure what to do with these
|
||||
map.push((name.clone(), Rc::new(Def::Unit(Expr::Const(
|
||||
"1".to_owned(), None, None)))));
|
||||
} else {
|
||||
map.push((name.clone(), Rc::new(Def::Dimension(name))));
|
||||
}
|
||||
} else {
|
||||
// derived
|
||||
let expr = parse_expr(iter);
|
||||
map.push((name, Rc::new(Def::Unit(expr))));
|
||||
}
|
||||
}
|
||||
},
|
||||
x => println!("Expected definition on line {}, got {:?}", line, x),
|
||||
};
|
||||
}
|
||||
Defs {
|
||||
|
@ -440,7 +304,7 @@ pub fn parse(mut iter: &mut Iter) -> Defs {
|
|||
aliases: aliases,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn tokens(mut iter: &mut Iter) -> Vec<Token> {
|
||||
let mut out = vec![];
|
||||
loop {
|
||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -90,19 +90,19 @@ pub fn load() -> Result<Context, String> {
|
|||
use std::io::Read;
|
||||
use std::fs::File;
|
||||
|
||||
let f = File::open("units.txt");
|
||||
let f = File::open("definitions.units");
|
||||
let mut f = match f {
|
||||
Ok(f) => f,
|
||||
Err(_) => {
|
||||
let mut path = try!(config_dir());
|
||||
path.push("rink/units.txt");
|
||||
path.push("rink/definitions.units");
|
||||
let f = File::open(&path);
|
||||
match f {
|
||||
Ok(f) => f,
|
||||
Err(e) => return Err(format!(
|
||||
concat!("Failed to open units.txt: {}\nIf you installed using `cargo install`, ",
|
||||
"then you need to obtain units.txt separately. Here is the URL, ",
|
||||
"download it and put it in {:?}.\n\n{}\n\n"),
|
||||
"Failed to open definitions.units: {}\nIf you installed using \
|
||||
`cargo install`, then you need to obtain units.txt separately. Here is the \
|
||||
URL, download it and put it in {:?}.\n\n{}\n\n",
|
||||
e, &path, UNITS_TXT_URL))
|
||||
}
|
||||
}
|
||||
|
@ -111,8 +111,10 @@ pub fn load() -> Result<Context, String> {
|
|||
let mut buf = vec![];
|
||||
f.read_to_end(&mut buf).unwrap();
|
||||
let string = String::from_utf8_lossy(&*buf);
|
||||
let mut iter = unit_defs::TokenIterator::new(&*string).peekable();
|
||||
let res = unit_defs::parse(&mut iter);
|
||||
//let mut iter = unit_defs::TokenIterator::new(&*string).peekable();
|
||||
//let res = unit_defs::parse(&mut iter);
|
||||
let mut iter = gnu_units::TokenIterator::new(&*string).peekable();
|
||||
let res = gnu_units::parse(&mut iter);
|
||||
|
||||
Ok(eval::Context::new(res))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue