mirror of
https://github.com/tiffany352/rink-rs
synced 2024-11-10 13:44:15 +00:00
Add TokenIterator, parse aliases
This commit is contained in:
parent
0b728865ec
commit
848bb4d4d6
2 changed files with 151 additions and 106 deletions
|
@ -7,7 +7,8 @@ fn main() {
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
f.read_to_end(&mut buf).unwrap();
|
f.read_to_end(&mut buf).unwrap();
|
||||||
let string = String::from_utf8_lossy(&*buf);
|
let string = String::from_utf8_lossy(&*buf);
|
||||||
//let res = unit_defs::tokens(&mut string.chars().peekable());
|
let mut iter = unit_defs::TokenIterator::new(&*string).peekable();
|
||||||
let res = unit_defs::parse(&mut string.chars().peekable());
|
//let res = unit_defs::tokens(&mut iter);
|
||||||
|
let res = unit_defs::parse(&mut iter);
|
||||||
println!("{:#?}", res);
|
println!("{:#?}", res);
|
||||||
}
|
}
|
||||||
|
|
252
src/unit_defs.rs
252
src/unit_defs.rs
|
@ -4,7 +4,7 @@ use std::iter::Peekable;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
Newline,
|
Newline,
|
||||||
Comment,
|
Comment,
|
||||||
|
@ -21,87 +21,102 @@ pub enum Token {
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Iter<'a> = Peekable<Chars<'a>>;
|
#[derive(Clone)]
|
||||||
|
pub struct TokenIterator<'a>(Peekable<Chars<'a>>);
|
||||||
|
|
||||||
fn token(mut iter: &mut Iter) -> Token {
|
impl<'a> TokenIterator<'a> {
|
||||||
if iter.peek() == None {
|
pub fn new(input: &'a str) -> TokenIterator<'a> {
|
||||||
return Token::Eof
|
TokenIterator(input.chars().peekable())
|
||||||
}
|
|
||||||
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> 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)]
|
#[derive(Debug)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
Unit(String),
|
Unit(String),
|
||||||
|
@ -122,7 +137,7 @@ pub enum Def {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_term(mut iter: &mut Iter) -> Expr {
|
fn parse_term(mut iter: &mut Iter) -> Expr {
|
||||||
match token(iter) {
|
match iter.next().unwrap() {
|
||||||
Token::Ident(name) => Expr::Unit(name),
|
Token::Ident(name) => Expr::Unit(name),
|
||||||
Token::Number(num) => Expr::Const(num),
|
Token::Number(num) => Expr::Const(num),
|
||||||
x => Expr::Error(format!("Expected term, got {:?}", x))
|
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 {
|
fn parse_pow(mut iter: &mut Iter) -> Expr {
|
||||||
let left = parse_term(iter);
|
let left = parse_term(iter);
|
||||||
let mut copy = iter.clone();
|
match *iter.peek().unwrap() {
|
||||||
match token(&mut copy) {
|
|
||||||
Token::Carot => {
|
Token::Carot => {
|
||||||
token(iter);
|
iter.next();
|
||||||
let right = parse_pow(iter);
|
let right = parse_pow(iter);
|
||||||
match right {
|
match right {
|
||||||
Expr::Const(n) => Expr::Pow(Box::new(left), n),
|
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 {
|
fn parse_frac(mut iter: &mut Iter) -> Expr {
|
||||||
let left = parse_pow(iter);
|
let left = parse_pow(iter);
|
||||||
let mut copy = iter.clone();
|
match *iter.peek().unwrap() {
|
||||||
match token(&mut copy) {
|
|
||||||
Token::Slash => {
|
Token::Slash => {
|
||||||
token(iter);
|
iter.next();
|
||||||
let right = parse_frac(iter);
|
let right = parse_frac(iter);
|
||||||
Expr::Frac(Box::new(left), Box::new(right))
|
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 {
|
fn parse_expr(mut iter: &mut Iter) -> Expr {
|
||||||
let mut terms = vec![];
|
let mut terms = vec![];
|
||||||
loop {
|
loop {
|
||||||
let mut copy = iter.clone();
|
match *iter.peek().unwrap() {
|
||||||
match token(&mut copy) {
|
Token::TriplePipe => break,
|
||||||
Token::Newline | Token::Comment | Token::Eof => {iter.next(); break},
|
Token::Newline | Token::Comment | Token::Eof => {
|
||||||
|
iter.next();
|
||||||
|
break
|
||||||
|
},
|
||||||
_ => terms.push(parse_frac(iter))
|
_ => 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>> {
|
fn parse_unknown(mut iter: &mut Iter) {
|
||||||
let mut map = HashMap::new();
|
|
||||||
loop {
|
loop {
|
||||||
match token(iter) {
|
match iter.next().unwrap() {
|
||||||
Token::Newline => {token(iter); continue},
|
Token::Newline | Token::Comment | Token::Eof => break,
|
||||||
Token::Comment => {token(iter); continue},
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::Eof => break,
|
||||||
Token::Ident(name) => {
|
Token::Ident(name) => {
|
||||||
let def = match token(iter) {
|
let def = match iter.next().unwrap() {
|
||||||
Token::ColonDash => Def::Prefix(parse_expr(iter)),
|
Token::ColonDash => Def::Prefix(parse_expr(iter)),
|
||||||
Token::DColonDash => Def::SPrefix(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),
|
Token::Ident(val) => Def::Dimension(val),
|
||||||
_ => Def::Error(format!("Malformed dimensionless unit"))
|
_ => Def::Error(format!("Malformed dimensionless unit"))
|
||||||
},
|
},
|
||||||
Token::ColonEq => Def::Unit(parse_expr(iter)),
|
Token::ColonEq => Def::Unit(parse_expr(iter)),
|
||||||
_ => {
|
_ => {
|
||||||
loop {
|
parse_unknown(iter);
|
||||||
match token(iter) {
|
|
||||||
Token::Newline | Token::Comment | Token::Eof => break,
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Def::Error(format!("Unknown definition"))
|
Def::Error(format!("Unknown definition"))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
map.insert(name.clone(), Rc::new(def));
|
map.insert(name.clone(), Rc::new(def));
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => parse_unknown(iter)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
map
|
(map, aliases)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tokens(mut iter: &mut Iter) -> Vec<Token> {
|
pub fn tokens(mut iter: &mut Iter) -> Vec<Token> {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
loop {
|
loop {
|
||||||
match token(iter) {
|
match iter.next().unwrap() {
|
||||||
Token::Eof => break,
|
Token::Eof => break,
|
||||||
x => out.push(x)
|
x => out.push(x)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue