//#![feature(phase)] //#[phase(plugin)] //extern crate regex_macros; //extern crate regex; extern crate pcre; use types::{MalVal,MalRet, _nil,_true,_false,_int,symbol,string,list}; use self::pcre::Pcre; use super::printer::unescape_str; #[deriving(Show, Clone)] struct Reader { tokens : Vec, position : uint, } impl Reader { fn next(&mut self) -> Option { if self.position < self.tokens.len() { self.position += 1; Some(self.tokens[self.position-1].to_string()) } else { None } } fn peek(&self) -> Option { if self.position < self.tokens.len() { Some(self.tokens[self.position].to_string()) } else { None } } } fn tokenize(str :String) -> Vec { let mut results = vec![]; let re = match Pcre::compile(r###"[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"###) { Err(_) => { fail!("failed to compile regex") }, Ok(re) => re }; let mut it = re.matches(str.as_slice()); loop { let opt_m = it.next(); if opt_m.is_none() { break; } let m = opt_m.unwrap(); if m.group(1) == "" { break; } results.push((*m.group(1)).to_string()); } results } fn read_atom(rdr : &mut Reader) -> MalRet { let otoken = rdr.next(); //println!("read_atom: {}", otoken); if otoken.is_none() { return Err("read_atom underflow".to_string()); } let stoken = otoken.unwrap(); let token = stoken.as_slice(); if regex!(r"^-?[0-9]+$").is_match(token) { let num : Option = from_str(token); Ok(_int(num.unwrap())) } else if regex!(r#"^".*"$"#).is_match(token) { let new_str = token.slice(1,token.len()-1); Ok(string(unescape_str(new_str))) } else if token == "nil" { Ok(_nil()) } else if token == "true" { Ok(_true()) } else if token == "false" { Ok(_false()) } else { Ok(symbol(token)) } } fn read_list(rdr : &mut Reader) -> MalRet { let otoken = rdr.next(); if otoken.is_none() { return Err("read_atom underflow".to_string()); } let stoken = otoken.unwrap(); let token = stoken.as_slice(); if token != "(" { return Err("expected '('".to_string()); } let mut ast_vec : Vec = vec![]; loop { let otoken = rdr.peek(); if otoken.is_none() { return Err("expected ')', got EOF".to_string()); } let stoken = otoken.unwrap(); let token = stoken.as_slice(); if token == ")" { break; } match read_form(rdr) { Ok(mv) => ast_vec.push(mv), Err(e) => return Err(e), } } rdr.next(); Ok(list(ast_vec)) } fn read_form(rdr : &mut Reader) -> MalRet { let otoken = rdr.peek(); //println!("read_form: {}", otoken); let stoken = otoken.unwrap(); let token = stoken.as_slice(); match token { "'" => { let _ = rdr.next(); match read_form(rdr) { Ok(f) => Ok(list(vec![symbol("quote"), f])), Err(e) => Err(e), } }, "`" => { let _ = rdr.next(); match read_form(rdr) { Ok(f) => Ok(list(vec![symbol("quasiquote"), f])), Err(e) => Err(e), } }, "~" => { let _ = rdr.next(); match read_form(rdr) { Ok(f) => Ok(list(vec![symbol("unquote"), f])), Err(e) => Err(e), } }, "~@" => { let _ = rdr.next(); match read_form(rdr) { Ok(f) => Ok(list(vec![symbol("splice-unquote"), f])), Err(e) => Err(e), } }, ")" => Err("unexected ')'".to_string()), "(" => read_list(rdr), _ => read_atom(rdr) } } pub fn read_str(str :String) -> MalRet { let tokens = tokenize(str); if tokens.len() == 0 { return Err("".to_string()); } //println!("tokens: {}", tokens); let rdr = &mut Reader{tokens: tokens, position: 0}; read_form(rdr) }