From 848bb4d4d642d649326f4e5725eaf18995f1d670 Mon Sep 17 00:00:00 2001 From: Tiffany Bennett Date: Tue, 2 Aug 2016 15:52:41 -0400 Subject: [PATCH] Add TokenIterator, parse aliases --- src/main.rs | 5 +- src/unit_defs.rs | 252 ++++++++++++++++++++++++++++------------------- 2 files changed, 151 insertions(+), 106 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3c51b74..630b9d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,8 @@ fn main() { let mut buf = vec![]; f.read_to_end(&mut buf).unwrap(); let string = String::from_utf8_lossy(&*buf); - //let res = unit_defs::tokens(&mut string.chars().peekable()); - let res = unit_defs::parse(&mut string.chars().peekable()); + let mut iter = unit_defs::TokenIterator::new(&*string).peekable(); + //let res = unit_defs::tokens(&mut iter); + let res = unit_defs::parse(&mut iter); println!("{:#?}", res); } diff --git a/src/unit_defs.rs b/src/unit_defs.rs index 1bd577c..c45c2a2 100644 --- a/src/unit_defs.rs +++ b/src/unit_defs.rs @@ -4,7 +4,7 @@ use std::iter::Peekable; use std::str::FromStr; use std::rc::Rc; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Token { Newline, Comment, @@ -21,87 +21,102 @@ pub enum Token { Error, } -pub type Iter<'a> = Peekable>; +#[derive(Clone)] +pub struct TokenIterator<'a>(Peekable>); -fn token(mut iter: &mut Iter) -> Token { - if iter.peek() == None { - return Token::Eof - } - match iter.next().unwrap() { - ' ' | '\t' => token(iter), - '\n' => Token::Newline, - '/' => match iter.peek() { - Some(&'/') => loop { - match iter.next() { - Some('\n') => return Token::Comment, - _ => () - } - }, - Some(&'*') => loop { - if let Some('*') = iter.next() { - if let Some(&'/') = iter.peek() { - return Token::Comment - } - } - if iter.peek() == None { - return Token::Error - } - }, - _ => Token::Slash - }, - x @ '0'...'9' => { - let mut buf = String::new(); - buf.push(x); - while let Some(c) = iter.peek().cloned() { - match c { - '0'...'9' | 'e' | 'E' | '.' => buf.push(iter.next().unwrap()), - _ => break - } - } - FromStr::from_str(&*buf).map(|x| Token::Number(x)).unwrap_or(Token::Error) - }, - ':' => match iter.next() { - Some(':') => match iter.next() { - Some('-') => Token::DColonDash, - _ => Token::Error - }, - Some('-') => Token::ColonDash, - Some('=') => Token::ColonEq, - _ => Token::Error - }, - '|' => if let Some('|') = iter.next() { - if let Some('|') = iter.next() { - Token::TriplePipe - } else { - Token::Error - } - } else { - Token::Error - }, - '=' => if let Some('!') = iter.next() { - if let Some('=') = iter.next() { - Token::EqBangEq - } else { - Token::Error - } - } else { - Token::Error - }, - '^' => Token::Carot, - x => { - let mut buf = String::new(); - buf.push(x); - while let Some(c) = iter.peek().cloned() { - match c { - ' ' | '\t' | '\n' | '/' | '^' | ':' | '=' | '-' | '0'...'9' => break, - _ => buf.push(iter.next().unwrap()) - } - } - Token::Ident(buf) - } +impl<'a> TokenIterator<'a> { + pub fn new(input: &'a str) -> TokenIterator<'a> { + TokenIterator(input.chars().peekable()) } } +impl<'a> Iterator for TokenIterator<'a> { + type Item = Token; + + fn next(&mut self) -> Option { + if self.0.peek() == None { + return Some(Token::Eof) + } + let res = match self.0.next().unwrap() { + ' ' | '\t' => return self.next(), + '\n' => Token::Newline, + '/' => match self.0.peek() { + Some(&'/') => loop { + match self.0.next() { + Some('\n') => return Some(Token::Comment), + _ => () + } + }, + Some(&'*') => loop { + if let Some('*') = self.0.next() { + if let Some(&'/') = self.0.peek() { + return Some(Token::Comment) + } + } + if self.0.peek() == None { + return Some(Token::Error) + } + }, + _ => Token::Slash + }, + x @ '0'...'9' | x @ '-' => { + let mut buf = String::new(); + buf.push(x); + while let Some(c) = self.0.peek().cloned() { + match c { + '0'...'9' | 'e' | 'E' | '.' => buf.push(self.0.next().unwrap()), + _ => break + } + } + FromStr::from_str(&*buf).map(|x| Token::Number(x)).unwrap_or(Token::Error) + }, + ':' => match self.0.next() { + Some(':') => match self.0.next() { + Some('-') => Token::DColonDash, + _ => Token::Error + }, + Some('-') => Token::ColonDash, + Some('=') => Token::ColonEq, + _ => Token::Error + }, + '|' => if let Some('|') = self.0.next() { + if let Some('|') = self.0.next() { + Token::TriplePipe + } else { + Token::Error + } + } else { + Token::Error + }, + '=' => if let Some('!') = self.0.next() { + if let Some('=') = self.0.next() { + Token::EqBangEq + } else { + Token::Error + } + } else { + Token::Error + }, + '^' => Token::Carot, + x => { + let mut buf = String::new(); + buf.push(x); + while let Some(c) = self.0.peek().cloned() { + if c.is_alphanumeric() { + buf.push(self.0.next().unwrap()); + } else { + break; + } + } + Token::Ident(buf) + } + }; + Some(res) + } +} + +pub type Iter<'a> = Peekable>; + #[derive(Debug)] pub enum Expr { Unit(String), @@ -122,7 +137,7 @@ pub enum Def { } fn parse_term(mut iter: &mut Iter) -> Expr { - match token(iter) { + match iter.next().unwrap() { Token::Ident(name) => Expr::Unit(name), Token::Number(num) => Expr::Const(num), x => Expr::Error(format!("Expected term, got {:?}", x)) @@ -131,10 +146,9 @@ fn parse_term(mut iter: &mut Iter) -> Expr { fn parse_pow(mut iter: &mut Iter) -> Expr { let left = parse_term(iter); - let mut copy = iter.clone(); - match token(&mut copy) { + match *iter.peek().unwrap() { Token::Carot => { - token(iter); + iter.next(); let right = parse_pow(iter); match right { Expr::Const(n) => Expr::Pow(Box::new(left), n), @@ -147,10 +161,9 @@ fn parse_pow(mut iter: &mut Iter) -> Expr { fn parse_frac(mut iter: &mut Iter) -> Expr { let left = parse_pow(iter); - let mut copy = iter.clone(); - match token(&mut copy) { + match *iter.peek().unwrap() { Token::Slash => { - token(iter); + iter.next(); let right = parse_frac(iter); Expr::Frac(Box::new(left), Box::new(right)) }, @@ -161,9 +174,12 @@ fn parse_frac(mut iter: &mut Iter) -> Expr { fn parse_expr(mut iter: &mut Iter) -> Expr { let mut terms = vec![]; loop { - let mut copy = iter.clone(); - match token(&mut copy) { - Token::Newline | Token::Comment | Token::Eof => {iter.next(); break}, + match *iter.peek().unwrap() { + Token::TriplePipe => break, + Token::Newline | Token::Comment | Token::Eof => { + iter.next(); + break + }, _ => terms.push(parse_frac(iter)) } } @@ -174,44 +190,72 @@ fn parse_expr(mut iter: &mut Iter) -> Expr { } } -pub fn parse(mut iter: &mut Iter) -> HashMap> { - let mut map = HashMap::new(); +fn parse_unknown(mut iter: &mut Iter) { loop { - match token(iter) { - Token::Newline => {token(iter); continue}, - Token::Comment => {token(iter); continue}, + match iter.next().unwrap() { + Token::Newline | Token::Comment | Token::Eof => break, + _ => () + } + } +} + +fn parse_alias(mut iter: &mut Iter) -> Option<(Expr, String)> { + 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.next().unwrap() { + Token::Newline | Token::Comment | Token::Eof => (), + _ => return None + }; + Some((expr, name)) +} + +pub fn parse(mut iter: &mut Iter) -> (HashMap>, Vec<(Expr, String)>) { + let mut map = HashMap::new(); + let mut aliases = vec![]; + 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 => continue, + Token::Comment => continue, Token::Eof => break, Token::Ident(name) => { - let def = match token(iter) { + let def = match iter.next().unwrap() { Token::ColonDash => Def::Prefix(parse_expr(iter)), Token::DColonDash => Def::SPrefix(parse_expr(iter)), - Token::EqBangEq => match token(iter) { + Token::EqBangEq => match iter.next().unwrap() { Token::Ident(val) => Def::Dimension(val), _ => Def::Error(format!("Malformed dimensionless unit")) }, Token::ColonEq => Def::Unit(parse_expr(iter)), _ => { - loop { - match token(iter) { - Token::Newline | Token::Comment | Token::Eof => break, - _ => () - } - } + parse_unknown(iter); Def::Error(format!("Unknown definition")) } }; map.insert(name.clone(), Rc::new(def)); }, - _ => () + _ => parse_unknown(iter) }; } - map + (map, aliases) } pub fn tokens(mut iter: &mut Iter) -> Vec { let mut out = vec![]; loop { - match token(iter) { + match iter.next().unwrap() { Token::Eof => break, x => out.push(x) }