diff options
| author | Joel Martin <github@martintribe.org> | 2014-10-27 20:07:29 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-10-27 20:07:29 -0500 |
| commit | 5939404b0fb822fd29a483dc0d0a4d716cef206e (patch) | |
| tree | 8196739b701df4fb7b61fed967eaca28f61d4b57 /rust/src | |
| parent | a77e2b31de9d1c1f5767e6bff56062f8b3c71211 (diff) | |
| download | mal-5939404b0fb822fd29a483dc0d0a4d716cef206e.tar.gz mal-5939404b0fb822fd29a483dc0d0a4d716cef206e.zip | |
rust: add vector and hash-map support.
Diffstat (limited to 'rust/src')
| -rw-r--r-- | rust/src/core.rs | 20 | ||||
| -rw-r--r-- | rust/src/reader.rs | 49 | ||||
| -rw-r--r-- | rust/src/step1_read_print.rs | 6 | ||||
| -rw-r--r-- | rust/src/step2_eval.rs | 26 | ||||
| -rw-r--r-- | rust/src/step3_env.rs | 21 | ||||
| -rw-r--r-- | rust/src/step4_if_fn_do.rs | 22 | ||||
| -rw-r--r-- | rust/src/step5_tco.rs | 22 | ||||
| -rw-r--r-- | rust/src/step6_file.rs | 21 | ||||
| -rw-r--r-- | rust/src/step7_quote.rs | 21 | ||||
| -rw-r--r-- | rust/src/step8_macros.rs | 21 | ||||
| -rw-r--r-- | rust/src/types.rs | 48 |
11 files changed, 211 insertions, 66 deletions
diff --git a/rust/src/core.rs b/rust/src/core.rs index 3e1889c..98eb32a 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -4,7 +4,7 @@ extern crate time; use std::collections::HashMap; use std::io::File; -use types::{MalVal,MalRet,Int,Strn,List, +use types::{MalVal,MalRet,Int,Strn,List,Vector, _nil,_true,_false,_int,string,list,func}; use reader; use printer; @@ -120,7 +120,7 @@ pub fn list_q(a:Vec<MalVal>) -> MalRet { pub fn cons(a:Vec<MalVal>) -> MalRet { match *a[1] { - List(ref v) => { + List(ref v) | Vector(ref v) => { let mut new_v = v.clone(); new_v.insert(0, a[0].clone()); Ok(list(new_v)) @@ -133,7 +133,7 @@ pub fn concat(a:Vec<MalVal>) -> MalRet { let mut new_v:Vec<MalVal> = vec![]; for lst in a.iter() { match **lst { - List(ref l) => { + List(ref l) | Vector(ref l) => { new_v.push_all(l.as_slice()); }, _ => return Err("concat called with non-sequence".to_string()), @@ -149,7 +149,7 @@ pub fn nth(a:Vec<MalVal>) -> MalRet { let a0 = a[0].clone(); let a1 = a[1].clone(); let seq = match *a0 { - List(ref v) => v, + List(ref v) | Vector(ref v) => v, _ => return Err("nth called with non-sequence".to_string()), }; let idx = match *a1 { @@ -174,7 +174,7 @@ pub fn first(a:Vec<MalVal>) -> MalRet { } let a0 = a[0].clone(); let seq = match *a0 { - List(ref v) => v, + List(ref v) | Vector(ref v) => v, _ => return Err("first called with non-sequence".to_string()), }; if seq.len() == 0 { @@ -190,7 +190,7 @@ pub fn rest(a:Vec<MalVal>) -> MalRet { } let a0 = a[0].clone(); let seq = match *a0 { - List(ref v) => v, + List(ref v) | Vector(ref v) => v, _ => return Err("rest called with non-sequence".to_string()), }; if seq.len() == 0 { @@ -205,8 +205,8 @@ pub fn count(a:Vec<MalVal>) -> MalRet { return Err("Wrong arity to count call".to_string()); } match *a[0].clone() { - List(ref lst) => { - Ok(_int(lst.len().to_int().unwrap())) + List(ref v) | Vector(ref v) => { + Ok(_int(v.len().to_int().unwrap())) }, _ => Err("count called on non-sequence".to_string()), } @@ -217,8 +217,8 @@ pub fn empty_q(a:Vec<MalVal>) -> MalRet { return Err("Wrong arity to empty? call".to_string()); } match *a[0].clone() { - List(ref lst) => { - match lst.len() { + List(ref v) | Vector(ref v) => { + match v.len() { 0 => Ok(_true()), _ => Ok(_false()), } diff --git a/rust/src/reader.rs b/rust/src/reader.rs index f0ef2e3..6a52dd2 100644 --- a/rust/src/reader.rs +++ b/rust/src/reader.rs @@ -6,7 +6,7 @@ extern crate pcre; use types::{MalVal,MalRet, - _nil,_true,_false,_int,symbol,string,list}; + _nil,_true,_false,_int,symbol,string,list,vector,hash_mapv}; use self::pcre::Pcre; use super::printer::unescape_str; @@ -48,6 +48,7 @@ fn tokenize(str :String) -> Vec<String> { if opt_m.is_none() { break; } let m = opt_m.unwrap(); if m.group(1) == "" { break; } + if m.group(1).starts_with(";") { continue; } results.push((*m.group(1)).to_string()); } @@ -77,20 +78,26 @@ fn read_atom(rdr : &mut Reader) -> MalRet { } } -fn read_list(rdr : &mut Reader) -> MalRet { +fn read_seq(rdr : &mut Reader, start: &str, end: &str) -> Result<Vec<MalVal>,String> { let otoken = rdr.next(); - if otoken.is_none() { return Err("read_atom underflow".to_string()); } + 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()); } + if token != start { + return Err("expected '".to_string() + start.to_string() + "'".to_string()); + } let mut ast_vec : Vec<MalVal> = vec![]; loop { let otoken = rdr.peek(); - if otoken.is_none() { return Err("expected ')', got EOF".to_string()); } + if otoken.is_none() { + return Err("expected '".to_string() + end.to_string() + "', got EOF".to_string()); + } let stoken = otoken.unwrap(); let token = stoken.as_slice(); - if token == ")" { break; } + if token == end { break; } match read_form(rdr) { Ok(mv) => ast_vec.push(mv), @@ -99,7 +106,28 @@ fn read_list(rdr : &mut Reader) -> MalRet { } rdr.next(); - Ok(list(ast_vec)) + Ok(ast_vec) +} + +fn read_list(rdr : &mut Reader) -> MalRet { + match read_seq(rdr, "(", ")") { + Ok(seq) => Ok(list(seq)), + Err(e) => Err(e), + } +} + +fn read_vector(rdr : &mut Reader) -> MalRet { + match read_seq(rdr, "[", "]") { + Ok(seq) => Ok(vector(seq)), + Err(e) => Err(e), + } +} + +fn read_hash_map(rdr : &mut Reader) -> MalRet { + match read_seq(rdr, "{", "}") { + Ok(seq) => hash_mapv(seq), + Err(e) => Err(e), + } } fn read_form(rdr : &mut Reader) -> MalRet { @@ -139,6 +167,13 @@ fn read_form(rdr : &mut Reader) -> MalRet { ")" => Err("unexected ')'".to_string()), "(" => read_list(rdr), + + "]" => Err("unexected ']'".to_string()), + "[" => read_vector(rdr), + + "}" => Err("unexected '}'".to_string()), + "{" => read_hash_map(rdr), + _ => read_atom(rdr) } } diff --git a/rust/src/step1_read_print.rs b/rust/src/step1_read_print.rs index 25ca9b5..d69ea6d 100644 --- a/rust/src/step1_read_print.rs +++ b/rust/src/step1_read_print.rs @@ -45,7 +45,11 @@ fn main() { match line { None => break, _ => () } match rep(line.unwrap()) { Ok(str) => println!("{}", str), - Err(str) => println!("Error: {}", str), + Err(str) => { + if str.as_slice() != "<empty line>" { + println!("Error: {}", str) + } + } } } } diff --git a/rust/src/step2_eval.rs b/rust/src/step2_eval.rs index f8046b9..4a0fcb5 100644 --- a/rust/src/step2_eval.rs +++ b/rust/src/step2_eval.rs @@ -6,8 +6,8 @@ extern crate regex; use std::collections::HashMap; -use types::{MalVal,MalRet,Int,Sym,List, - _nil,_int,list,func}; +use types::{MalVal,MalRet,Int,Sym,List,Vector,Hash_Map, + _nil,_int,list,vector,hash_map,func}; mod readline; mod types; mod env; @@ -28,16 +28,26 @@ fn eval_ast(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet { None => Ok(_nil()), } }, - List(ref a) => { + List(ref a) | Vector(ref a) => { let mut ast_vec : Vec<MalVal> = vec![]; for mv in a.iter() { - let mv2 = mv.clone(); - match eval(mv2, env) { - Ok(mv) => { ast_vec.push(mv); }, - Err(e) => { return Err(e); }, + match eval(mv.clone(), env) { + Ok(mv) => ast_vec.push(mv), + Err(e) => return Err(e), } } - Ok(list(ast_vec)) + Ok(match *ast { List(_) => list(ast_vec), + _ => vector(ast_vec) }) + }, + Hash_Map(ref hm) => { + let mut new_hm: HashMap<String,MalVal> = HashMap::new(); + for (key, value) in hm.iter() { + match eval(value.clone(), env) { + Ok(mv) => { new_hm.insert(key.to_string(), mv); }, + Err(e) => return Err(e), + } + } + Ok(hash_map(new_hm)) }, _ => { Ok(ast.clone()) diff --git a/rust/src/step3_env.rs b/rust/src/step3_env.rs index 4646a97..f9f79ea 100644 --- a/rust/src/step3_env.rs +++ b/rust/src/step3_env.rs @@ -4,8 +4,10 @@ extern crate regex_macros; extern crate regex; -use types::{MalVal,MalRet,Int,Sym,List,Vector, - _int,list,func}; +use std::collections::HashMap; + +use types::{MalVal,MalRet,Int,Sym,List,Vector,Hash_Map, + _int,list,vector,hash_map,func}; use env::{Env,env_new,env_set,env_get}; mod readline; mod types; @@ -26,7 +28,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Sym(ref sym) => { env_get(env.clone(), sym.clone()) }, - List(ref a) => { + List(ref a) | Vector(ref a) => { let mut ast_vec : Vec<MalVal> = vec![]; for mv in a.iter() { let mv2 = mv.clone(); @@ -35,7 +37,18 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Err(e) => { return Err(e); }, } } - Ok(list(ast_vec)) + Ok(match *ast { List(_) => list(ast_vec), + _ => vector(ast_vec) }) + }, + Hash_Map(ref hm) => { + let mut new_hm: HashMap<String,MalVal> = HashMap::new(); + for (key, value) in hm.iter() { + match eval(value.clone(), env.clone()) { + Ok(mv) => { new_hm.insert(key.to_string(), mv); }, + Err(e) => return Err(e), + } + } + Ok(hash_map(new_hm)) }, _ => { Ok(ast) diff --git a/rust/src/step4_if_fn_do.rs b/rust/src/step4_if_fn_do.rs index 175d1be..0f3603d 100644 --- a/rust/src/step4_if_fn_do.rs +++ b/rust/src/step4_if_fn_do.rs @@ -4,9 +4,10 @@ extern crate regex_macros; extern crate regex; -use types::{MalVal,MalRet, - Nil,False,Sym,List,Vector, - _nil,list,malfunc}; +use std::collections::HashMap; + +use types::{MalVal,MalRet,Nil,False,Sym,List,Vector,Hash_Map, + _nil,list,vector,hash_map,malfunc}; use env::{Env,env_new,env_set,env_get}; mod readline; mod types; @@ -28,7 +29,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Sym(ref sym) => { env_get(env.clone(), sym.clone()) }, - List(ref a) => { + List(ref a) | Vector(ref a) => { let mut ast_vec : Vec<MalVal> = vec![]; for mv in a.iter() { let mv2 = mv.clone(); @@ -37,7 +38,18 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Err(e) => { return Err(e); }, } } - Ok(list(ast_vec)) + Ok(match *ast { List(_) => list(ast_vec), + _ => vector(ast_vec) }) + }, + Hash_Map(ref hm) => { + let mut new_hm: HashMap<String,MalVal> = HashMap::new(); + for (key, value) in hm.iter() { + match eval(value.clone(), env.clone()) { + Ok(mv) => { new_hm.insert(key.to_string(), mv); }, + Err(e) => return Err(e), + } + } + Ok(hash_map(new_hm)) }, _ => { Ok(ast) diff --git a/rust/src/step5_tco.rs b/rust/src/step5_tco.rs index 345ec52..9c826c7 100644 --- a/rust/src/step5_tco.rs +++ b/rust/src/step5_tco.rs @@ -4,9 +4,10 @@ extern crate regex_macros; extern crate regex; -use types::{MalVal,MalRet,MalFunc, - Nil,False,Sym,List,Vector,Func, - _nil,list,malfunc}; +use std::collections::HashMap; + +use types::{MalVal,MalRet,MalFunc,Nil,False,Sym,List,Vector,Hash_Map,Func, + _nil,list,vector,hash_map,malfunc}; use env::{Env,env_new,env_bind,env_set,env_get}; mod readline; mod types; @@ -28,7 +29,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Sym(ref sym) => { env_get(env.clone(), sym.clone()) }, - List(ref a) => { + List(ref a) | Vector(ref a) => { let mut ast_vec : Vec<MalVal> = vec![]; for mv in a.iter() { let mv2 = mv.clone(); @@ -37,7 +38,18 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Err(e) => { return Err(e); }, } } - Ok(list(ast_vec)) + Ok(match *ast { List(_) => list(ast_vec), + _ => vector(ast_vec) }) + }, + Hash_Map(ref hm) => { + let mut new_hm: HashMap<String,MalVal> = HashMap::new(); + for (key, value) in hm.iter() { + match eval(value.clone(), env.clone()) { + Ok(mv) => { new_hm.insert(key.to_string(), mv); }, + Err(e) => return Err(e), + } + } + Ok(hash_map(new_hm)) }, _ => { Ok(ast) diff --git a/rust/src/step6_file.rs b/rust/src/step6_file.rs index 1b3427c..237b7f0 100644 --- a/rust/src/step6_file.rs +++ b/rust/src/step6_file.rs @@ -4,11 +4,11 @@ extern crate regex_macros; extern crate regex; +use std::collections::HashMap; use std::os; -use types::{MalVal,MalRet,MalFunc, - Nil,False,Sym,List,Vector,Func, - _nil,string,list,malfunc}; +use types::{MalVal,MalRet,MalFunc,Nil,False,Sym,List,Vector,Hash_Map,Func, + _nil,string,list,vector,hash_map,malfunc}; use env::{Env,env_new,env_bind,env_root,env_set,env_get}; mod readline; mod types; @@ -30,7 +30,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Sym(ref sym) => { env_get(env.clone(), sym.clone()) }, - List(ref a) => { + List(ref a) | Vector(ref a) => { let mut ast_vec : Vec<MalVal> = vec![]; for mv in a.iter() { let mv2 = mv.clone(); @@ -39,7 +39,18 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Err(e) => { return Err(e); }, } } - Ok(list(ast_vec)) + Ok(match *ast { List(_) => list(ast_vec), + _ => vector(ast_vec) }) + }, + Hash_Map(ref hm) => { + let mut new_hm: HashMap<String,MalVal> = HashMap::new(); + for (key, value) in hm.iter() { + match eval(value.clone(), env.clone()) { + Ok(mv) => { new_hm.insert(key.to_string(), mv); }, + Err(e) => return Err(e), + } + } + Ok(hash_map(new_hm)) }, _ => { Ok(ast) diff --git a/rust/src/step7_quote.rs b/rust/src/step7_quote.rs index c33d75b..3427eea 100644 --- a/rust/src/step7_quote.rs +++ b/rust/src/step7_quote.rs @@ -4,11 +4,11 @@ extern crate regex_macros; extern crate regex; +use std::collections::HashMap; use std::os; -use types::{MalVal,MalRet,MalFunc, - Nil,False,Sym,List,Vector,Func, - _nil,symbol,string,list,malfunc}; +use types::{MalVal,MalRet,MalFunc,Nil,False,Sym,List,Vector,Hash_Map,Func, + _nil,symbol,string,list,vector,hash_map,malfunc}; use env::{Env,env_new,env_bind,env_root,env_set,env_get}; mod readline; mod types; @@ -81,7 +81,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Sym(ref sym) => { env_get(env.clone(), sym.clone()) }, - List(ref a) => { + List(ref a) | Vector(ref a) => { let mut ast_vec : Vec<MalVal> = vec![]; for mv in a.iter() { let mv2 = mv.clone(); @@ -90,7 +90,18 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Err(e) => { return Err(e); }, } } - Ok(list(ast_vec)) + Ok(match *ast { List(_) => list(ast_vec), + _ => vector(ast_vec) }) + }, + Hash_Map(ref hm) => { + let mut new_hm: HashMap<String,MalVal> = HashMap::new(); + for (key, value) in hm.iter() { + match eval(value.clone(), env.clone()) { + Ok(mv) => { new_hm.insert(key.to_string(), mv); }, + Err(e) => return Err(e), + } + } + Ok(hash_map(new_hm)) }, _ => { Ok(ast) diff --git a/rust/src/step8_macros.rs b/rust/src/step8_macros.rs index c8cc9b3..1c84c58 100644 --- a/rust/src/step8_macros.rs +++ b/rust/src/step8_macros.rs @@ -4,11 +4,11 @@ extern crate regex_macros; extern crate regex; +use std::collections::HashMap; use std::os; -use types::{MalVal,MalRet,MalFunc, - Nil,False,Sym,List,Vector,Func, - _nil,symbol,string,list,malfunc,malfuncd}; +use types::{MalVal,MalRet,MalFunc,Nil,False,Sym,List,Vector,Hash_Map,Func, + _nil,symbol,string,list,vector,hash_map,malfunc,malfuncd}; use env::{Env,env_new,env_bind,env_root,env_find,env_set,env_get}; mod readline; mod types; @@ -141,7 +141,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Sym(ref sym) => { env_get(env.clone(), sym.clone()) }, - List(ref a) => { + List(ref a) | Vector(ref a) => { let mut ast_vec : Vec<MalVal> = vec![]; for mv in a.iter() { let mv2 = mv.clone(); @@ -150,7 +150,18 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Err(e) => { return Err(e); }, } } - Ok(list(ast_vec)) + Ok(match *ast { List(_) => list(ast_vec), + _ => vector(ast_vec) }) + }, + Hash_Map(ref hm) => { + let mut new_hm: HashMap<String,MalVal> = HashMap::new(); + for (key, value) in hm.iter() { + match eval(value.clone(), env.clone()) { + Ok(mv) => { new_hm.insert(key.to_string(), mv); }, + Err(e) => return Err(e), + } + } + Ok(hash_map(new_hm)) }, _ => { Ok(ast) diff --git a/rust/src/types.rs b/rust/src/types.rs index b8e1de0..e540ff1 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -1,12 +1,13 @@ #![allow(dead_code)] use std::rc::Rc; -use std::collections; +use std::collections::HashMap; use std::fmt; use super::printer::{escape_str,pr_list}; use super::env::{Env,env_new,env_bind}; #[deriving(Clone)] +#[allow(non_camel_case_types)] pub enum MalType { Nil, True, @@ -16,7 +17,7 @@ pub enum MalType { Sym(String), List(Vec<MalVal>), Vector(Vec<MalVal>), - HashMap(collections::HashMap<String, MalVal>), + Hash_Map(HashMap<String, MalVal>), Func(fn(Vec<MalVal>) -> MalRet), //Func(fn(&[MalVal]) -> MalRet), //Func(|Vec<MalVal>|:'a -> MalRet), @@ -59,19 +60,22 @@ impl MalType { Vector(ref v) => { res = pr_list(v, _r, "[", "]", " ") }, - HashMap(ref v) => { + Hash_Map(ref v) => { let mut first = true; res.push_str("{"); for (key, value) in v.iter() { if first { first = false; } else { res.push_str(" "); } - res.push_str(key.as_slice()); + if print_readably { + res.push_str(escape_str(key.as_slice()).as_slice()) + } else { + res.push_str(key.as_slice()) + } res.push_str(" "); res.push_str(value.pr_str(_r).as_slice()); } res.push_str("}") }, // TODO: better native function representation - //Func(ref v) => { Func(_) => { res.push_str(format!("#<function ...>").as_slice()) }, @@ -79,10 +83,8 @@ impl MalType { res.push_str(format!("(fn* {} {})", mf.params, mf.exp).as_slice()) }, /* - -// Atom(ref v) => v.fmt(f), + Atom(ref v) => v.fmt(f), */ - //_ => { res.push_str("#<unknown type>") }, }; res } @@ -115,8 +117,10 @@ impl PartialEq for MalType { (&Strn(ref a), &Strn(ref b)) => a == b, (&Sym(ref a), &Sym(ref b)) => a == b, (&List(ref a), &List(ref b)) | - (&Vector(ref a), &Vector(ref b)) => a == b, - (&HashMap(ref a), &HashMap(ref b)) => a == b, + (&Vector(ref a), &Vector(ref b)) | + (&List(ref a), &Vector(ref b)) | + (&Vector(ref a), &List(ref b)) => a == b, + (&Hash_Map(ref a), &Hash_Map(ref b)) => a == b, // TODO: fix this (&Func(_), &Func(_)) => false, (&MalFunc(_), &MalFunc(_)) => false, @@ -142,7 +146,29 @@ pub fn symbol(strn: &str) -> MalVal { Rc::new(Sym(strn.to_string())) } pub fn strn(strn: &str) -> MalVal { Rc::new(Strn(strn.to_string())) } pub fn string(strn: String) -> MalVal { Rc::new(Strn(strn)) } -pub fn list(lst: Vec<MalVal>) -> MalVal { Rc::new(List(lst)) } +pub fn list(seq: Vec<MalVal>) -> MalVal { Rc::new(List(seq)) } +pub fn vector(seq: Vec<MalVal>) -> MalVal { Rc::new(Vector(seq)) } +pub fn hash_map(hm: HashMap<String,MalVal>) -> MalVal { Rc::new(Hash_Map(hm)) } + +pub fn hash_mapv(seq: Vec<MalVal>) -> MalRet { + if seq.len() % 2 == 1 { + return Err("odd number of elements to hash-map".to_string()); + } + let mut new_hm: HashMap<String,MalVal> = HashMap::new(); + let mut it = seq.iter(); + loop { + let k = match it.next() { + Some(mv) => match *mv.clone() { + Strn(ref s) => s.to_string(), + _ => return Err("key is not a string in hash-map call".to_string()), + }, + None => break, + }; + let v = it.next().unwrap(); + new_hm.insert(k, v.clone()); + } + Ok(Rc::new(Hash_Map(new_hm))) +} pub fn func(f: fn(Vec<MalVal>) -> MalRet ) -> MalVal { Rc::new(Func(f)) |
