diff options
Diffstat (limited to 'rust/src/core.rs')
| -rw-r--r-- | rust/src/core.rs | 285 |
1 files changed, 121 insertions, 164 deletions
diff --git a/rust/src/core.rs b/rust/src/core.rs index 2bc3c39..f7257f3 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -1,31 +1,30 @@ #![allow(dead_code)] -extern crate time; use std::collections::HashMap; -use std::io::File; +use std::fs::File; +use std::io::prelude::*; +use std::num::ToPrimitive; +use time; use types::{MalVal,MalRet,err_val,err_str,err_string, - Nil,Int,Strn,List,Vector,Hash_Map,Func,MalFunc,Atom, _nil,_true,_false,_int,string, list,vector,listm,vectorm,hash_mapm,func,funcm,malfuncd}; +use types::MalType::{Nil, Int, Strn, List, Vector, Hash_Map, Func, MalFunc, Atom}; use types; use readline; use reader; use printer; // General functions -fn equal_q(a:Vec<MalVal>) -> MalRet { +fn equal_q(a: Vec<MalVal>) -> MalRet { if a.len() != 2 { return err_str("Wrong arity to equal? call"); } - match a[0] == a[1] { - true => Ok(_true()), - false => Ok(_false()), - } + if a[0] == a[1] {Ok(_true())} else {Ok(_false())} } // Errors/Exceptions -fn throw(a:Vec<MalVal>) -> MalRet { +fn throw(a: Vec<MalVal>) -> MalRet { if a.len() != 1 { return err_str("Wrong arity to throw call"); } @@ -33,27 +32,27 @@ fn throw(a:Vec<MalVal>) -> MalRet { } // String routines -fn pr_str(a:Vec<MalVal>) -> MalRet { +fn pr_str(a: Vec<MalVal>) -> MalRet { Ok(string(printer::pr_list(&a, true, "", "", " "))) } -fn str(a:Vec<MalVal>) -> MalRet { +fn str(a: Vec<MalVal>) -> MalRet { Ok(string(printer::pr_list(&a, false, "", "", ""))) } -fn prn(a:Vec<MalVal>) -> MalRet { - println!("{}", printer::pr_list(&a, true, "", "", " ")) +fn prn(a: Vec<MalVal>) -> MalRet { + println!("{}", printer::pr_list(&a, true, "", "", " ")); Ok(_nil()) } -fn println(a:Vec<MalVal>) -> MalRet { - println!("{}", printer::pr_list(&a, false, "", "", " ")) +fn println(a: Vec<MalVal>) -> MalRet { + println!("{}", printer::pr_list(&a, false, "", "", " ")); Ok(_nil()) } -fn readline(a:Vec<MalVal>) -> MalRet { +fn readline(a: Vec<MalVal>) -> MalRet { match *a[0] { - Strn(ref a0) => match readline::mal_readline(a0.as_slice()) { + Strn(ref a0) => match readline::mal_readline(&a0) { Some(line) => Ok(string(line)), None => err_val(_nil()), }, @@ -61,18 +60,19 @@ fn readline(a:Vec<MalVal>) -> MalRet { } } -fn read_string(a:Vec<MalVal>) -> MalRet { +fn read_string(a: Vec<MalVal>) -> MalRet { match *a[0] { Strn(ref a0) => reader::read_str(a0.to_string()), _ => err_str("read_string called with non-string"), } } -fn slurp(a:Vec<MalVal>) -> MalRet { +fn slurp(a: Vec<MalVal>) -> MalRet { match *a[0] { Strn(ref a0) => { - match File::open(&Path::new(a0.as_slice())).read_to_string() { - Ok(s) => Ok(string(s)), + let mut s = String::new(); + match File::open(a0).and_then(|mut f| f.read_to_string(&mut s)) { + Ok(_) => Ok(string(s)), Err(e) => err_string(e.to_string()), } }, @@ -82,7 +82,9 @@ fn slurp(a:Vec<MalVal>) -> MalRet { // Numeric functions -fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet { +fn int_op<F>(f: F, a: Vec<MalVal>) -> MalRet + where F: FnOnce(isize, isize) -> isize +{ match *a[0] { Int(a0) => match *a[1] { Int(a1) => Ok(_int(f(a0,a1))), @@ -92,13 +94,15 @@ fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet { } } -fn bool_op(f: |i:int,j:int|-> bool, a:Vec<MalVal>) -> MalRet { +fn bool_op<F>(f: F, a: Vec<MalVal>) -> MalRet + where F: FnOnce(isize, isize) -> bool +{ match *a[0] { Int(a0) => match *a[1] { Int(a1) => { match f(a0,a1) { true => Ok(_true()), - false => Ok(_false()), + false => Ok(_false()), } }, _ => err_str("second arg must be an int"), @@ -107,83 +111,73 @@ fn bool_op(f: |i:int,j:int|-> bool, a:Vec<MalVal>) -> MalRet { } } -pub fn add(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i+j }, a) } -pub fn sub(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i-j }, a) } -pub fn mul(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i*j }, a) } -pub fn div(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i/j }, a) } +pub fn add(a: Vec<MalVal>) -> MalRet { int_op(|i,j| { i+j }, a) } +pub fn sub(a: Vec<MalVal>) -> MalRet { int_op(|i,j| { i-j }, a) } +pub fn mul(a: Vec<MalVal>) -> MalRet { int_op(|i,j| { i*j }, a) } +pub fn div(a: Vec<MalVal>) -> MalRet { int_op(|i,j| { i/j }, a) } -pub fn lt (a:Vec<MalVal>) -> MalRet { bool_op(|i,j| { i<j }, a) } -pub fn lte(a:Vec<MalVal>) -> MalRet { bool_op(|i,j| { i<=j }, a) } -pub fn gt (a:Vec<MalVal>) -> MalRet { bool_op(|i,j| { i>j }, a) } -pub fn gte(a:Vec<MalVal>) -> MalRet { bool_op(|i,j| { i>=j }, a) } +pub fn lt (a: Vec<MalVal>) -> MalRet { bool_op(|i,j| { i<j }, a) } +pub fn lte(a: Vec<MalVal>) -> MalRet { bool_op(|i,j| { i<=j }, a) } +pub fn gt (a: Vec<MalVal>) -> MalRet { bool_op(|i,j| { i>j }, a) } +pub fn gte(a: Vec<MalVal>) -> MalRet { bool_op(|i,j| { i>=j }, a) } -#[allow(unused_variable)] -pub fn time_ms(a:Vec<MalVal>) -> MalRet { +pub fn time_ms(_a: Vec<MalVal>) -> MalRet { //let x = time::now(); let now = time::get_time(); - let now_ms = (now.sec * 1000).to_int().unwrap() + (now.nsec.to_int().unwrap() / 1000000); + let now_ms = (now.sec * 1000).to_isize().unwrap() + + (now.nsec.to_isize().unwrap() / 1000000); Ok(_int(now_ms)) } // Hash Map functions -pub fn assoc(a:Vec<MalVal>) -> MalRet { +pub fn assoc(a: Vec<MalVal>) -> MalRet { if a.len() < 3 { return err_str("Wrong arity to assoc call"); } match *a[0] { - Hash_Map(ref hm,_) => { - types::_assoc(hm, a.slice(1,a.len()).to_vec()) - }, - Nil => { - types::hash_mapv(a.slice(1,a.len()).to_vec()) - } - _ => return err_str("assoc onto non-hash map"), + Hash_Map(ref hm,_) => types::_assoc(hm, a[1..].to_vec()), + Nil => types::hash_mapv(a[1..].to_vec()), + _ => err_str("assoc onto non-hash map"), } } -pub fn dissoc(a:Vec<MalVal>) -> MalRet { +pub fn dissoc(a: Vec<MalVal>) -> MalRet { if a.len() < 2 { return err_str("Wrong arity to dissoc call"); } match *a[0] { - Hash_Map(ref hm,_) => { - types::_dissoc(hm, a.slice(1,a.len()).to_vec()) - }, - Nil => { - Ok(_nil()) - } - _ => return err_str("dissoc onto non-hash map"), + Hash_Map(ref hm,_) => types::_dissoc(hm, a[1..].to_vec()), + Nil => Ok(_nil()), + _ => err_str("dissoc onto non-hash map"), } } -pub fn get(a:Vec<MalVal>) -> MalRet { +pub fn get(a: Vec<MalVal>) -> MalRet { if a.len() != 2 { return err_str("Wrong arity to get call"); } - let a0 = a[0].clone(); - let hm: &HashMap<String,MalVal> = match *a0 { + let hm = match *a[0] { Hash_Map(ref hm,_) => hm, Nil => return Ok(_nil()), _ => return err_str("get on non-hash map"), }; match *a[1] { Strn(ref key) => { - match hm.find_copy(key) { - Some(v) => Ok(v), + match hm.get(key) { + Some(v) => Ok(v.clone()), None => Ok(_nil()), } }, - _ => return err_str("get with non-string key"), + _ => err_str("get with non-string key"), } } -pub fn contains_q(a:Vec<MalVal>) -> MalRet { +pub fn contains_q(a: Vec<MalVal>) -> MalRet { if a.len() != 2 { return err_str("Wrong arity to contains? call"); } - let a0 = a[0].clone(); - let hm: &HashMap<String,MalVal> = match *a0 { + let hm = match *a[0] { Hash_Map(ref hm,_) => hm, Nil => return Ok(_false()), _ => return err_str("contains? on non-hash map"), @@ -194,50 +188,37 @@ pub fn contains_q(a:Vec<MalVal>) -> MalRet { true => Ok(_true()), false => Ok(_false()), } - }, - _ => return err_str("contains? with non-string key"), + } + _ => err_str("contains? with non-string key"), } } -pub fn keys(a:Vec<MalVal>) -> MalRet { +pub fn keys(a: Vec<MalVal>) -> MalRet { if a.len() != 1 { return err_str("Wrong arity to keys call"); } - let a0 = a[0].clone(); - let hm: &HashMap<String,MalVal> = match *a0 { + let hm = match *a[0] { Hash_Map(ref hm,_) => hm, Nil => return Ok(_nil()), _ => return err_str("contains? on non-hash map"), }; - //if hm.len() == 0 { return Ok(_nil()); } - let mut keys = vec![]; - for k in hm.keys() { - keys.push(string(k.to_string())); - } - Ok(list(keys)) + Ok(list(hm.keys().map(|s| string(s.to_string())).collect())) } -pub fn vals(a:Vec<MalVal>) -> MalRet { +pub fn vals(a: Vec<MalVal>) -> MalRet { if a.len() != 1 { return err_str("Wrong arity to values call"); } - let a0 = a[0].clone(); - let hm: &HashMap<String,MalVal> = match *a0 { + let hm = match *a[0] { Hash_Map(ref hm,_) => hm, Nil => return Ok(_nil()), _ => return err_str("contains? on non-hash map"), }; - //if hm.len() == 0 { return Ok(_nil()); } - let mut vals = vec![]; - for k in hm.values() { - vals.push(k.clone()); - } - Ok(list(vals)) + Ok(list(hm.values().map(|s| s.clone()).collect())) } - // Sequence functions -pub fn cons(a:Vec<MalVal>) -> MalRet { +pub fn cons(a: Vec<MalVal>) -> MalRet { match *a[1] { List(ref v,_) | Vector(ref v,_) => { let mut new_v = v.clone(); @@ -248,32 +229,28 @@ pub fn cons(a:Vec<MalVal>) -> MalRet { } } -pub fn concat(a:Vec<MalVal>) -> MalRet { - let mut new_v:Vec<MalVal> = vec![]; +pub fn concat(a: Vec<MalVal>) -> MalRet { + let mut new_v: Vec<MalVal> = vec![]; for lst in a.iter() { match **lst { - List(ref l,_) | Vector(ref l,_) => { - new_v.push_all(l.as_slice()); - }, + List(ref l,_) | Vector(ref l,_) => new_v.push_all(l), _ => return err_str("concat called with non-sequence"), } } Ok(list(new_v)) } -pub fn nth(a:Vec<MalVal>) -> MalRet { +pub fn nth(a: Vec<MalVal>) -> MalRet { if a.len() != 2 { return err_str("Wrong arity to nth call"); } - let a0 = a[0].clone(); - let a1 = a[1].clone(); - let seq = match *a0 { + let seq = match *a[0] { List(ref v,_) | Vector(ref v,_) => v, _ => return err_str("nth called with non-sequence"), }; - let idx = match *a1 { + let idx = match *a[1] { Int(i) => { - match i.to_uint() { + match i.to_usize() { Some(ui) => ui, None => return Ok(_nil()), } @@ -281,18 +258,17 @@ pub fn nth(a:Vec<MalVal>) -> MalRet { _ => return err_str("nth called with non-integer index"), }; if idx >= seq.len() { - return err_str("nth: index out of range") + err_str("nth: index out of range") } else { Ok(seq[idx].clone()) } } -pub fn first(a:Vec<MalVal>) -> MalRet { +pub fn first(a: Vec<MalVal>) -> MalRet { if a.len() != 1 { return err_str("Wrong arity to first call"); } - let a0 = a[0].clone(); - let seq = match *a0 { + let seq = match *a[0] { List(ref v,_) | Vector(ref v,_) => v, _ => return err_str("first called with non-sequence"), }; @@ -303,27 +279,26 @@ pub fn first(a:Vec<MalVal>) -> MalRet { } } -pub fn rest(a:Vec<MalVal>) -> MalRet { +pub fn rest(a: Vec<MalVal>) -> MalRet { if a.len() != 1 { return err_str("Wrong arity to rest call"); } - let a0 = a[0].clone(); - let seq = match *a0 { + let seq = match *a[0] { List(ref v,_) | Vector(ref v,_) => v, _ => return err_str("rest called with non-sequence"), }; if seq.len() == 0 { Ok(list(vec![])) } else { - Ok(list(seq.slice(1,seq.len()).to_vec())) + Ok(list(seq[1..].to_vec())) } } -pub fn empty_q(a:Vec<MalVal>) -> MalRet { +pub fn empty_q(a: Vec<MalVal>) -> MalRet { if a.len() != 1 { return err_str("Wrong arity to empty? call"); } - match *a[0].clone() { + match *a[0] { List(ref v,_) | Vector(ref v,_) => { match v.len() { 0 => Ok(_true()), @@ -334,48 +309,42 @@ pub fn empty_q(a:Vec<MalVal>) -> MalRet { } } -pub fn count(a:Vec<MalVal>) -> MalRet { +pub fn count(a: Vec<MalVal>) -> MalRet { if a.len() != 1 { return err_str("Wrong arity to count call"); } - match *a[0].clone() { - List(ref v,_) | Vector(ref v,_) => { - Ok(_int(v.len().to_int().unwrap())) - }, + match *a[0] { + List(ref v,_) | Vector(ref v,_) => Ok(_int(v.len().to_isize().unwrap())), Nil => Ok(_int(0)), _ => err_str("count called on non-sequence"), } } -pub fn apply(a:Vec<MalVal>) -> MalRet { +pub fn apply(a: Vec<MalVal>) -> MalRet { if a.len() < 2 { return err_str("apply call needs 2 or more arguments"); } let ref f = a[0]; - let mut args = a.slice(1,a.len()-1).to_vec(); + let mut args = a[1..a.len()-1].to_vec(); match *a[a.len()-1] { - List(ref v,_) | Vector(ref v,_) => { - args.push_all(v.as_slice()); + List(ref v, _) | Vector(ref v, _) => { + args.push_all(v); f.apply(args) }, _ => err_str("apply call with non-sequence"), } } -pub fn map(a:Vec<MalVal>) -> MalRet { +pub fn map(a: Vec<MalVal>) -> MalRet { if a.len() != 2 { return err_str("Wrong arity to map call"); } let mut results:Vec<MalVal> = vec![]; - let ref f = a[0].clone(); - let seq = a[1].clone(); - match *seq { + match *a[1] { List(ref v,_) | Vector(ref v,_) => { for mv in v.iter() { - match f.apply(vec![mv.clone()]) { - Ok(res) => results.push(res), - Err(e) => return Err(e), - } + let res = try!(a[0].apply(vec![mv.clone()])); + results.push(res); } }, _ => return err_str("map call with non-sequence"), @@ -383,53 +352,52 @@ pub fn map(a:Vec<MalVal>) -> MalRet { Ok(list(results)) } -pub fn conj(a:Vec<MalVal>) -> MalRet { +pub fn conj(a: Vec<MalVal>) -> MalRet { if a.len() < 2 { return err_str("Wrong arity to conj call"); } - let mut new_v:Vec<MalVal> = vec![]; - match *a[0].clone() { + let mut new_v: Vec<MalVal> = vec![]; + match *a[0] { List(ref l,_) => { - new_v.push_all(l.as_slice()); + new_v.push_all(l); for mv in a.iter().skip(1) { - new_v.insert(0,mv.clone()); + new_v.insert(0, mv.clone()); } Ok(list(new_v)) - }, + } Vector(ref l,_) => { - new_v.push_all(l.as_slice()); + new_v.push_all(l); for mv in a.iter().skip(1) { new_v.push(mv.clone()); } Ok(vector(new_v)) - }, - _ => return err_str("conj called with non-sequence"), + } + _ => err_str("conj called with non-sequence"), } } // Metadata functions -fn with_meta(a:Vec<MalVal>) -> MalRet { +fn with_meta(a: Vec<MalVal>) -> MalRet { if a.len() != 2 { return err_str("Wrong arity to with-meta call"); } - let mv = a[0].clone(); let meta = a[1].clone(); - match *mv { - List(ref v,_) => Ok(listm(v.clone(),meta)), - Vector(ref v,_) => Ok(vectorm(v.clone(),meta)), - Hash_Map(ref hm,_) => Ok(hash_mapm(hm.clone(),meta)), - MalFunc(ref mfd,_) => Ok(malfuncd(mfd.clone(),meta)), - Func(f,_) => Ok(funcm(f,meta)), + match *a[0] { + List(ref v,_) => Ok(listm(v.clone(), meta)), + Vector(ref v,_) => Ok(vectorm(v.clone(), meta)), + Hash_Map(ref hm,_) => Ok(hash_mapm(hm.clone(), meta)), + MalFunc(ref mfd,_) => Ok(malfuncd(mfd.clone(), meta)), + Func(f,_) => Ok(funcm(f, meta)), _ => err_str("type does not support metadata"), } } -fn meta(a:Vec<MalVal>) -> MalRet { +fn meta(a: Vec<MalVal>) -> MalRet { if a.len() != 1 { return err_str("Wrong arity to meta call"); } - match *a[0].clone() { + match *a[0] { List(_,ref meta) | Vector(_,ref meta) | Hash_Map(_,ref meta) | @@ -440,53 +408,42 @@ fn meta(a:Vec<MalVal>) -> MalRet { } // Atom functions -fn deref(a:Vec<MalVal>) -> MalRet { +fn deref(a: Vec<MalVal>) -> MalRet { if a.len() != 1 { return err_str("Wrong arity to deref call"); } - match *a[0].clone() { - Atom(ref val) => { - let val_cell = val.borrow(); - Ok(val_cell.clone()) - }, + match *a[0] { + Atom(ref val) => Ok(val.borrow().clone()), _ => err_str("deref called on non-atom"), } } -fn reset_bang(a:Vec<MalVal>) -> MalRet { +fn reset_bang(a: Vec<MalVal>) -> MalRet { if a.len() != 2 { return err_str("Wrong arity to map call"); } - let a1 = a[1].clone(); - match *a[0].clone() { + match *a[0] { Atom(ref val) => { let mut val_cell = val.borrow_mut(); - let atm_mv = val_cell.deref_mut(); - *atm_mv = a1.clone(); - Ok(a1) + *val_cell = a[1].clone(); + Ok(a[1].clone()) }, _ => err_str("reset! called on non-atom"), } } -fn swap_bang(a:Vec<MalVal>) -> MalRet { +fn swap_bang(a: Vec<MalVal>) -> MalRet { if a.len() < 2 { return err_str("Wrong arity to swap_q call"); } let f = a[1].clone(); - match *a[0].clone() { + match *a[0] { Atom(ref val) => { let mut val_cell = val.borrow_mut(); - let atm_mv = val_cell.deref_mut(); - let mut args = a.slice(2,a.len()).to_vec(); - args.insert(0, atm_mv.clone()); - match f.apply(args) { - Ok(new_mv) => { - *atm_mv = new_mv.clone(); - Ok(new_mv) - } - Err(e) => Err(e), - } + let mut args = a[2..].to_vec(); + args.insert(0, val_cell.clone()); + *val_cell = try!(f.apply(args)); + Ok(val_cell.clone()) }, _ => err_str("swap! called on non-atom"), } @@ -494,7 +451,7 @@ fn swap_bang(a:Vec<MalVal>) -> MalRet { pub fn ns() -> HashMap<String,MalVal> { - let mut ns: HashMap<String,MalVal> = HashMap::new();; + let mut ns = HashMap::new();; ns.insert("=".to_string(), func(equal_q)); ns.insert("throw".to_string(), func(throw)); |
