diff options
| author | Joel Martin <github@martintribe.org> | 2015-03-05 13:07:30 -0600 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-03-05 13:07:30 -0600 |
| commit | 35012ea4d59764ab3744f56b5fb5684e86e80422 (patch) | |
| tree | b27e98a23acf56242cf393aa6ea0cdf7815b7d38 /rust/src/bin | |
| parent | 758933f21515b282423bfcb0a2d5a7eca9b41b20 (diff) | |
| parent | e1b2062f95505729e5188d4c857003877e2c09b4 (diff) | |
| download | mal-35012ea4d59764ab3744f56b5fb5684e86e80422.tar.gz mal-35012ea4d59764ab3744f56b5fb5684e86e80422.zip | |
Merge pull request #26 from alexcrichton/update
Update Rust code to the current Rust nightly
Diffstat (limited to 'rust/src/bin')
| -rw-r--r-- | rust/src/bin/step0_repl.rs | 26 | ||||
| -rw-r--r-- | rust/src/bin/step1_read_print.rs | 45 | ||||
| -rw-r--r-- | rust/src/bin/step2_eval.rs | 124 | ||||
| -rw-r--r-- | rust/src/bin/step3_env.rs | 199 | ||||
| -rw-r--r-- | rust/src/bin/step4_if_fn_do.rs | 225 | ||||
| -rw-r--r-- | rust/src/bin/step5_tco.rs | 248 | ||||
| -rw-r--r-- | rust/src/bin/step6_file.rs | 282 | ||||
| -rw-r--r-- | rust/src/bin/step7_quote.rs | 342 | ||||
| -rw-r--r-- | rust/src/bin/step8_macros.rs | 426 | ||||
| -rw-r--r-- | rust/src/bin/step9_try.rs | 468 | ||||
| -rw-r--r-- | rust/src/bin/stepA_mal.rs | 381 |
11 files changed, 2766 insertions, 0 deletions
diff --git a/rust/src/bin/step0_repl.rs b/rust/src/bin/step0_repl.rs new file mode 100644 index 0000000..030c551 --- /dev/null +++ b/rust/src/bin/step0_repl.rs @@ -0,0 +1,26 @@ +extern crate mal; + +use mal::readline::mal_readline; + +// read +fn read(str: String) -> String { + str +} + +// eval +fn eval(ast: String) -> String { + ast +} + +// print +fn print(exp: String) -> String { + exp +} + +fn main() { + loop { + let line = mal_readline("user> "); + match line { None => break, _ => () } + println!("{}", print(eval(read(line.unwrap())))); + } +} diff --git a/rust/src/bin/step1_read_print.rs b/rust/src/bin/step1_read_print.rs new file mode 100644 index 0000000..8be7e0d --- /dev/null +++ b/rust/src/bin/step1_read_print.rs @@ -0,0 +1,45 @@ +extern crate mal; + +use mal::types::{MalVal, MalRet, MalError}; +use mal::types::MalError::{ErrString, ErrMalVal}; +use mal::{readline, reader}; + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn eval(ast: MalVal) -> MalRet { + Ok(ast) +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: String) -> Result<String,MalError> { + match read(str) { + Err(e) => Err(e), + Ok(ast) => { + //println!("read: {}", ast); + match eval(ast) { + Err(e) => Err(e), + Ok(exp) => Ok(print(exp)), + } + } + } +} + +fn main() { + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(line.unwrap()) { + Ok(str) => println!("{}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), + } + } +} diff --git a/rust/src/bin/step2_eval.rs b/rust/src/bin/step2_eval.rs new file mode 100644 index 0000000..3efa51e --- /dev/null +++ b/rust/src/bin/step2_eval.rs @@ -0,0 +1,124 @@ +extern crate mal; + +use std::collections::HashMap; + +use mal::types::{MalVal, MalRet, MalError, err_str}; +use mal::types::{_nil, list, vector, hash_map, _int, func}; +use mal::types::MalType::{Sym, List, Vector, Hash_Map, Int}; +use mal::types::MalError::{ErrString, ErrMalVal}; +use mal::{readline, reader}; + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn eval_ast(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet { + match *ast { + Sym(ref sym) => { + match env.get(sym) { + Some(mv) => Ok(mv.clone()), + None => Ok(_nil()), + } + }, + List(ref a,_) | Vector(ref a,_) => { + let mut ast_vec : Vec<MalVal> = vec![]; + for mv in a.iter() { + match eval(mv.clone(), env) { + Ok(mv) => ast_vec.push(mv), + Err(e) => return Err(e), + } + } + 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()) + } + } +} + +fn eval(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet { + let ast2 = ast.clone(); + match *ast2 { + List(_,_) => (), // continue + _ => return eval_ast(ast2, env), + } + + // apply list + match eval_ast(ast, env) { + Err(e) => Err(e), + Ok(el) => { + match *el { + List(ref args,_) => { + let ref f = args.clone()[0]; + f.apply(args[1..].to_vec()) + } + _ => err_str("Invalid apply"), + } + } + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: &str, env: &HashMap<String,MalVal>) -> Result<String,MalError> { + match read(str.to_string()) { + Err(e) => Err(e), + Ok(ast) => { + //println!("read: {}", ast); + match eval(ast, env) { + Err(e) => Err(e), + Ok(exp) => Ok(print(exp)), + } + } + } +} + +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))), + _ => err_str("second arg must be an int"), + }, + _ => err_str("first arg must be an int"), + } +} +fn add(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i+j }, a) } +fn sub(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i-j }, a) } +fn mul(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i*j }, a) } +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(), 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> "); + match line { None => break, _ => () } + match rep(&line.unwrap(), &repl_env) { + Ok(str) => println!("{}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), + } + } +} diff --git a/rust/src/bin/step3_env.rs b/rust/src/bin/step3_env.rs new file mode 100644 index 0000000..0e75b26 --- /dev/null +++ b/rust/src/bin/step3_env.rs @@ -0,0 +1,199 @@ +extern crate mal; + +use std::collections::HashMap; + +use mal::types::{MalVal, MalRet, MalError, err_str}; +use mal::types::{symbol, _int, list, vector, hash_map, func}; +use mal::types::MalError::{ErrString, ErrMalVal}; +use mal::types::MalType::{Int, Sym, List, Vector, Hash_Map}; +use mal::env::{Env, env_new, env_set, env_get}; +use mal::{readline, reader}; + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn eval_ast(ast: MalVal, env: Env) -> MalRet { + let ast2 = ast.clone(); + match *ast2 { + //match *ast { + Sym(_) => { + env_get(&env, &ast) + }, + 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.clone()) { + Ok(mv) => { ast_vec.push(mv); }, + Err(e) => { return Err(e); }, + } + } + 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) + } + } +} + +fn eval(ast: MalVal, env: Env) -> MalRet { + //println!("eval: {}, {}", ast, env.borrow()); + //println!("eval: {}", ast); + let ast2 = ast.clone(); + match *ast2 { + List(_,_) => (), // continue + _ => return eval_ast(ast2, env), + } + + // apply list + match *ast2 { + List(_,_) => (), // continue + _ => return Ok(ast2), + } + + let (args, a0sym) = match *ast2 { + List(ref args,_) => { + if args.len() == 0 { + return Ok(ast); + } + let ref a0 = *args[0]; + match *a0 { + Sym(ref a0sym) => (args, &a0sym[..]), + _ => (args, "__<fn*>__"), + } + }, + _ => return err_str("Expected list"), + }; + + match a0sym { + "def!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + let res = eval(a2, env.clone()); + match res { + Ok(r) => { + match *a1 { + Sym(_) => { + env_set(&env.clone(), a1.clone(), r.clone()); + return Ok(r); + }, + _ => { + return err_str("def! of non-symbol") + } + } + }, + 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(_) => { + match eval(exp.clone(), let_env.clone()) { + Ok(r) => { + env_set(&let_env, b.clone(), r); + }, + Err(e) => { + return Err(e); + }, + } + }, + _ => { + return err_str("let* with non-symbol binding"); + }, + } + } + }, + _ => return err_str("let* with non-list bindings"), + } + return eval(a2, let_env.clone()); + }, + _ => { // function call + return match eval_ast(ast, env) { + Err(e) => Err(e), + Ok(el) => { + let args = match *el { + List(ref args,_) => args, + _ => return err_str("Invalid apply"), + }; + let ref f = args.clone()[0]; + f.apply(args[1..].to_vec()) + } + }; + }, + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: &str, env: Env) -> Result<String,MalError> { + match read(str.to_string()) { + Err(e) => Err(e), + Ok(ast) => { + //println!("read: {}", ast); + match eval(ast, env) { + Err(e) => Err(e), + Ok(exp) => Ok(print(exp)), + } + } + } +} + +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))), + _ => err_str("second arg must be an int"), + }, + _ => err_str("first arg must be an int"), + } +} +fn add(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i+j }, a) } +fn sub(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i-j }, a) } +fn mul(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i*j }, a) } +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, symbol("+"), func(add)); + env_set(&repl_env, symbol("-"), func(sub)); + env_set(&repl_env, symbol("*"), func(mul)); + env_set(&repl_env, symbol("/"), func(div)); + + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(&line.unwrap(), repl_env.clone()) { + Ok(str) => println!("{}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), + } + } +} diff --git a/rust/src/bin/step4_if_fn_do.rs b/rust/src/bin/step4_if_fn_do.rs new file mode 100644 index 0000000..afbf69a --- /dev/null +++ b/rust/src/bin/step4_if_fn_do.rs @@ -0,0 +1,225 @@ +extern crate mal; + +use std::collections::HashMap; + +use mal::types::{MalVal, MalRet, MalError, err_str}; +use mal::types::{symbol, _nil, list, vector, hash_map, malfunc}; +use mal::types::MalType::{Nil, False, Sym, List, Vector, Hash_Map}; +use mal::types::MalError::{ErrString, ErrMalVal}; +use mal::{readline, reader, core}; +use mal::env::{env_set, env_get, env_new, Env}; + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn eval_ast(ast: MalVal, env: Env) -> MalRet { + let ast2 = ast.clone(); + match *ast2 { + //match *ast { + Sym(_) => env_get(&env, &ast), + 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.clone()) { + Ok(mv) => { ast_vec.push(mv); }, + Err(e) => { return Err(e); }, + } + } + 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) + } + } +} + +fn eval(ast: MalVal, env: Env) -> MalRet { + //println!("eval: {}, {}", ast, env.borrow()); + //println!("eval: {}", ast); + let ast2 = ast.clone(); + match *ast2 { + List(_,_) => (), // continue + _ => return eval_ast(ast2, env), + } + + // apply list + match *ast2 { + List(_,_) => (), // continue + _ => return Ok(ast2), + } + + let (args, a0sym) = match *ast2 { + List(ref args,_) => { + if args.len() == 0 { + return Ok(ast); + } + let ref a0 = *args[0]; + match *a0 { + Sym(ref a0sym) => (args, &a0sym[..]), + _ => (args, "__<fn*>__"), + } + }, + _ => return err_str("Expected list"), + }; + + match a0sym { + "def!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + let res = eval(a2, env.clone()); + match res { + Ok(r) => { + match *a1 { + Sym(_) => { + env_set(&env.clone(), a1.clone(), r.clone()); + return Ok(r); + }, + _ => { + return err_str("def! of non-symbol") + } + } + }, + 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(_) => { + match eval(exp.clone(), let_env.clone()) { + Ok(r) => { + env_set(&let_env, b.clone(), r); + }, + Err(e) => { + return Err(e); + }, + } + }, + _ => { + return err_str("let* with non-symbol binding"); + }, + } + } + }, + _ => return err_str("let* with non-list bindings"), + } + return eval(a2, let_env.clone()); + }, + "do" => { + let el = list(args[1..].to_vec()); + return match eval_ast(el, env.clone()) { + Err(e) => return Err(e), + Ok(el) => { + match *el { + List(ref lst,_) => { + let ref last = lst[lst.len()-1]; + return Ok(last.clone()); + } + _ => return err_str("invalid do call"), + } + }, + }; + }, + "if" => { + let a1 = (*args)[1].clone(); + let cond = eval(a1, env.clone()); + match cond { + Err(e) => return Err(e), + Ok(c) => match *c { + False | Nil => { + if args.len() >= 4 { + let a3 = (*args)[3].clone(); + return eval(a3, env.clone()); + } else { + return Ok(_nil()); + } + }, + _ => { + let a2 = (*args)[2].clone(); + return eval(a2, env.clone()); + }, + } + } + }, + "fn*" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + return Ok(malfunc(eval, a2, env.clone(), a1, _nil())); + }, + _ => { // function call + return match eval_ast(ast, env.clone()) { + Err(e) => Err(e), + Ok(el) => { + let args = match *el { + List(ref args,_) => args, + _ => return err_str("Invalid apply"), + }; + let ref f = args.clone()[0]; + f.apply(args[1..].to_vec()) + } + }; + }, + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: &str, env: Env) -> Result<String,MalError> { + match read(str.to_string()) { + 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, symbol(&k), v); + } + + // core.mal: defined using the language itself + let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone()); + + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(&line.unwrap(), repl_env.clone()) { + Ok(str) => println!("{}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), + } + } +} diff --git a/rust/src/bin/step5_tco.rs b/rust/src/bin/step5_tco.rs new file mode 100644 index 0000000..4117634 --- /dev/null +++ b/rust/src/bin/step5_tco.rs @@ -0,0 +1,248 @@ +extern crate mal; + +use std::collections::HashMap; + +use mal::types::{MalVal, MalRet, MalError, err_str}; +use mal::types::{symbol, _nil, list, vector, hash_map, malfunc}; +use mal::types::MalType::{Nil, False, Sym, List, Vector, Hash_Map, Func, MalFunc}; +use mal::types::MalError::{ErrString, ErrMalVal}; +use mal::{readline, reader, core}; +use mal::env::{env_set, env_get, env_new, env_bind, Env}; + + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn eval_ast(ast: MalVal, env: Env) -> MalRet { + let ast2 = ast.clone(); + match *ast2 { + //match *ast { + Sym(_) => env_get(&env, &ast), + 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.clone()) { + Ok(mv) => { ast_vec.push(mv); }, + Err(e) => { return Err(e); }, + } + } + 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) + } + } +} + +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(_,_) => (), // continue + _ => return Ok(ast2), + } + + let (args, a0sym) = match *ast2 { + List(ref args,_) => { + if args.len() == 0 { + return Ok(ast3); + } + let ref a0 = *args[0]; + match *a0 { + Sym(ref a0sym) => (args, &a0sym[..]), + _ => (args, "__<fn*>__"), + } + }, + _ => return err_str("Expected list"), + }; + + match a0sym { + "def!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + let res = eval(a2, env.clone()); + match res { + Ok(r) => { + match *a1 { + Sym(_) => { + env_set(&env.clone(), a1.clone(), r.clone()); + return Ok(r); + }, + _ => { + return err_str("def! of non-symbol") + } + } + }, + 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(_) => { + match eval(exp.clone(), let_env.clone()) { + Ok(r) => { + env_set(&let_env, b.clone(), r); + }, + Err(e) => { + return Err(e); + }, + } + }, + _ => { + return err_str("let* with non-symbol binding"); + }, + } + } + }, + _ => return err_str("let* with non-list bindings"), + } + ast = a2; + env = let_env.clone(); + continue 'tco; + }, + "do" => { + let el = list(args[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()); + match cond { + Err(e) => return Err(e), + Ok(c) => match *c { + 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(eval, a2, env.clone(), a1, _nil())); + }, + _ => { // function call + return match eval_ast(ast3, env.clone()) { + Err(e) => Err(e), + Ok(el) => { + let args = match *el { + List(ref args,_) => args, + _ => return err_str("Invalid apply"), + }; + match *args.clone()[0] { + Func(f,_) => f(args[1..].to_vec()), + MalFunc(ref mf,_) => { + let mfc = mf.clone(); + let alst = list(args[1..].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_str(&e), + } + }, + _ => err_str("attempt to call non-function"), + } + } + } + }, + } + + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: &str, env: Env) -> Result<String,MalError> { + match read(str.to_string()) { + 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, symbol(&k), v); + } + + // core.mal: defined using the language itself + let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone()); + + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(&line.unwrap(), repl_env.clone()) { + Ok(str) => println!("{}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), + } + } +} diff --git a/rust/src/bin/step6_file.rs b/rust/src/bin/step6_file.rs new file mode 100644 index 0000000..8d9a26c --- /dev/null +++ b/rust/src/bin/step6_file.rs @@ -0,0 +1,282 @@ +#![feature(exit_status)] + +extern crate mal; + +use std::collections::HashMap; +use std::env as stdenv; + +use mal::types::{MalVal, MalRet, MalError, err_str}; +use mal::types::{symbol, _nil, string, list, vector, hash_map, malfunc}; +use mal::types::MalType::{Nil, False, Sym, List, Vector, Hash_Map, Func, MalFunc}; +use mal::types::MalError::{ErrString, ErrMalVal}; +use mal::{readline, reader, core}; +use mal::env::{env_set, env_get, env_new, env_bind, env_root, Env}; + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn eval_ast(ast: MalVal, env: Env) -> MalRet { + let ast2 = ast.clone(); + match *ast2 { + //match *ast { + Sym(_) => env_get(&env, &ast), + 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.clone()) { + Ok(mv) => { ast_vec.push(mv); }, + Err(e) => { return Err(e); }, + } + } + 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) + } + } +} + +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(_,_) => (), // continue + _ => return Ok(ast2), + } + + let (args, a0sym) = match *ast2 { + List(ref args,_) => { + if args.len() == 0 { + return Ok(ast3); + } + let ref a0 = *args[0]; + match *a0 { + Sym(ref a0sym) => (args, &a0sym[..]), + _ => (args, "__<fn*>__"), + } + }, + _ => return err_str("Expected list"), + }; + + match a0sym { + "def!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + let res = eval(a2, env.clone()); + match res { + Ok(r) => { + match *a1 { + Sym(_) => { + env_set(&env.clone(), a1.clone(), r.clone()); + return Ok(r); + }, + _ => { + return err_str("def! of non-symbol") + } + } + }, + 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(_) => { + match eval(exp.clone(), let_env.clone()) { + Ok(r) => { + env_set(&let_env, b.clone(), r); + }, + Err(e) => { + return Err(e); + }, + } + }, + _ => { + return err_str("let* with non-symbol binding"); + }, + } + } + }, + _ => return err_str("let* with non-list bindings"), + } + ast = a2; + env = let_env.clone(); + continue 'tco; + }, + "do" => { + let el = list(args[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()); + match cond { + Err(e) => return Err(e), + Ok(c) => match *c { + 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(eval, a2, env.clone(), a1, _nil())); + }, + "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) => { + let args = match *el { + List(ref args,_) => args, + _ => return err_str("Invalid apply"), + }; + match *args.clone()[0] { + Func(f,_) => f(args[1..].to_vec()), + MalFunc(ref mf,_) => { + let mfc = mf.clone(); + let alst = list(args[1..].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_str(&e), + } + }, + _ => err_str("attempt to call non-function"), + } + } + } + }, + } + + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: &str, env: Env) -> Result<String,MalError> { + match read(str.to_string()) { + 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, symbol(&k), v); + } + // see eval() for definition of "eval" + env_set(&repl_env, symbol("*ARGV*"), list(vec![])); + + // core.mal: defined using the language itself + let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone()); + let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env.clone()); + + // Invoked with command line arguments + let args = stdenv::args(); + if args.len() > 1 { + let mv_args = args.skip(2) + .map(|a| string(a)) + .collect::<Vec<MalVal>>(); + env_set(&repl_env, symbol("*ARGV*"), list(mv_args)); + let lf = format!("(load-file \"{}\")", + stdenv::args().skip(1).next().unwrap()); + return match rep(&lf, repl_env.clone()) { + Ok(_) => stdenv::set_exit_status(0), + Err(str) => { + println!("Error: {:?}", str); + stdenv::set_exit_status(1); + } + }; + } + + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(&line.unwrap(), repl_env.clone()) { + Ok(str) => println!("{}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), + } + } +} diff --git a/rust/src/bin/step7_quote.rs b/rust/src/bin/step7_quote.rs new file mode 100644 index 0000000..77d5d33 --- /dev/null +++ b/rust/src/bin/step7_quote.rs @@ -0,0 +1,342 @@ +#![feature(exit_status)] + +extern crate mal; + +use std::collections::HashMap; +use std::env as stdenv; + +use mal::types::{MalVal, MalRet, MalError, err_str}; +use mal::types::{symbol, _nil, string, list, vector, hash_map, malfunc}; +use mal::types::MalType::{Nil, False, Sym, List, Vector, Hash_Map, Func, MalFunc}; +use mal::types::MalError::{ErrString, ErrMalVal}; +use mal::{readline, reader, core}; +use mal::env::{env_set, env_get, env_new, env_bind, env_root, Env}; + + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn is_pair(x: MalVal) -> bool { + match *x { + List(ref lst,_) | Vector(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,_) | Vector(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,_) | Vector(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[1..].to_vec()))]) + } + }, + _ => (), + } + }, + _ => (), + } + } + let rest = list(args[1..].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(_) => env_get(&env, &ast), + 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.clone()) { + Ok(mv) => { ast_vec.push(mv); }, + Err(e) => { return Err(e); }, + } + } + 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) + } + } +} + +fn eval(mut ast: MalVal, mut env: Env) -> MalRet { + 'tco: loop { + + //println!("eval: {}, {}", ast, env.borrow()); + //println!("eval: {}", ast); + let ast2 = ast.clone(); + match *ast2 { + List(_,_) => (), // continue + _ => return eval_ast(ast2, env), + } + + // apply list + match *ast2 { + List(_,_) => (), // continue + _ => return Ok(ast2), + } + let ast3 = ast2.clone(); + + let (args, a0sym) = match *ast2 { + List(ref args,_) => { + if args.len() == 0 { + return Ok(ast3); + } + let ref a0 = *args[0]; + match *a0 { + Sym(ref a0sym) => (args, &a0sym[..]), + _ => (args, "__<fn*>__"), + } + }, + _ => return err_str("Expected list"), + }; + + match a0sym { + "def!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + let res = eval(a2, env.clone()); + match res { + Ok(r) => { + match *a1 { + Sym(_) => { + env_set(&env.clone(), a1.clone(), r.clone()); + return Ok(r); + }, + _ => { + return err_str("def! of non-symbol") + } + } + }, + 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(_) => { + match eval(exp.clone(), let_env.clone()) { + Ok(r) => { + env_set(&let_env, b.clone(), r); + }, + Err(e) => { + return Err(e); + }, + } + }, + _ => { + return err_str("let* with non-symbol binding"); + }, + } + } + }, + _ => return err_str("let* with non-list bindings"), + } + 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[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()); + match cond { + Err(e) => return Err(e), + Ok(c) => match *c { + 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(eval, a2, env.clone(), a1, _nil())); + }, + "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) => { + let args = match *el { + List(ref args,_) => args, + _ => return err_str("Invalid apply"), + }; + match *args.clone()[0] { + Func(f,_) => f(args[1..].to_vec()), + MalFunc(ref mf,_) => { + let mfc = mf.clone(); + let alst = list(args[1..].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_str(&e), + } + }, + _ => err_str("attempt to call non-function"), + } + } + } + }, + } + + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: &str, env: Env) -> Result<String,MalError> { + match read(str.to_string()) { + 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, symbol(&k), v); + } + // see eval() for definition of "eval" + env_set(&repl_env, symbol("*ARGV*"), list(vec![])); + + // core.mal: defined using the language itself + let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone()); + let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env.clone()); + + // Invoked with command line arguments + let args = stdenv::args(); + if args.len() > 1 { + let mv_args = args.skip(2) + .map(|a| string(a)) + .collect::<Vec<MalVal>>(); + env_set(&repl_env, symbol("*ARGV*"), list(mv_args)); + let lf = format!("(load-file \"{}\")", + stdenv::args().skip(1).next().unwrap()); + return match rep(&lf, repl_env.clone()) { + Ok(_) => stdenv::set_exit_status(0), + Err(str) => { + println!("Error: {:?}", str); + stdenv::set_exit_status(1); + } + }; + } + + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(&line.unwrap(), repl_env.clone()) { + Ok(str) => println!("{}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), + } + } +} diff --git a/rust/src/bin/step8_macros.rs b/rust/src/bin/step8_macros.rs new file mode 100644 index 0000000..a808926 --- /dev/null +++ b/rust/src/bin/step8_macros.rs @@ -0,0 +1,426 @@ +#![feature(exit_status)] + +extern crate mal; + +use std::collections::HashMap; +use std::env as stdenv; + +use mal::types::{MalVal, MalRet, MalError, err_str}; +use mal::types::{symbol, _nil, string, list, vector, hash_map, malfunc, malfuncd}; +use mal::types::MalType::{Nil, False, Sym, List, Vector, Hash_Map, Func, MalFunc}; +use mal::types::MalError::{ErrString, ErrMalVal}; +use mal::{readline, reader, core}; +use mal::env::{env_set, env_get, env_new, env_bind, env_find, env_root, Env}; + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn is_pair(x: MalVal) -> bool { + match *x { + List(ref lst,_) | Vector(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,_) | Vector(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,_) | Vector(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[1..].to_vec()))]) + } + }, + _ => (), + } + }, + _ => (), + } + } + let rest = list(args[1..].to_vec()); + return list(vec![symbol("cons"), + quasiquote(a0.clone()), + quasiquote(rest)]) + }, + _ => _nil(), // should never reach + } +} + +fn is_macro_call(ast: MalVal, env: Env) -> bool { + match *ast { + List(ref lst,_) => { + match *lst[0] { + Sym(_) => { + if env_find(&env, &lst[0]).is_some() { + match env_get(&env, &lst[0]) { + Ok(f) => { + match *f { + MalFunc(ref mfd,_) => { + mfd.is_macro + }, + _ => false, + } + }, + _ => false, + } + } else { + false + } + }, + _ => false, + } + }, + _ => false, + } +} + +fn macroexpand(mut ast: MalVal, env: Env) -> MalRet { + while is_macro_call(ast.clone(), env.clone()) { + let ast2 = ast.clone(); + let args = match *ast2 { + List(ref args,_) => args, + _ => break, + }; + let ref a0 = args[0]; + let mf = match **a0 { + Sym(_) => try!(env_get(&env, &a0)), + _ => break, + }; + match *mf { + MalFunc(_,_) => ast = try!(mf.apply(args[1..].to_vec())), + _ => break, + } + } + Ok(ast) +} + +fn eval_ast(ast: MalVal, env: Env) -> MalRet { + let ast2 = ast.clone(); + match *ast2 { + //match *ast { + Sym(_) => env_get(&env, &ast), + 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.clone()) { + Ok(mv) => { ast_vec.push(mv); }, + Err(e) => { return Err(e); }, + } + } + 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) + } + } +} + +fn eval(mut ast: MalVal, mut env: Env) -> MalRet { + 'tco: loop { + + //println!("eval: {}, {}", ast, env.borrow()); + //println!("eval: {}", ast); + let mut ast2 = ast.clone(); + match *ast2 { + List(_,_) => (), // continue + _ => return eval_ast(ast2, env), + } + + // apply list + match macroexpand(ast2, env.clone()) { + Ok(a) => { + ast2 = a; + }, + Err(e) => return Err(e), + } + match *ast2 { + List(_,_) => (), // continue + _ => return Ok(ast2), + } + let ast3 = ast2.clone(); + + let (args, a0sym) = match *ast2 { + List(ref args,_) => { + if args.len() == 0 { + return Ok(ast3); + } + let ref a0 = *args[0]; + match *a0 { + Sym(ref a0sym) => (args, &a0sym[..]), + _ => (args, "__<fn*>__"), + } + }, + _ => return err_str("Expected list"), + }; + + match a0sym { + "def!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + let res = eval(a2, env.clone()); + match res { + Ok(r) => { + match *a1 { + Sym(_) => { + env_set(&env.clone(), a1.clone(), r.clone()); + return Ok(r); + }, + _ => { + return err_str("def! of non-symbol") + } + } + }, + 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(_) => { + match eval(exp.clone(), let_env.clone()) { + Ok(r) => { + env_set(&let_env, b.clone(), r); + }, + Err(e) => { + return Err(e); + }, + } + }, + _ => { + return err_str("let* with non-symbol binding"); + }, + } + } + }, + _ => return err_str("let* with non-list bindings"), + } + 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; + }, + "defmacro!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + match eval(a2, env.clone()) { + Ok(r) => { + match *r { + MalFunc(ref mfd,_) => { + match *a1 { + Sym(_) => { + let mut new_mfd = mfd.clone(); + new_mfd.is_macro = true; + let mf = malfuncd(new_mfd,_nil()); + env_set(&env.clone(), a1.clone(), mf.clone()); + return Ok(mf); + }, + _ => return err_str("def! of non-symbol"), + } + }, + _ => return err_str("def! of non-symbol"), + } + }, + Err(e) => return Err(e), + } + }, + "macroexpand" => { + let a1 = (*args)[1].clone(); + return macroexpand(a1, env.clone()) + }, + "do" => { + let el = list(args[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()); + match cond { + Err(e) => return Err(e), + Ok(c) => match *c { + 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(eval, a2, env.clone(), a1, _nil())); + }, + "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) => { + let args = match *el { + List(ref args,_) => args, + _ => return err_str("Invalid apply"), + }; + match *args.clone()[0] { + Func(f,_) => f(args[1..].to_vec()), + MalFunc(ref mf,_) => { + let mfc = mf.clone(); + let alst = list(args[1..].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_str(&e), + } + }, + _ => err_str("attempt to call non-function"), + } + } + } + }, + } + + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: &str, env: Env) -> Result<String,MalError> { + match read(str.to_string()) { + 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, symbol(&k), v); + } + // see eval() for definition of "eval" + env_set(&repl_env, symbol("*ARGV*"), list(vec![])); + + // core.mal: defined using the language itself + let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone()); + let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env.clone()); + let _ = rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", repl_env.clone()); + let _ = rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))", repl_env.clone()); + + // Invoked with command line arguments + let args = stdenv::args(); + if args.len() > 1 { + let mv_args = args.skip(2) + .map(|a| string(a)) + .collect::<Vec<MalVal>>(); + env_set(&repl_env, symbol("*ARGV*"), list(mv_args)); + let lf = format!("(load-file \"{}\")", + stdenv::args().skip(1).next().unwrap()); + return match rep(&lf, repl_env.clone()) { + Ok(_) => stdenv::set_exit_status(0), + Err(str) => { + println!("Error: {:?}", str); + stdenv::set_exit_status(1); + } + }; + } + + // repl loop + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(&line.unwrap(), repl_env.clone()) { + Ok(str) => println!("{}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), + } + } +} diff --git a/rust/src/bin/step9_try.rs b/rust/src/bin/step9_try.rs new file mode 100644 index 0000000..f6c5dbf --- /dev/null +++ b/rust/src/bin/step9_try.rs @@ -0,0 +1,468 @@ +#![feature(exit_status)] + +extern crate mal; + +use std::collections::HashMap; +use std::env as stdenv; + +use mal::types::{MalVal, MalRet, MalError, err_str}; +use mal::types::{symbol, _nil, string, list, vector, hash_map, malfunc, malfuncd}; +use mal::types::MalType::{Nil, False, Sym, List, Vector, Hash_Map, Func, MalFunc}; +use mal::types::MalError::{ErrString, ErrMalVal}; +use mal::{readline, reader, core}; +use mal::env::{env_set, env_get, env_new, env_bind, env_find, env_root, Env}; + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn is_pair(x: MalVal) -> bool { + match *x { + List(ref lst, _) | Vector(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,_) | Vector(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,_) | Vector(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[1..].to_vec()))]) + } + }, + _ => (), + } + }, + _ => (), + } + } + let rest = list(args[1..].to_vec()); + return list(vec![symbol("cons"), + quasiquote(a0.clone()), + quasiquote(rest)]) + }, + _ => _nil(), // should never reach + } +} + +fn is_macro_call(ast: MalVal, env: Env) -> bool { + match *ast { + List(ref lst,_) => { + match *lst[0] { + Sym(_) => { + if env_find(&env, &lst[0]).is_some() { + match env_get(&env, &lst[0]) { + Ok(f) => { + match *f { + MalFunc(ref mfd,_) => { + mfd.is_macro + }, + _ => false, + } + }, + _ => false, + } + } else { + false + } + }, + _ => false, + } + }, + _ => false, + } +} + +fn macroexpand(mut ast: MalVal, env: Env) -> MalRet { + while is_macro_call(ast.clone(), env.clone()) { + let ast2 = ast.clone(); + let args = match *ast2 { + List(ref args,_) => args, + _ => break, + }; + let ref a0 = args[0]; + let mf = match **a0 { + Sym(_) => { + match env_get(&env, &a0) { + Ok(mf) => mf, + Err(e) => return Err(e), + } + }, + _ => break, + }; + match *mf { + MalFunc(_,_) => { + match mf.apply(args[1..].to_vec()) { + Ok(r) => ast = r, + Err(e) => return Err(e), + } + }, + _ => break, + } + } + Ok(ast) +} + +fn eval_ast(ast: MalVal, env: Env) -> MalRet { + let ast2 = ast.clone(); + match *ast2 { + //match *ast { + Sym(_) => { + env_get(&env, &ast) + }, + 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.clone()) { + Ok(mv) => { ast_vec.push(mv); }, + Err(e) => { return Err(e); }, + } + } + 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) + } + } +} + +fn eval(mut ast: MalVal, mut env: Env) -> MalRet { + 'tco: loop { + + //println!("eval: {}, {}", ast, env.borrow()); + //println!("eval: {}", ast); + let mut ast2 = ast.clone(); + match *ast2 { + List(_,_) => (), // continue + _ => return eval_ast(ast2, env), + } + + // apply list + match macroexpand(ast2, env.clone()) { + Ok(a) => { + ast2 = a; + }, + Err(e) => return Err(e), + } + match *ast2 { + List(_,_) => (), // continue + _ => return Ok(ast2), + } + let ast3 = ast2.clone(); + + let (args, a0sym) = match *ast2 { + List(ref args,_) => { + if args.len() == 0 { + return Ok(ast3); + } + let ref a0 = *args[0]; + match *a0 { + Sym(ref a0sym) => (args, &a0sym[..]), + _ => (args, "__<fn*>__"), + } + }, + _ => return err_str("Expected list"), + }; + + match a0sym { + "def!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + let res = eval(a2, env.clone()); + match res { + Ok(r) => { + match *a1 { + Sym(_) => { + env_set(&env.clone(), a1.clone(), r.clone()); + return Ok(r); + }, + _ => { + return err_str("def! of non-symbol") + } + } + }, + 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(_) => { + match eval(exp.clone(), let_env.clone()) { + Ok(r) => { + env_set(&let_env, b.clone(), r); + }, + Err(e) => { + return Err(e); + }, + } + }, + _ => { + return err_str("let* with non-symbol binding"); + }, + } + } + }, + _ => return err_str("let* with non-list bindings"), + } + 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; + }, + "defmacro!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + match eval(a2, env.clone()) { + Ok(r) => { + match *r { + MalFunc(ref mfd,_) => { + match *a1 { + Sym(_) => { + let mut new_mfd = mfd.clone(); + new_mfd.is_macro = true; + let mf = malfuncd(new_mfd,_nil()); + env_set(&env.clone(), a1.clone(), mf.clone()); + return Ok(mf); + }, + _ => return err_str("def! of non-symbol"), + } + }, + _ => return err_str("def! of non-symbol"), + } + }, + Err(e) => return Err(e), + } + }, + "macroexpand" => { + let a1 = (*args)[1].clone(); + return macroexpand(a1, env.clone()) + }, + "try*" => { + let a1 = (*args)[1].clone(); + match eval(a1, env.clone()) { + Ok(res) => return Ok(res), + Err(err) => { + if args.len() < 3 { return Err(err); } + let a2 = (*args)[2].clone(); + let cat = match *a2 { + List(ref cat,_) => cat, + _ => return err_str("invalid catch* clause"), + }; + if cat.len() != 3 { + return err_str("wrong arity to catch* clause"); + } + let c1 = (*cat)[1].clone(); + match *c1 { + Sym(_) => {}, + _ => return err_str("invalid catch* binding"), + }; + let exc = match err { + ErrMalVal(mv) => mv, + ErrString(s) => string(s), + }; + let bind_env = env_new(Some(env.clone())); + env_set(&bind_env, c1.clone(), exc); + let c2 = (*cat)[2].clone(); + return eval(c2, bind_env); + }, + }; + } + "do" => { + let el = list(args[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()); + match cond { + Err(e) => return Err(e), + Ok(c) => match *c { + 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(eval, a2, env.clone(), a1, _nil())); + }, + "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) => { + let args = match *el { + List(ref args,_) => args, + _ => return err_str("Invalid apply"), + }; + match *args.clone()[0] { + Func(f,_) => f(args[1..].to_vec()), + MalFunc(ref mf,_) => { + let mfc = mf.clone(); + let alst = list(args[1..].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_str(&e), + } + }, + _ => err_str("attempt to call non-function"), + } + } + } + }, + } + + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: &str, env: Env) -> Result<String,MalError> { + match read(str.to_string()) { + 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, symbol(&k), v); + } + // see eval() for definition of "eval" + env_set(&repl_env, symbol("*ARGV*"), list(vec![])); + + // core.mal: defined using the language itself + let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone()); + let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env.clone()); + let _ = rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", repl_env.clone()); + let _ = rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))", repl_env.clone()); + + // Invoked with command line arguments + let args = stdenv::args(); + if args.len() > 1 { + let mv_args = args.skip(2) + .map(|a| string(a)) + .collect::<Vec<MalVal>>(); + env_set(&repl_env, symbol("*ARGV*"), list(mv_args)); + let lf = format!("(load-file \"{}\")", + stdenv::args().skip(1).next().unwrap()); + return match rep(&lf, repl_env.clone()) { + Ok(_) => stdenv::set_exit_status(0), + Err(str) => { + println!("Error: {:?}", str); + stdenv::set_exit_status(1); + } + }; + } + + // repl loop + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(&line.unwrap(), repl_env.clone()) { + Ok(str) => println!("{}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), + } + } +} diff --git a/rust/src/bin/stepA_mal.rs b/rust/src/bin/stepA_mal.rs new file mode 100644 index 0000000..b84a079 --- /dev/null +++ b/rust/src/bin/stepA_mal.rs @@ -0,0 +1,381 @@ +#![feature(exit_status)] + +extern crate mal; + +use std::collections::HashMap; +use std::env as stdenv; + +use mal::types::{MalVal, MalRet, MalError, err_str}; +use mal::types::{symbol, _nil, string, list, vector, hash_map, malfunc, malfuncd}; +use mal::types::MalType::{Nil, False, Sym, List, Vector, Hash_Map, Func, MalFunc}; +use mal::types::MalError::{ErrString, ErrMalVal}; +use mal::{readline, reader, core}; +use mal::env::{env_set, env_get, env_new, env_bind, env_find, env_root, Env}; + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn is_pair(x: MalVal) -> bool { + match *x { + List(ref lst,_) | Vector(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,_) | Vector(ref args,_) => { + let ref a0 = args[0]; + match **a0 { + Sym(ref s) if *s == "unquote" => return args[1].clone(), + _ => (), + } + if is_pair(a0.clone()) { + match **a0 { + List(ref a0args,_) | Vector(ref a0args,_) => { + match *a0args[0] { + Sym(ref s) if *s == "splice-unquote" => { + return list(vec![symbol("concat"), + a0args[1].clone(), + quasiquote(list(args[1..].to_vec()))]) + }, + _ => (), + } + }, + _ => (), + } + } + let rest = list(args[1..].to_vec()); + return list(vec![symbol("cons"), + quasiquote(a0.clone()), + quasiquote(rest)]) + }, + _ => _nil(), // should never reach + } +} + +fn is_macro_call(ast: MalVal, env: Env) -> bool { + let lst = match *ast { + List(ref lst,_) => &lst[0], + _ => return false + }; + match **lst { + Sym(_) => {}, + _ => return false + } + if env_find(&env, lst).is_none() { + return false + } + let f = match env_get(&env, lst) { + Ok(f) => f, + _ => return false + }; + match *f { + MalFunc(ref mfd,_) => mfd.is_macro, + _ => false, + } +} + +fn macroexpand(mut ast: MalVal, env: Env) -> MalRet { + while is_macro_call(ast.clone(), env.clone()) { + let ast2 = ast.clone(); + let args = match *ast2 { + List(ref args,_) => args, + _ => break, + }; + let ref a0 = args[0]; + let mf = match **a0 { + Sym(_) => try!(env_get(&env, &a0)), + _ => break, + }; + match *mf { + MalFunc(_,_) => ast = try!(mf.apply(args[1..].to_vec())), + _ => break, + } + } + Ok(ast) +} + +fn eval_ast(ast: MalVal, env: Env) -> MalRet { + match *ast { + Sym(_) => env_get(&env, &ast), + List(ref a,_) | Vector(ref a,_) => { + let mut ast_vec : Vec<MalVal> = vec![]; + for mv in a.iter() { + let mv2 = mv.clone(); + ast_vec.push(try!(eval(mv2, env.clone()))); + } + 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() { + new_hm.insert(key.to_string(), + try!(eval(value.clone(), env.clone()))); + } + Ok(hash_map(new_hm)) + } + _ => Ok(ast.clone()), + } +} + +fn eval(mut ast: MalVal, mut env: Env) -> MalRet { + 'tco: loop { + + //println!("eval: {}, {}", ast, env.borrow()); + //println!("eval: {}", ast); + match *ast { + List(_,_) => (), // continue + _ => return eval_ast(ast, env), + } + + // apply list + ast = try!(macroexpand(ast, env.clone())); + match *ast { + List(_,_) => (), // continue + _ => return Ok(ast), + } + + let tmp = ast; + let (args, a0sym) = match *tmp { + List(ref args,_) => { + if args.len() == 0 { + return Ok(tmp.clone()); + } + let ref a0 = *args[0]; + match *a0 { + Sym(ref a0sym) => (args, &a0sym[..]), + _ => (args, "__<fn*>__"), + } + }, + _ => return err_str("Expected list"), + }; + + match a0sym { + "def!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + let r = try!(eval(a2, env.clone())); + match *a1 { + Sym(_) => { + env_set(&env.clone(), a1, r.clone()); + return Ok(r); + }, + _ => return err_str("def! of non-symbol"), + } + }, + "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(_) => { + let r = try!(eval(exp.clone(), let_env.clone())); + env_set(&let_env, b.clone(), r); + }, + _ => return err_str("let* with non-symbol binding"), + } + } + }, + _ => return err_str("let* with non-list bindings"), + } + 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; + }, + "defmacro!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + let r = try!(eval(a2, env.clone())); + match *r { + MalFunc(ref mfd,_) => { + match *a1 { + Sym(_) => { + let mut new_mfd = mfd.clone(); + new_mfd.is_macro = true; + let mf = malfuncd(new_mfd,_nil()); + env_set(&env.clone(), a1.clone(), mf.clone()); + return Ok(mf); + }, + _ => return err_str("def! of non-symbol"), + } + }, + _ => return err_str("def! of non-symbol"), + } + }, + "macroexpand" => { + let a1 = (*args)[1].clone(); + return macroexpand(a1, env.clone()) + }, + "try*" => { + let a1 = (*args)[1].clone(); + match eval(a1, env.clone()) { + Ok(res) => return Ok(res), + Err(err) => { + if args.len() < 3 { return Err(err); } + let a2 = (*args)[2].clone(); + let cat = match *a2 { + List(ref cat,_) => cat, + _ => return err_str("invalid catch* clause"), + }; + if cat.len() != 3 { + return err_str("wrong arity to catch* clause"); + } + let c1 = (*cat)[1].clone(); + match *c1 { + Sym(_) => {}, + _ => return err_str("invalid catch* binding"), + }; + let exc = match err { + ErrMalVal(mv) => mv, + ErrString(s) => string(s), + }; + let bind_env = env_new(Some(env.clone())); + env_set(&bind_env, c1.clone(), exc); + let c2 = (*cat)[2].clone(); + return eval(c2, bind_env); + }, + }; + } + "do" => { + let el = list(args[1..args.len()-1].to_vec()); + try!(eval_ast(el, env.clone())); + ast = args[args.len() - 1].clone(); + continue 'tco; + }, + "if" => { + let a1 = (*args)[1].clone(); + let c = try!(eval(a1, env.clone())); + match *c { + False | Nil => { + if args.len() >= 4 { + ast = args[3].clone(); + continue 'tco; + } else { + return Ok(_nil()); + } + }, + _ => { + ast = args[2].clone(); + continue 'tco; + }, + } + }, + "fn*" => { + let a1 = args[1].clone(); + let a2 = args[2].clone(); + return Ok(malfunc(eval, a2, env, a1, _nil())); + }, + "eval" => { + let a1 = (*args)[1].clone(); + ast = try!(eval(a1, env.clone())); + env = env_root(&env); + continue 'tco; + }, + _ => { // function call + let el = try!(eval_ast(tmp.clone(), env.clone())); + let args = match *el { + List(ref args,_) => args, + _ => return err_str("Invalid apply"), + }; + return match *args.clone()[0] { + Func(f,_) => f(args[1..].to_vec()), + MalFunc(ref mf,_) => { + let mfc = mf.clone(); + let alst = list(args[1..].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_str(&e), + } + }, + _ => err_str("attempt to call non-function"), + } + }, + } + + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: &str, env: Env) -> Result<String,MalError> { + let ast = try!(read(str.to_string())); + //println!("read: {}", ast); + let exp = try!(eval(ast, env)); + 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, symbol(&k), v); + } + // see eval() for definition of "eval" + env_set(&repl_env, symbol("*ARGV*"), list(vec![])); + + // core.mal: defined using the language itself + let _ = rep("(def! *host-language* \"rust\")", repl_env.clone()); + let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone()); + let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env.clone()); + let _ = rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", repl_env.clone()); + let _ = rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))", repl_env.clone()); + + // Invoked with command line arguments + let args = stdenv::args(); + if args.len() > 1 { + let mv_args = args.skip(2) + .map(|a| string(a)) + .collect::<Vec<MalVal>>(); + env_set(&repl_env, symbol("*ARGV*"), list(mv_args)); + let lf = format!("(load-file \"{}\")", + stdenv::args().skip(1).next().unwrap()); + return match rep(&lf, repl_env.clone()) { + Ok(_) => stdenv::set_exit_status(0), + Err(str) => { + println!("Error: {:?}", str); + stdenv::set_exit_status(1); + } + }; + } + + // repl loop + let _ = rep("(println (str \"Mal [\" *host-language* \"]\"))", repl_env.clone()); + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(&line.unwrap(), repl_env.clone()) { + Ok(str) => println!("{}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), + } + } +} |
