aboutsummaryrefslogtreecommitdiff
path: root/rust/src/core.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/core.rs')
-rw-r--r--rust/src/core.rs161
1 files changed, 121 insertions, 40 deletions
diff --git a/rust/src/core.rs b/rust/src/core.rs
index 98eb32a..61dc0ce 100644
--- a/rust/src/core.rs
+++ b/rust/src/core.rs
@@ -4,16 +4,18 @@ extern crate time;
use std::collections::HashMap;
use std::io::File;
-use types::{MalVal,MalRet,Int,Strn,List,Vector,
+use types::{MalVal,MalRet,err_val,err_str,err_string,
+ Int,Strn,List,Vector,Hash_Map,
_nil,_true,_false,_int,string,list,func};
+use types;
+use readline;
use reader;
use printer;
// General functions
-
fn equal_q(a:Vec<MalVal>) -> MalRet {
if a.len() != 2 {
- return Err("Wrong arity to equal? call".to_string());
+ return err_str("Wrong arity to equal? call");
}
match a[0] == a[1] {
true => Ok(_true()),
@@ -21,6 +23,14 @@ fn equal_q(a:Vec<MalVal>) -> MalRet {
}
}
+// Errors/Exceptions
+fn throw(a:Vec<MalVal>) -> MalRet {
+ if a.len() != 1 {
+ return err_str("Wrong arity to throw call");
+ }
+ err_val(a[0].clone())
+}
+
// String routines
fn pr_str(a:Vec<MalVal>) -> MalRet {
Ok(string(printer::pr_list(&a, true, "", "", " ")))
@@ -40,10 +50,20 @@ fn println(a:Vec<MalVal>) -> MalRet {
Ok(_nil())
}
+fn readline(a:Vec<MalVal>) -> MalRet {
+ match *a[0] {
+ Strn(ref a0) => match readline::mal_readline(a0.as_slice()) {
+ Some(line) => Ok(string(line)),
+ None => err_val(_nil()),
+ },
+ _ => err_str("read_string called with non-string"),
+ }
+}
+
fn read_string(a:Vec<MalVal>) -> MalRet {
match *a[0] {
Strn(ref a0) => reader::read_str(a0.to_string()),
- _ => Err("read_string called with non-string".to_string()),
+ _ => err_str("read_string called with non-string"),
}
}
@@ -52,10 +72,10 @@ fn slurp(a:Vec<MalVal>) -> MalRet {
Strn(ref a0) => {
match File::open(&Path::new(a0.as_slice())).read_to_string() {
Ok(s) => Ok(string(s)),
- Err(e) => Err(e.to_string()),
+ Err(e) => err_string(e.to_string()),
}
},
- _ => Err("slurp called with non-string".to_string()),
+ _ => err_str("slurp called with non-string"),
}
}
@@ -65,9 +85,9 @@ fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet {
match *a[0] {
Int(a0) => match *a[1] {
Int(a1) => Ok(_int(f(a0,a1))),
- _ => Err("second arg must be an int".to_string()),
+ _ => err_str("second arg must be an int"),
},
- _ => Err("first arg must be an int".to_string()),
+ _ => err_str("first arg must be an int"),
}
}
@@ -80,9 +100,9 @@ fn bool_op(f: |i:int,j:int|-> bool, a:Vec<MalVal>) -> MalRet {
false => Ok(_false()),
}
},
- _ => Err("second arg must be an int".to_string()),
+ _ => err_str("second arg must be an int"),
},
- _ => Err("first arg must be an int".to_string()),
+ _ => err_str("first arg must be an int"),
}
}
@@ -105,19 +125,29 @@ pub fn time_ms(a:Vec<MalVal>) -> MalRet {
}
-// Sequence functions
-pub fn _list(a:Vec<MalVal>) -> MalRet { Ok(list(a)) }
-
-pub fn list_q(a:Vec<MalVal>) -> MalRet {
- if a.len() != 1 {
- return Err("Wrong arity to list? call".to_string());
+// Hash Map functions
+pub fn get(a:Vec<MalVal>) -> MalRet {
+ if a.len() != 2 {
+ return err_str("Wrong arity to get call");
}
- match *a[0].clone() {
- List(_) => Ok(_true()),
- _ => Ok(_false()),
+ let a0 = a[0].clone();
+ let hm: &HashMap<String,MalVal> = match *a0 {
+ Hash_Map(ref hm) => hm,
+ _ => return err_str("get of non-hash map"),
+ };
+ match *a[1] {
+ Strn(ref key) => {
+ match hm.find_copy(key) {
+ Some(v) => Ok(v),
+ None => Ok(_nil()),
+ }
+ },
+ _ => return err_str("get with non-string key"),
}
}
+
+// Sequence functions
pub fn cons(a:Vec<MalVal>) -> MalRet {
match *a[1] {
List(ref v) | Vector(ref v) => {
@@ -125,7 +155,7 @@ pub fn cons(a:Vec<MalVal>) -> MalRet {
new_v.insert(0, a[0].clone());
Ok(list(new_v))
},
- _ => Err("Second arg to cons not a sequence".to_string()),
+ _ => err_str("Second arg to cons not a sequence"),
}
}
@@ -136,7 +166,7 @@ pub fn concat(a:Vec<MalVal>) -> MalRet {
List(ref l) | Vector(ref l) => {
new_v.push_all(l.as_slice());
},
- _ => return Err("concat called with non-sequence".to_string()),
+ _ => return err_str("concat called with non-sequence"),
}
}
Ok(list(new_v))
@@ -144,13 +174,13 @@ pub fn concat(a:Vec<MalVal>) -> MalRet {
pub fn nth(a:Vec<MalVal>) -> MalRet {
if a.len() != 2 {
- return Err("Wrong arity to nth call".to_string());
+ return err_str("Wrong arity to nth call");
}
let a0 = a[0].clone();
let a1 = a[1].clone();
let seq = match *a0 {
List(ref v) | Vector(ref v) => v,
- _ => return Err("nth called with non-sequence".to_string()),
+ _ => return err_str("nth called with non-sequence"),
};
let idx = match *a1 {
Int(i) => {
@@ -159,7 +189,7 @@ pub fn nth(a:Vec<MalVal>) -> MalRet {
None => return Ok(_nil()),
}
},
- _ => return Err("nth called with non-integer index".to_string()),
+ _ => return err_str("nth called with non-integer index"),
};
if idx >= seq.len() {
Ok(_nil())
@@ -170,12 +200,12 @@ pub fn nth(a:Vec<MalVal>) -> MalRet {
pub fn first(a:Vec<MalVal>) -> MalRet {
if a.len() != 1 {
- return Err("Wrong arity to first call".to_string());
+ return err_str("Wrong arity to first call");
}
let a0 = a[0].clone();
let seq = match *a0 {
List(ref v) | Vector(ref v) => v,
- _ => return Err("first called with non-sequence".to_string()),
+ _ => return err_str("first called with non-sequence"),
};
if seq.len() == 0 {
Ok(_nil())
@@ -186,12 +216,12 @@ pub fn first(a:Vec<MalVal>) -> MalRet {
pub fn rest(a:Vec<MalVal>) -> MalRet {
if a.len() != 1 {
- return Err("Wrong arity to rest call".to_string());
+ return err_str("Wrong arity to rest call");
}
let a0 = a[0].clone();
let seq = match *a0 {
List(ref v) | Vector(ref v) => v,
- _ => return Err("rest called with non-sequence".to_string()),
+ _ => return err_str("rest called with non-sequence"),
};
if seq.len() == 0 {
Ok(list(vec![]))
@@ -200,31 +230,67 @@ pub fn rest(a:Vec<MalVal>) -> MalRet {
}
}
-pub fn count(a:Vec<MalVal>) -> MalRet {
+pub fn empty_q(a:Vec<MalVal>) -> MalRet {
if a.len() != 1 {
- return Err("Wrong arity to count call".to_string());
+ return err_str("Wrong arity to empty? call");
}
match *a[0].clone() {
List(ref v) | Vector(ref v) => {
- Ok(_int(v.len().to_int().unwrap()))
+ match v.len() {
+ 0 => Ok(_true()),
+ _ => Ok(_false()),
+ }
},
- _ => Err("count called on non-sequence".to_string()),
+ _ => err_str("empty? called on non-sequence"),
}
}
-pub fn empty_q(a:Vec<MalVal>) -> MalRet {
+pub fn count(a:Vec<MalVal>) -> MalRet {
if a.len() != 1 {
- return Err("Wrong arity to empty? call".to_string());
+ return err_str("Wrong arity to count call");
}
match *a[0].clone() {
List(ref v) | Vector(ref v) => {
- match v.len() {
- 0 => Ok(_true()),
- _ => Ok(_false()),
+ Ok(_int(v.len().to_int().unwrap()))
+ },
+ _ => err_str("count called on non-sequence"),
+ }
+}
+
+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();
+ match *a[a.len()-1] {
+ List(ref v) | Vector(ref v) => {
+ args.push_all(v.as_slice());
+ f.apply(args)
+ },
+ _ => err_str("apply call with non-sequence"),
+ }
+}
+
+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 {
+ 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),
+ }
}
},
- _ => Err("empty? called on non-sequence".to_string()),
+ _ => return err_str("map call with non-sequence"),
}
+ Ok(list(results))
}
@@ -233,11 +299,17 @@ pub fn ns() -> HashMap<String,MalVal> {
let mut ns: HashMap<String,MalVal> = HashMap::new();;
ns.insert("=".to_string(), func(equal_q));
+ ns.insert("throw".to_string(), func(throw));
+ ns.insert("nil?".to_string(), func(types::nil_q));
+ ns.insert("true?".to_string(), func(types::true_q));
+ ns.insert("false?".to_string(), func(types::false_q));
+ ns.insert("symbol?".to_string(), func(types::symbol_q));
ns.insert("pr-str".to_string(), func(pr_str));
ns.insert("str".to_string(), func(str));
ns.insert("prn".to_string(), func(prn));
ns.insert("println".to_string(), func(println));
+ ns.insert("readline".to_string(), func(readline));
ns.insert("read-string".to_string(), func(read_string));
ns.insert("slurp".to_string(), func(slurp));
@@ -251,8 +323,15 @@ pub fn ns() -> HashMap<String,MalVal> {
ns.insert("/".to_string(), func(div));
ns.insert("time-ms".to_string(), func(time_ms));
- ns.insert("list".to_string(), func(_list));
- ns.insert("list?".to_string(), func(list_q));
+ ns.insert("list".to_string(), func(types::listv));
+ ns.insert("list?".to_string(), func(types::list_q));
+ ns.insert("vector".to_string(), func(types::vectorv));
+ ns.insert("vector?".to_string(), func(types::vector_q));
+ ns.insert("hash-map".to_string(), func(types::hash_mapv));
+ ns.insert("map?".to_string(), func(types::hash_map_q));
+ ns.insert("get".to_string(), func(get));
+
+ ns.insert("sequential?".to_string(), func(types::sequential_q));
ns.insert("cons".to_string(), func(cons));
ns.insert("concat".to_string(), func(concat));
ns.insert("empty?".to_string(), func(empty_q));
@@ -260,6 +339,8 @@ pub fn ns() -> HashMap<String,MalVal> {
ns.insert("first".to_string(), func(first));
ns.insert("rest".to_string(), func(rest));
ns.insert("count".to_string(), func(count));
+ ns.insert("apply".to_string(), func(apply));
+ ns.insert("map".to_string(), func(map));
return ns;
}