rust: add step9_try. Refactor error handling.
[jackhill/mal.git] / rust / src / reader.rs
1 //#![feature(phase)]
2 //#[phase(plugin)]
3 //extern crate regex_macros;
4 //extern crate regex;
5
6 extern crate pcre;
7
8 use types::{MalVal,MalRet,ErrString,ErrMalVal,
9 _nil,_true,_false,_int,symbol,string,list,vector,hash_mapv,
10 err_str,err_string,err_val};
11 use self::pcre::Pcre;
12 use super::printer::unescape_str;
13
14 #[deriving(Show, Clone)]
15 struct Reader {
16 tokens : Vec<String>,
17 position : uint,
18 }
19
20 impl Reader {
21 fn next(&mut self) -> Option<String> {
22 if self.position < self.tokens.len() {
23 self.position += 1;
24 Some(self.tokens[self.position-1].to_string())
25 } else {
26 None
27 }
28 }
29 fn peek(&self) -> Option<String> {
30 if self.position < self.tokens.len() {
31 Some(self.tokens[self.position].to_string())
32 } else {
33 None
34 }
35 }
36 }
37
38 fn tokenize(str :String) -> Vec<String> {
39 let mut results = vec![];
40
41 let re = match Pcre::compile(r###"[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"###) {
42 Err(_) => { fail!("failed to compile regex") },
43 Ok(re) => re
44 };
45
46 let mut it = re.matches(str.as_slice());
47 loop {
48 let opt_m = it.next();
49 if opt_m.is_none() { break; }
50 let m = opt_m.unwrap();
51 if m.group(1) == "" { break; }
52 if m.group(1).starts_with(";") { continue; }
53
54 results.push((*m.group(1)).to_string());
55 }
56 results
57 }
58
59 fn read_atom(rdr : &mut Reader) -> MalRet {
60 let otoken = rdr.next();
61 //println!("read_atom: {}", otoken);
62 if otoken.is_none() { return err_str("read_atom underflow"); }
63 let stoken = otoken.unwrap();
64 let token = stoken.as_slice();
65 if regex!(r"^-?[0-9]+$").is_match(token) {
66 let num : Option<int> = from_str(token);
67 Ok(_int(num.unwrap()))
68 } else if regex!(r#"^".*"$"#).is_match(token) {
69 let new_str = token.slice(1,token.len()-1);
70 Ok(string(unescape_str(new_str)))
71 } else if token == "nil" {
72 Ok(_nil())
73 } else if token == "true" {
74 Ok(_true())
75 } else if token == "false" {
76 Ok(_false())
77 } else {
78 Ok(symbol(token))
79 }
80 }
81
82 fn read_seq(rdr : &mut Reader, start: &str, end: &str) -> Result<Vec<MalVal>,String> {
83 let otoken = rdr.next();
84 if otoken.is_none() {
85 return Err("read_atom underflow".to_string());
86 }
87 let stoken = otoken.unwrap();
88 let token = stoken.as_slice();
89 if token != start {
90 return Err("expected '".to_string() + start.to_string() + "'".to_string());
91 }
92
93 let mut ast_vec : Vec<MalVal> = vec![];
94 loop {
95 let otoken = rdr.peek();
96 if otoken.is_none() {
97 return Err("expected '".to_string() + end.to_string() + "', got EOF".to_string());
98 }
99 let stoken = otoken.unwrap();
100 let token = stoken.as_slice();
101 if token == end { break; }
102
103 match read_form(rdr) {
104 Ok(mv) => ast_vec.push(mv),
105 Err(ErrString(es)) => return Err(es),
106 Err(ErrMalVal(_)) => return Err("read_seq exception".to_string()),
107 }
108 }
109 rdr.next();
110
111 Ok(ast_vec)
112 }
113
114 fn read_list(rdr : &mut Reader) -> MalRet {
115 match read_seq(rdr, "(", ")") {
116 Ok(seq) => Ok(list(seq)),
117 Err(es) => err_string(es),
118 }
119 }
120
121 fn read_vector(rdr : &mut Reader) -> MalRet {
122 match read_seq(rdr, "[", "]") {
123 Ok(seq) => Ok(vector(seq)),
124 Err(es) => err_string(es),
125 }
126 }
127
128 fn read_hash_map(rdr : &mut Reader) -> MalRet {
129 match read_seq(rdr, "{", "}") {
130 Ok(seq) => hash_mapv(seq),
131 Err(es) => err_string(es),
132 }
133 }
134
135 fn read_form(rdr : &mut Reader) -> MalRet {
136 let otoken = rdr.peek();
137 //println!("read_form: {}", otoken);
138 let stoken = otoken.unwrap();
139 let token = stoken.as_slice();
140 match token {
141 "'" => {
142 let _ = rdr.next();
143 match read_form(rdr) {
144 Ok(f) => Ok(list(vec![symbol("quote"), f])),
145 Err(e) => Err(e),
146 }
147 },
148 "`" => {
149 let _ = rdr.next();
150 match read_form(rdr) {
151 Ok(f) => Ok(list(vec![symbol("quasiquote"), f])),
152 Err(e) => Err(e),
153 }
154 },
155 "~" => {
156 let _ = rdr.next();
157 match read_form(rdr) {
158 Ok(f) => Ok(list(vec![symbol("unquote"), f])),
159 Err(e) => Err(e),
160 }
161 },
162 "~@" => {
163 let _ = rdr.next();
164 match read_form(rdr) {
165 Ok(f) => Ok(list(vec![symbol("splice-unquote"), f])),
166 Err(e) => Err(e),
167 }
168 },
169
170 ")" => err_str("unexected ')'"),
171 "(" => read_list(rdr),
172
173 "]" => err_str("unexected ']'"),
174 "[" => read_vector(rdr),
175
176 "}" => err_str("unexected '}'"),
177 "{" => read_hash_map(rdr),
178
179 _ => read_atom(rdr)
180 }
181 }
182
183 pub fn read_str(str :String) -> MalRet {
184 let tokens = tokenize(str);
185 if tokens.len() == 0 {
186 // any malval as the error slot means empty line
187 return err_val(_nil())
188 }
189 //println!("tokens: {}", tokens);
190 let rdr = &mut Reader{tokens: tokens, position: 0};
191 read_form(rdr)
192 }