Add TokenIterator, parse aliases

This commit is contained in:
Tiffany Bennett 2016-08-02 15:52:41 -04:00
parent 0b728865ec
commit 848bb4d4d6
2 changed files with 151 additions and 106 deletions

View file

@ -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);
}

View file

@ -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<Chars<'a>>;
#[derive(Clone)]
pub struct TokenIterator<'a>(Peekable<Chars<'a>>);
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<Token> {
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<TokenIterator<'a>>;
#[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<String, Rc<Def>> {
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<String, Rc<Def>>, 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<Token> {
let mut out = vec![];
loop {
match token(iter) {
match iter.next().unwrap() {
Token::Eof => break,
x => out.push(x)
}