diff options
| author | Joel Martin <github@martintribe.org> | 2014-10-25 16:51:52 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-01-06 21:58:58 -0600 |
| commit | 4ee7c0f2970accc0f49eeac7fb2a0359b159c8ae (patch) | |
| tree | 91aee7451aefe68050ec797f6054c205df2358cf /rust/src | |
| parent | 85bec8a08b76b5b4797ddd9976a138b22974e1c4 (diff) | |
| download | mal-4ee7c0f2970accc0f49eeac7fb2a0359b159c8ae.tar.gz mal-4ee7c0f2970accc0f49eeac7fb2a0359b159c8ae.zip | |
rust: add step7_quote. Refactor with type constructors.
Diffstat (limited to 'rust/src')
| -rw-r--r-- | rust/src/core.rs | 119 | ||||
| -rw-r--r-- | rust/src/env.rs | 15 | ||||
| -rw-r--r-- | rust/src/reader.rs | 48 | ||||
| -rw-r--r-- | rust/src/step2_eval.rs | 18 | ||||
| -rw-r--r-- | rust/src/step3_env.rs | 22 | ||||
| -rw-r--r-- | rust/src/step4_if_fn_do.rs | 23 | ||||
| -rw-r--r-- | rust/src/step5_tco.rs | 26 | ||||
| -rw-r--r-- | rust/src/step6_file.rs | 29 | ||||
| -rw-r--r-- | rust/src/step7_quote.rs | 341 | ||||
| -rw-r--r-- | rust/src/types.rs | 21 |
10 files changed, 535 insertions, 127 deletions
diff --git a/rust/src/core.rs b/rust/src/core.rs index 1779b80..94042d6 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -1,10 +1,11 @@ #![allow(dead_code)] -use std::rc::Rc; +extern crate time; use std::collections::HashMap; use std::io::File; -use types::{MalVal,MalRet,Func,True,False,Int,Strn,List,Nil}; +use types::{MalVal,MalRet,Int,Strn,List, + _nil,_true,_false,_int,string,list,func}; use reader; use printer; @@ -15,28 +16,28 @@ fn equal_q(a:Vec<MalVal>) -> MalRet { return Err("Wrong arity to equal? call".to_string()); } match a[0] == a[1] { - true => Ok(Rc::new(True)), - false => Ok(Rc::new(False)), + true => Ok(_true()), + false => Ok(_false()), } } // String routines fn pr_str(a:Vec<MalVal>) -> MalRet { - Ok(Rc::new(Strn(printer::pr_list(&a, true, "", "", " ")))) + Ok(string(printer::pr_list(&a, true, "", "", " "))) } fn str(a:Vec<MalVal>) -> MalRet { - Ok(Rc::new(Strn(printer::pr_list(&a, false, "", "", "")))) + Ok(string(printer::pr_list(&a, false, "", "", ""))) } fn prn(a:Vec<MalVal>) -> MalRet { println!("{}", printer::pr_list(&a, true, "", "", " ")) - Ok(Rc::new(Nil)) + Ok(_nil()) } fn println(a:Vec<MalVal>) -> MalRet { println!("{}", printer::pr_list(&a, false, "", "", " ")) - Ok(Rc::new(Nil)) + Ok(_nil()) } fn read_string(a:Vec<MalVal>) -> MalRet { @@ -50,7 +51,7 @@ 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(Rc::new(Strn(s))), + Ok(s) => Ok(string(s)), Err(e) => Err(e.to_string()), } }, @@ -63,7 +64,7 @@ fn slurp(a:Vec<MalVal>) -> MalRet { fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet { match *a[0] { Int(a0) => match *a[1] { - Int(a1) => Ok(Rc::new(Int(f(a0,a1)))), + Int(a1) => Ok(_int(f(a0,a1))), _ => Err("second arg must be an int".to_string()), }, _ => Err("first arg must be an int".to_string()), @@ -75,10 +76,9 @@ fn bool_op(f: |i:int,j:int|-> bool, a:Vec<MalVal>) -> MalRet { Int(a0) => match *a[1] { Int(a1) => { match f(a0,a1) { - true => Ok(Rc::new(True)), - false => Ok(Rc::new(False)), + true => Ok(_true()), + false => Ok(_false()), } - //Ok(Rc::new(Int(f(a0,a1)))), }, _ => Err("second arg must be an int".to_string()), }, @@ -96,20 +96,50 @@ 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 { + //let x = time::now(); + let now = time::get_time(); + let now_ms = (now.sec * 1000).to_int().unwrap() + (now.nsec.to_int().unwrap() / 1000000); + Ok(_int(now_ms)) +} + // Sequence functions -pub fn list(a:Vec<MalVal>) -> MalRet { - Ok(Rc::new(List(a))) -} +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()); } match *a[0].clone() { - List(_) => Ok(Rc::new(True)), - _ => Ok(Rc::new(False)), + List(_) => Ok(_true()), + _ => Ok(_false()), + } +} + +pub fn cons(a:Vec<MalVal>) -> MalRet { + match *a[1] { + List(ref v) => { + let mut new_v = v.clone(); + new_v.insert(0, a[0].clone()); + Ok(list(new_v)) + }, + _ => Err("Second arg to cons not a sequence".to_string()), + } +} + +pub fn concat(a:Vec<MalVal>) -> MalRet { + let mut new_v:Vec<MalVal> = vec![]; + for lst in a.iter() { + match **lst { + List(ref l) => { + new_v.push_all(l.as_slice()); + }, + _ => return Err("concat called with non-sequence".to_string()), + } } + Ok(list(new_v)) } pub fn count(a:Vec<MalVal>) -> MalRet { @@ -118,7 +148,7 @@ pub fn count(a:Vec<MalVal>) -> MalRet { } match *a[0].clone() { List(ref lst) => { - Ok(Rc::new(Int(lst.len().to_int().unwrap()))) + Ok(_int(lst.len().to_int().unwrap())) }, _ => Err("count called on non-sequence".to_string()), } @@ -131,8 +161,8 @@ pub fn empty_q(a:Vec<MalVal>) -> MalRet { match *a[0].clone() { List(ref lst) => { match lst.len() { - 0 => Ok(Rc::new(True)), - _ => Ok(Rc::new(False)), + 0 => Ok(_true()), + _ => Ok(_false()), } }, _ => Err("empty? called on non-sequence".to_string()), @@ -144,28 +174,31 @@ pub fn empty_q(a:Vec<MalVal>) -> MalRet { pub fn ns() -> HashMap<String,MalVal> { let mut ns: HashMap<String,MalVal> = HashMap::new();; - ns.insert("=".to_string(), Rc::new(Func(equal_q))); - - ns.insert("pr-str".to_string(), Rc::new(Func(pr_str))); - ns.insert("str".to_string(), Rc::new(Func(str))); - ns.insert("prn".to_string(), Rc::new(Func(prn))); - ns.insert("println".to_string(), Rc::new(Func(println))); - ns.insert("read-string".to_string(), Rc::new(Func(read_string))); - ns.insert("slurp".to_string(), Rc::new(Func(slurp))); - - ns.insert("<".to_string(), Rc::new(Func(lt))); - ns.insert("<=".to_string(), Rc::new(Func(lte))); - ns.insert(">".to_string(), Rc::new(Func(gt))); - ns.insert(">=".to_string(), Rc::new(Func(gte))); - ns.insert("+".to_string(), Rc::new(Func(add))); - ns.insert("-".to_string(), Rc::new(Func(sub))); - ns.insert("*".to_string(), Rc::new(Func(mul))); - ns.insert("/".to_string(), Rc::new(Func(div))); - - ns.insert("list".to_string(), Rc::new(Func(list))); - ns.insert("list?".to_string(), Rc::new(Func(list_q))); - ns.insert("empty?".to_string(), Rc::new(Func(empty_q))); - ns.insert("count".to_string(), Rc::new(Func(count))); + ns.insert("=".to_string(), func(equal_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("read-string".to_string(), func(read_string)); + ns.insert("slurp".to_string(), func(slurp)); + + ns.insert("<".to_string(), func(lt)); + ns.insert("<=".to_string(), func(lte)); + ns.insert(">".to_string(), func(gt)); + ns.insert(">=".to_string(), func(gte)); + ns.insert("+".to_string(), func(add)); + ns.insert("-".to_string(), func(sub)); + ns.insert("*".to_string(), func(mul)); + 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("cons".to_string(), func(cons)); + ns.insert("concat".to_string(), func(concat)); + ns.insert("empty?".to_string(), func(empty_q)); + ns.insert("count".to_string(), func(count)); return ns; } diff --git a/rust/src/env.rs b/rust/src/env.rs index 3c98015..730010a 100644 --- a/rust/src/env.rs +++ b/rust/src/env.rs @@ -1,11 +1,12 @@ +#![allow(dead_code)] + use std::rc::Rc; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; -use types::{MalVal,MalRet,Nil,Sym,List}; +use types::{MalVal,MalRet,Sym,List,_nil,list}; -#[allow(dead_code)] struct EnvType { data: HashMap<String,MalVal>, outer: Option<Env>, @@ -13,12 +14,10 @@ struct EnvType { pub type Env = Rc<RefCell<EnvType>>; -#[allow(dead_code)] pub fn env_new(outer: Option<Env>) -> Env { Rc::new(RefCell::new(EnvType{data: HashMap::new(), outer: outer})) } -#[allow(dead_code)] pub fn env_bind(env: &Env, mbinds: MalVal, mexprs: MalVal) -> Result<Env,String> { @@ -46,7 +45,7 @@ pub fn env_bind(env: &Env, match **sym { Sym(ref s) => { let rest = exprs.slice(i-1,exprs.len()).to_vec(); - env_set(env, s.clone(), Rc::new(List(rest))); + env_set(env, s.clone(), list(rest)); } _ => return Err("& bind to non-symbol".to_string()), } @@ -60,7 +59,6 @@ pub fn env_bind(env: &Env, } } -#[allow(dead_code)] pub fn env_find(env: Env, key: String) -> Option<Env> { if env.borrow().data.contains_key(&key) { Some(env) @@ -72,7 +70,6 @@ pub fn env_find(env: Env, key: String) -> Option<Env> { } } -#[allow(dead_code)] pub fn env_root(env: &Env) -> Env { match env.borrow().outer { Some(ref ei) => env_root(ei), @@ -80,18 +77,16 @@ pub fn env_root(env: &Env) -> Env { } } -#[allow(dead_code)] pub fn env_set(env: &Env, key: String, val: MalVal) { env.borrow_mut().data.insert(key, val.clone()); } -#[allow(dead_code)] pub fn env_get(env: Env, key: String) -> MalRet { match env_find(env, key.clone()) { Some(e) => { match e.borrow().data.find_copy(&key) { Some(v) => Ok(v), - None => Ok(Rc::new(Nil)), + None => Ok(_nil()), } }, None => Err("'".to_string() + key + "' not found".to_string()), diff --git a/rust/src/reader.rs b/rust/src/reader.rs index 035cfde..f0ef2e3 100644 --- a/rust/src/reader.rs +++ b/rust/src/reader.rs @@ -5,8 +5,8 @@ extern crate pcre; -use std::rc::Rc; -use types::{MalVal,MalRet,Nil,True,False,Int,Strn,Sym,List}; +use types::{MalVal,MalRet, + _nil,_true,_false,_int,symbol,string,list}; use self::pcre::Pcre; use super::printer::unescape_str; @@ -62,18 +62,18 @@ fn read_atom(rdr : &mut Reader) -> MalRet { let token = stoken.as_slice(); if regex!(r"^-?[0-9]+$").is_match(token) { let num : Option<int> = from_str(token); - Ok(Rc::new(Int(num.unwrap()))) + Ok(_int(num.unwrap())) } else if regex!(r#"^".*"$"#).is_match(token) { let new_str = token.slice(1,token.len()-1); - Ok(Rc::new(Strn(unescape_str(new_str)))) + Ok(string(unescape_str(new_str))) } else if token == "nil" { - Ok(Rc::new(Nil)) + Ok(_nil()) } else if token == "true" { - Ok(Rc::new(True)) + Ok(_true()) } else if token == "false" { - Ok(Rc::new(False)) + Ok(_false()) } else { - Ok(Rc::new(Sym(String::from_str(token)))) + Ok(symbol(token)) } } @@ -99,8 +99,7 @@ fn read_list(rdr : &mut Reader) -> MalRet { } rdr.next(); - //ast_vec.push(Rc::new(Nil)); - Ok(Rc::new(List(ast_vec))) + Ok(list(ast_vec)) } fn read_form(rdr : &mut Reader) -> MalRet { @@ -109,6 +108,35 @@ fn read_form(rdr : &mut Reader) -> MalRet { 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) diff --git a/rust/src/step2_eval.rs b/rust/src/step2_eval.rs index 11c1884..3b27762 100644 --- a/rust/src/step2_eval.rs +++ b/rust/src/step2_eval.rs @@ -4,10 +4,10 @@ extern crate regex_macros; extern crate regex; -use std::rc::Rc; use std::collections::HashMap; -use types::{MalVal,MalRet,Nil,Int,Sym,List,Func}; +use types::{MalVal,MalRet,Int,Sym,List,Func, + _nil,_int,list,func}; mod readline; mod types; mod env; @@ -25,7 +25,7 @@ fn eval_ast(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet { Sym(ref sym) => { match env.find_copy(sym) { Some(mv) => Ok(mv), - None => Ok(Rc::new(Nil)), + None => Ok(_nil()), } }, List(ref a) => { @@ -37,7 +37,7 @@ fn eval_ast(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet { Err(e) => { return Err(e); }, } } - Ok(Rc::new(List(ast_vec))) + Ok(list(ast_vec)) }, _ => { Ok(ast.clone()) @@ -98,7 +98,7 @@ fn rep(str: String, env: &HashMap<String,MalVal>) -> Result<String,String> { fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet { match *a[0] { Int(a0) => match *a[1] { - Int(a1) => Ok(Rc::new(Int(f(a0,a1)))), + Int(a1) => Ok(_int(f(a0,a1))), _ => Err("second arg must be an int".to_string()), }, _ => Err("first arg must be an int".to_string()), @@ -111,10 +111,10 @@ fn div(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i/j }, a) } fn main() { let mut repl_env : HashMap<String,MalVal> = HashMap::new(); - repl_env.insert("+".to_string(), Rc::new(Func(add))); - repl_env.insert("-".to_string(), Rc::new(Func(sub))); - repl_env.insert("*".to_string(), Rc::new(Func(mul))); - repl_env.insert("/".to_string(), Rc::new(Func(div))); + repl_env.insert("+".to_string(), func(add)); + repl_env.insert("-".to_string(), func(sub)); + repl_env.insert("*".to_string(), func(mul)); + repl_env.insert("/".to_string(), func(div)); loop { let line = readline::mal_readline("user> "); diff --git a/rust/src/step3_env.rs b/rust/src/step3_env.rs index f916396..98d918b 100644 --- a/rust/src/step3_env.rs +++ b/rust/src/step3_env.rs @@ -4,9 +4,8 @@ extern crate regex_macros; extern crate regex; -use std::rc::Rc; - -use types::{MalVal,MalRet,Int,Sym,List,Vector,Func}; +use types::{MalVal,MalRet,Int,Sym,List,Vector,Func, + _int,list,func}; use env::{Env,env_new,env_set,env_get}; mod readline; mod types; @@ -36,7 +35,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Err(e) => { return Err(e); }, } } - Ok(Rc::new(List(ast_vec))) + Ok(list(ast_vec)) }, _ => { Ok(ast) @@ -45,6 +44,8 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { } fn eval(ast: MalVal, env: Env) -> MalRet { + //println!("eval: {}, {}", ast, env.borrow()); + //println!("eval: {}", ast); let ast2 = ast.clone(); match *ast2 { List(_) => (), // continue @@ -54,6 +55,9 @@ fn eval(ast: MalVal, env: Env) -> MalRet { // apply list match *ast2 { List(ref args) => { + if args.len() == 0 { + return Ok(ast); + } let ref a0 = *args[0]; match *a0 { Sym(ref a0sym) => { @@ -162,7 +166,7 @@ fn rep(str: String, env: Env) -> Result<String,String> { fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet { match *a[0] { Int(a0) => match *a[1] { - Int(a1) => Ok(Rc::new(Int(f(a0,a1)))), + Int(a1) => Ok(_int(f(a0,a1))), _ => Err("second arg must be an int".to_string()), }, _ => Err("first arg must be an int".to_string()), @@ -175,10 +179,10 @@ fn div(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i/j }, a) } fn main() { let repl_env = env_new(None); - env_set(&repl_env, "+".to_string(), Rc::new(Func(add))); - env_set(&repl_env, "-".to_string(), Rc::new(Func(sub))); - env_set(&repl_env, "*".to_string(), Rc::new(Func(mul))); - env_set(&repl_env, "/".to_string(), Rc::new(Func(div))); + env_set(&repl_env, "+".to_string(), func(add)); + env_set(&repl_env, "-".to_string(), func(sub)); + env_set(&repl_env, "*".to_string(), func(mul)); + env_set(&repl_env, "/".to_string(), func(div)); loop { let line = readline::mal_readline("user> "); diff --git a/rust/src/step4_if_fn_do.rs b/rust/src/step4_if_fn_do.rs index 9666f34..acf18bf 100644 --- a/rust/src/step4_if_fn_do.rs +++ b/rust/src/step4_if_fn_do.rs @@ -4,10 +4,9 @@ extern crate regex_macros; extern crate regex; -use std::rc::Rc; - -use types::{MalVal,MalRet,MalFunc,MalFuncData, - Nil,False,Sym,List,Vector,Func}; +use types::{MalVal,MalRet,MalFunc, + Nil,False,Sym,List,Vector,Func, + _nil,list,malfunc}; use env::{Env,env_new,env_bind,env_set,env_get}; mod readline; mod types; @@ -38,7 +37,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Err(e) => { return Err(e); }, } } - Ok(Rc::new(List(ast_vec))) + Ok(list(ast_vec)) }, _ => { Ok(ast) @@ -116,7 +115,7 @@ fn eval(ast: MalVal, env: Env) -> MalRet { return eval(a2, let_env.clone()); }, "do" => { - let el = Rc::new(List(args.slice(1,args.len()).to_vec())); + let el = list(args.slice(1,args.len()-1).to_vec()); match eval_ast(el, env.clone()) { Err(e) => return Err(e), Ok(el) => { @@ -140,7 +139,7 @@ fn eval(ast: MalVal, env: Env) -> MalRet { let a3 = (*args)[3].clone(); return eval(a3, env.clone()); } else { - return Ok(Rc::new(Nil)); + return Ok(_nil()); } }, _ => { @@ -152,10 +151,7 @@ fn eval(ast: MalVal, env: Env) -> MalRet { "fn*" => { let a1 = (*args)[1].clone(); let a2 = (*args)[2].clone(); - return Ok(Rc::new(MalFunc(MalFuncData{ - exp: a2, - env: env.clone(), - params: a1}))); + return Ok(malfunc(a2, env.clone(), a1)); }, _ => () } @@ -180,10 +176,9 @@ fn eval(ast: MalVal, env: Env) -> MalRet { Func(f) => f(args.slice(1,args.len()).to_vec()), MalFunc(ref mf) => { let mfc = mf.clone(); - let alst = List(args.slice(1,args.len()).to_vec()); + let alst = list(args.slice(1,args.len()).to_vec()); let new_env = env_new(Some(mfc.env.clone())); - match env_bind(&new_env, mfc.params, - Rc::new(alst)) { + match env_bind(&new_env, mfc.params, alst) { Ok(_) => eval(mfc.exp, new_env), Err(e) => Err(e), } diff --git a/rust/src/step5_tco.rs b/rust/src/step5_tco.rs index c53702f..3051fa7 100644 --- a/rust/src/step5_tco.rs +++ b/rust/src/step5_tco.rs @@ -4,10 +4,9 @@ extern crate regex_macros; extern crate regex; -use std::rc::Rc; - -use types::{MalVal,MalRet,MalFunc,MalFuncData, - Nil,False,Sym,List,Vector,Func}; +use types::{MalVal,MalRet,MalFunc, + Nil,False,Sym,List,Vector,Func, + _nil,list,malfunc}; use env::{Env,env_new,env_bind,env_set,env_get}; mod readline; mod types; @@ -38,7 +37,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Err(e) => { return Err(e); }, } } - Ok(Rc::new(List(ast_vec))) + Ok(list(ast_vec)) }, _ => { Ok(ast) @@ -121,13 +120,12 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { continue 'tco; }, "do" => { - let el = Rc::new(List(args.slice(1,args.len()-1).to_vec())); + let el = list(args.slice(1,args.len()-1).to_vec()); match eval_ast(el, env.clone()) { Err(e) => return Err(e), Ok(_) => { let ref last = args[args.len()-1]; ast = last.clone(); - env = env.clone(); continue 'tco; }, } @@ -144,7 +142,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { env = env.clone(); continue 'tco; } else { - return Ok(Rc::new(Nil)); + return Ok(_nil()); } }, _ => { @@ -158,10 +156,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { "fn*" => { let a1 = (*args)[1].clone(); let a2 = (*args)[2].clone(); - return Ok(Rc::new(MalFunc(MalFuncData{ - exp: a2, - env: env.clone(), - params: a1}))); + return Ok(malfunc(a2, env.clone(), a1)); }, _ => () } @@ -186,10 +181,9 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { Func(f) => f(args.slice(1,args.len()).to_vec()), MalFunc(ref mf) => { let mfc = mf.clone(); - let alst = List(args.slice(1,args.len()).to_vec()); + let alst = list(args.slice(1,args.len()).to_vec()); let new_env = env_new(Some(mfc.env.clone())); - match env_bind(&new_env, mfc.params, - Rc::new(alst)) { + match env_bind(&new_env, mfc.params, alst) { Ok(_) => { ast = mfc.exp; env = new_env; @@ -231,9 +225,11 @@ fn rep(str: String, env: Env) -> Result<String,String> { } fn main() { + // core.rs: defined using rust let repl_env = env_new(None); for (k, v) in core::ns().into_iter() { env_set(&repl_env, k, v); } + // core.mal: defined using the language itself let _ = rep("(def! not (fn* (a) (if a false true)))".to_string(), repl_env.clone()); diff --git a/rust/src/step6_file.rs b/rust/src/step6_file.rs index 958704f..69757fe 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::rc::Rc; use std::os; -use types::{MalVal,MalRet,MalFunc,MalFuncData, - Nil,False,Sym,Strn,List,Vector,Func}; +use types::{MalVal,MalRet,MalFunc, + Nil,False,Sym,List,Vector,Func, + _nil,string,list,malfunc}; use env::{Env,env_new,env_bind,env_root,env_set,env_get}; mod readline; mod types; @@ -39,7 +39,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet { Err(e) => { return Err(e); }, } } - Ok(Rc::new(List(ast_vec))) + Ok(list(ast_vec)) }, _ => { Ok(ast) @@ -122,13 +122,12 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { continue 'tco; }, "do" => { - let el = Rc::new(List(args.slice(1,args.len()-1).to_vec())); + let el = list(args.slice(1,args.len()-1).to_vec()); match eval_ast(el, env.clone()) { Err(e) => return Err(e), Ok(_) => { let ref last = args[args.len()-1]; ast = last.clone(); - env = env.clone(); continue 'tco; }, } @@ -145,7 +144,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { env = env.clone(); continue 'tco; } else { - return Ok(Rc::new(Nil)); + return Ok(_nil()); } }, _ => { @@ -159,10 +158,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { "fn*" => { let a1 = (*args)[1].clone(); let a2 = (*args)[2].clone(); - return Ok(Rc::new(MalFunc(MalFuncData{ - exp: a2, - env: env.clone(), - params: a1}))); + return Ok(malfunc(a2, env.clone(), a1)); }, "eval" => { let a1 = (*args)[1].clone(); @@ -198,10 +194,9 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { Func(f) => f(args.slice(1,args.len()).to_vec()), MalFunc(ref mf) => { let mfc = mf.clone(); - let alst = List(args.slice(1,args.len()).to_vec()); + let alst = list(args.slice(1,args.len()).to_vec()); let new_env = env_new(Some(mfc.env.clone())); - match env_bind(&new_env, mfc.params, - Rc::new(alst)) { + match env_bind(&new_env, mfc.params, alst) { Ok(_) => { ast = mfc.exp; env = new_env; @@ -247,7 +242,7 @@ fn main() { let repl_env = env_new(None); for (k, v) in core::ns().into_iter() { env_set(&repl_env, k, v); } // see eval() for definition of "eval" - env_set(&repl_env, "*ARGV*".to_string(), Rc::new(List(vec![]))); + env_set(&repl_env, "*ARGV*".to_string(), list(vec![])); // core.mal: defined using the language itself let _ = rep("(def! not (fn* (a) (if a false true)))".to_string(), @@ -259,9 +254,9 @@ fn main() { let args = os::args(); if args.len() > 1 { let mv_args = args.slice(2,args.len()).iter() - .map(|a| Rc::new(Strn(a.clone()))) + .map(|a| string(a.to_string())) .collect::<Vec<MalVal>>(); - env_set(&repl_env, "*ARGV*".to_string(), Rc::new(List(mv_args))); + env_set(&repl_env, "*ARGV*".to_string(), list(mv_args)); match rep("(load-file \"".to_string() + args[1] + "\")".to_string(), repl_env.clone()) { Ok(_) => { diff --git a/rust/src/step7_quote.rs b/rust/src/step7_quote.rs new file mode 100644 index 0000000..ae284d4 --- /dev/null +++ b/rust/src/step7_quote.rs @@ -0,0 +1,341 @@ +// support precompiled regexes in reader.rs +#![feature(phase)] +#[phase(plugin)] +extern crate regex_macros; +extern crate regex; + +use std::os; + +use types::{MalVal,MalRet,MalFunc, + Nil,False,Sym,List,Vector,Func, + _nil,symbol,string,list,malfunc}; +use env::{Env,env_new,env_bind,env_root,env_set,env_get}; +mod readline; +mod types; +mod reader; +mod printer; +mod env; +mod core; + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn is_pair(x: MalVal) -> bool { + match *x { + List(ref lst) => lst.len() > 0, + _ => false, + } +} + +fn quasiquote(ast: MalVal) -> MalVal { + if !is_pair(ast.clone()) { + return list(vec![symbol("quote"), ast]) + } + + match *ast.clone() { + List(ref args) => { + let ref a0 = args[0]; + match **a0 { + Sym(ref s) => { + if s.to_string() == "unquote".to_string() { + let ref a1 = args[1]; + return a1.clone(); + } + }, + _ => (), + } + if is_pair(a0.clone()) { + match **a0 { + List(ref a0args) => { + let a00 = a0args[0].clone(); + match *a00 { + Sym(ref s) => { + if s.to_string() == "splice-unquote".to_string() { + return list(vec![symbol("concat"), + a0args[1].clone(), + quasiquote(list(args.slice(1,args.len()).to_vec()))]) + } + }, + _ => (), + } + }, + _ => (), + } + } + let rest = list(args.slice(1,args.len()).to_vec()); + return list(vec![symbol("cons"), + quasiquote(a0.clone()), + quasiquote(rest)]) + }, + _ => _nil(), // should never reach + } +} + +fn eval_ast(ast: MalVal, env: Env) -> MalRet { + let ast2 = ast.clone(); + match *ast2 { + //match *ast { + Sym(ref sym) => { + env_get(env.clone(), sym.clone()) + }, + List(ref a) => { + let mut ast_vec : Vec<MalVal> = vec![]; + for mv in a.iter() { + let mv2 = mv.clone(); + match eval(mv2, env.clone()) { + Ok(mv) => { ast_vec.push(mv); }, + Err(e) => { return Err(e); }, + } + } + Ok(list(ast_vec)) + }, + _ => { + Ok(ast) + } + } +} + +fn eval(mut ast: MalVal, mut env: Env) -> MalRet { + 'tco: loop { + + //println!("eval: {}, {}", ast, env.borrow()); + //println!("eval: {}", ast); + let ast2 = ast.clone(); + let ast3 = ast.clone(); + match *ast2 { + List(_) => (), // continue + _ => return eval_ast(ast2, env), + } + + // apply list + match *ast2 { + List(ref args) => { + if args.len() == 0 { + return Ok(ast3); + } + let ref a0 = *args[0]; + match *a0 { + Sym(ref a0sym) => { + match a0sym.as_slice() { + "def!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + let res = eval(a2, env.clone()); + match res { + Ok(r) => { + match *a1 { + Sym(ref s) => { + env_set(&env.clone(), s.clone(), r.clone()); + return Ok(r); + }, + _ => { + return Err("def! of non-symbol".to_string()) + } + } + }, + Err(e) => return Err(e), + } + }, + "let*" => { + let let_env = env_new(Some(env.clone())); + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + match *a1 { + List(ref binds) | Vector(ref binds) => { + let mut it = binds.iter(); + while it.len() >= 2 { + let b = it.next().unwrap(); + let exp = it.next().unwrap(); + match **b { + Sym(ref bstr) => { + match eval(exp.clone(), let_env.clone()) { + Ok(r) => { + env_set(&let_env, bstr.clone(), r); + }, + Err(e) => { + return Err(e); + }, + } + }, + _ => { + return Err("let* with non-symbol binding".to_string()); + }, + } + } + }, + _ => return Err("let* with non-list bindings".to_string()), + } + ast = a2; + env = let_env.clone(); + continue 'tco; + }, + "quote" => { + return Ok((*args)[1].clone()); + }, + "quasiquote" => { + let a1 = (*args)[1].clone(); + ast = quasiquote(a1); + continue 'tco; + }, + "do" => { + let el = list(args.slice(1,args.len()-1).to_vec()); + match eval_ast(el, env.clone()) { + Err(e) => return Err(e), + Ok(_) => { + let ref last = args[args.len()-1]; + ast = last.clone(); + continue 'tco; + }, + } + }, + "if" => { + let a1 = (*args)[1].clone(); + let cond = eval(a1, env.clone()); + if cond.is_err() { return cond; } + match *cond.unwrap() { + False | Nil => { + if args.len() >= 4 { + let a3 = (*args)[3].clone(); + ast = a3; + env = env.clone(); + continue 'tco; + } else { + return Ok(_nil()); + } + }, + _ => { + let a2 = (*args)[2].clone(); + ast = a2; + env = env.clone(); + continue 'tco; + }, + } + }, + "fn*" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + return Ok(malfunc(a2, env.clone(), a1)); + }, + "eval" => { + let a1 = (*args)[1].clone(); + match eval(a1, env.clone()) { + Ok(exp) => { + ast = exp; + env = env_root(&env); + continue 'tco; + }, + Err(e) => return Err(e), + } + }, + _ => () + } + } + _ => (), + } + // function call + return match eval_ast(ast3, env.clone()) { + Err(e) => Err(e), + Ok(el) => { + match *el { + List(ref args) => { + // TODO: make this work + //match args.as_slice() { + // [&Func(f), rest..] => { + // (*f)(rest.to_vec()) + // }, + // _ => Err("attempt to call non-function".to_string()), + //} + let args2 = args.clone(); + match *args2[0] { + Func(f) => f(args.slice(1,args.len()).to_vec()), + MalFunc(ref mf) => { + let mfc = mf.clone(); + let alst = list(args.slice(1,args.len()).to_vec()); + let new_env = env_new(Some(mfc.env.clone())); + match env_bind(&new_env, mfc.params, alst) { + Ok(_) => { + ast = mfc.exp; + env = new_env; + continue 'tco; + }, + Err(e) => Err(e), + } + }, + _ => Err("attempt to call non-function".to_string()), + } + } + _ => Err("Invalid apply".to_string()), + } + } + } + } + _ => return Err("Expected list".to_string()), + } + + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: String, env: Env) -> Result<String,String> { + match read(str) { + Err(e) => Err(e), + Ok(ast) => { + //println!("read: {}", ast); + match eval(ast, env) { + Err(e) => Err(e), + Ok(exp) => Ok(print(exp)), + } + } + } +} + +fn main() { + // core.rs: defined using rust + let repl_env = env_new(None); + for (k, v) in core::ns().into_iter() { env_set(&repl_env, k, v); } + // see eval() for definition of "eval" + env_set(&repl_env, "*ARGV*".to_string(), list(vec![])); + + // core.mal: defined using the language itself + let _ = rep("(def! not (fn* (a) (if a false true)))".to_string(), + repl_env.clone()); + let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))".to_string(), + repl_env.clone()); + + // Invoked with command line arguments + let args = os::args(); + if args.len() > 1 { + let mv_args = args.slice(2,args.len()).iter() + .map(|a| string(a.to_string())) + .collect::<Vec<MalVal>>(); + env_set(&repl_env, "*ARGV*".to_string(), list(mv_args)); + match rep("(load-file \"".to_string() + args[1] + "\")".to_string(), + repl_env.clone()) { + Ok(_) => { + os::set_exit_status(0); + return; + }, + Err(str) => { + println!("Error: {}", str); + os::set_exit_status(1); + return; + }, + } + } + + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(line.unwrap(), repl_env.clone()) { + Ok(str) => println!("{}", str), + Err(str) => println!("Error: {}", str), + } + } +} diff --git a/rust/src/types.rs b/rust/src/types.rs index 8bd658f..85262c7 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use std::rc::Rc; use std::collections; use std::fmt; @@ -111,3 +113,22 @@ impl fmt::Show for MalType { write!(f, "{}", self.pr_str(true)) } } + +// Convenience constructor functions +pub fn _nil() -> MalVal { Rc::new(Nil) } +pub fn _true() -> MalVal { Rc::new(True) } +pub fn _false() -> MalVal { Rc::new(False) } +pub fn _int(i: int) -> MalVal { Rc::new(Int(i)) } + +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 func(f: fn(Vec<MalVal>) -> MalRet ) -> MalVal { + Rc::new(Func(f)) +} +pub fn malfunc(exp: MalVal, env: Env, params: MalVal) -> MalVal { + Rc::new(MalFunc(MalFuncData{ exp: exp, env: env, params: params})) +} |
