123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- use std::collections::HashMap;
- use std::iter::Peekable;
- use std::str::{Chars,FromStr};
- #[derive(Clone,Debug,PartialEq)]
- pub enum Adnot {
- Sum(String, Vec<Adnot>),
- Prod(HashMap<String, Adnot>),
- List(Vec<Adnot>),
- Str(String),
- Sym(String),
- Num(i64),
- Dbl(f64),
- }
- #[derive(Debug)]
- pub struct AdnotError {
- message: String,
- }
- type Stream<'a> = Peekable<Chars<'a>>;
- fn fail<T>(s: &str) -> Result<T, AdnotError> {
- Err(AdnotError { message: s.to_string()})
- }
- fn parse_val(s: &mut Stream) -> Result<Adnot, AdnotError> {
- if let Some(c) = s.next() {
- match c {
- '[' => parse_list(s),
- '(' => parse_sum(s),
- '{' => parse_prod(s),
- '"' => parse_string(s),
- _ if c.is_digit(10) || c == '-' => parse_num(c, s),
- _ if c.is_alphabetic() =>
- Ok(Adnot::Sym(try!(parse_sym(c, s)))),
- _ => fail(&format!("Invalid character: {:?}", c)),
- }
- } else {
- fail("Unexpected end of input")
- }
- }
- fn parse_list(s: &mut Stream) -> Result<Adnot, AdnotError> {
- let mut vec = vec![];
- loop {
- skip_space(s);
- if let Some(&']') = s.peek() {
- s.next();
- return Ok(Adnot::List(vec));
- } else {
- vec.push(try!(parse_val(s)));
- }
- }
- }
- fn parse_sum(s: &mut Stream) -> Result<Adnot, AdnotError> {
- let mut vec = vec![];
- skip_space(s);
- let first = match s.next() {
- Some(c) if c.is_alphabetic() => c,
- Some(_) => { return fail("Expected a tagname character") }
- None => { return fail("Unexpected end of input") }
- };
- let name = try!(parse_sym(first, s));
- loop {
- skip_space(s);
- if let Some(&')') = s.peek() {
- s.next();
- return Ok(Adnot::Sum(name, vec));
- } else {
- vec.push(try!(parse_val(s)));
- }
- }
- }
- fn parse_prod(s: &mut Stream) -> Result<Adnot, AdnotError> {
- let mut map = HashMap::new();
- loop {
- skip_space(s);
- if let Some(&'}') = s.peek() {
- s.next();
- return Ok(Adnot::Prod(map));
- } else {
- skip_space(s);
- let first = match s.next() {
- Some(c) if c.is_alphabetic() => c,
- Some(_) => { return fail("Expected a tagname character") }
- None => { return fail("Unexpected end of input") }
- };
- let key = try!(parse_sym(first, s));
- skip_space(s);
- let val = try!(parse_val(s));
- map.insert(key, val);
- }
- }
- }
- fn parse_string(s: &mut Stream) -> Result<Adnot, AdnotError> {
- let mut chars = Vec::new();
- while let Some(c) = s.next() {
- if c == '"' {
- break;
- } else if c == '\\' {
- match s.next() {
- Some('n') => chars.push('\n'),
- Some('r') => chars.push('\r'),
- Some('t') => chars.push('\t'),
- Some('\'') => chars.push('\''),
- Some('\"') => chars.push('\"'),
- Some('\\') => chars.push('\\'),
- _ => return fail("Invalid escape sequence"),
- }
- } else {
- chars.push(c);
- }
- };
- Ok(Adnot::Str(chars.iter().cloned().collect()))
- }
- fn parse_num(c: char, s: &mut Stream) -> Result<Adnot, AdnotError> {
- let mut str = vec![c];
- str.extend(s.take_while(|c| c.is_digit(10)));
- let string: String = str.iter().cloned().collect();
- Ok(Adnot::Num(i64::from_str(&string).unwrap()))
- }
- fn parse_sym(c: char, s: &mut Stream) -> Result<String, AdnotError> {
- let mut chars = vec![c];
- while let Some(&c) = s.peek() {
- if c.is_alphanumeric() || c == '_' {
- chars.push(s.next().unwrap());
- } else {
- break;
- }
- };
- Ok(chars.iter().cloned().collect())
- }
- fn skip_space(s: &mut Stream) {
- while let Some(&c) = s.peek() {
- match c {
- '#' => { skip_comment(s); }
- _ if c.is_whitespace() => { s.next(); }
- _ => break,
- }
- }
- }
- fn skip_comment(s: &mut Stream) {
- s.next();
- while let Some(&c) = s.peek() {
- if c == '\n' || c == '\r' {
- s.next();
- return;
- } else {
- s.next();
- }
- }
- }
- impl Adnot {
- pub fn parse(s: &str) -> Result<Adnot, AdnotError> {
- let mut stream = s.chars().peekable();
- skip_space(&mut stream);
- parse_val(&mut stream)
- }
- }
|