aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-03-05 00:22:43 -0800
committerAlex Crichton <alex@alexcrichton.com>2015-03-05 00:40:57 -0800
commitbbeb1b87c2b848189c0f71c93cf4b70b32d45a4d (patch)
tree257ac1a8a70f7f981be440c22763dd9ec7e1e562
parenta551bd4cd4d802173057ed124b911abed4ec530b (diff)
downloadmal-bbeb1b87c2b848189c0f71c93cf4b70b32d45a4d.tar.gz
mal-bbeb1b87c2b848189c0f71c93cf4b70b32d45a4d.zip
Update Rust code to the current Rust nightly
Lots of changes! Hopefully everything is still semantically equivalent (tests still pass)
-rw-r--r--README.md5
-rw-r--r--rust/Cargo.toml40
-rw-r--r--rust/Makefile4
-rw-r--r--rust/src/bin/step0_repl.rs (renamed from rust/src/step0_repl.rs)5
-rw-r--r--rust/src/bin/step1_read_print.rs (renamed from rust/src/step1_read_print.rs)15
-rw-r--r--rust/src/bin/step2_eval.rs (renamed from rust/src/step2_eval.rs)31
-rw-r--r--rust/src/bin/step3_env.rs (renamed from rust/src/step3_env.rs)35
-rw-r--r--rust/src/bin/step4_if_fn_do.rs (renamed from rust/src/step4_if_fn_do.rs)38
-rw-r--r--rust/src/bin/step5_tco.rs (renamed from rust/src/step5_tco.rs)43
-rw-r--r--rust/src/bin/step6_file.rs (renamed from rust/src/step6_file.rs)75
-rw-r--r--rust/src/bin/step7_quote.rs (renamed from rust/src/step7_quote.rs)80
-rw-r--r--rust/src/bin/step8_macros.rs (renamed from rust/src/step8_macros.rs)97
-rw-r--r--rust/src/bin/step9_try.rs (renamed from rust/src/step9_try.rs)87
-rw-r--r--rust/src/bin/stepA_mal.rs381
-rw-r--r--rust/src/core.rs285
-rw-r--r--rust/src/env.rs50
-rw-r--r--rust/src/lib.rs17
-rw-r--r--rust/src/printer.rs6
-rw-r--r--rust/src/reader.rs46
-rw-r--r--rust/src/readline.rs57
-rw-r--r--rust/src/stepA_mal.rs479
-rw-r--r--rust/src/types.rs96
22 files changed, 851 insertions, 1121 deletions
diff --git a/README.md b/README.md
index 0fce3a9..74c1d27 100644
--- a/README.md
+++ b/README.md
@@ -315,10 +315,7 @@ tool (cargo) to build.
```
cd rust
-# Need patched pcre lib (should be temporary)
-git clone https://github.com/kanaka/rust-pcre cadencemarseille-pcre
-cargo build --release
-./target/stepX_YYY
+cargo run --release --bin stepX_YYY
```
### Scala ###
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index daf999d..da6cdb7 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -1,39 +1,13 @@
[package]
-name = "Mal"
+name = "mal"
version = "0.0.1"
authors = [ "Your name <you@example.com>" ]
+[dependencies]
+time = "0.1"
+regex = "0.1"
+libc = "0.1"
-[dependencies.cadencemarseille-pcre]
-
-git = "https://github.com/kanaka/rust-pcre"
-
-
-#[profile.dev]
-#
-#debug = true
-
-
-[[bin]]
-name = "step0_repl"
-[[bin]]
-name = "step1_read_print"
-[[bin]]
-name = "step2_eval"
-[[bin]]
-name = "step3_env"
-[[bin]]
-name = "step4_if_fn_do"
-[[bin]]
-name = "step5_tco"
-[[bin]]
-name = "step6_file"
-[[bin]]
-name = "step7_quote"
-[[bin]]
-name = "step8_macros"
-[[bin]]
-name = "step9_try"
-[[bin]]
-name = "stepA_mal"
+[dependencies.pcre]
+git = "https://github.com/alexcrichton/rust-pcre"
diff --git a/rust/Makefile b/rust/Makefile
index fa1edc9..c71289d 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -3,7 +3,7 @@
SOURCES_BASE = src/types.rs src/readline.rs \
src/reader.rs src/printer.rs \
src/env.rs src/core.rs
-SOURCES_LISP = src/env.rs src/core.rs src/stepA_mal.rs
+SOURCES_LISP = src/env.rs src/core.rs src/bin/stepA_mal.rs
SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)
#####################
@@ -28,7 +28,7 @@ clean:
cargo clean
rm -f mal
-.PHONY: stats stats-lisp
+.PHONY: stats stats-lisp mal
stats: $(SOURCES)
@wc $^
diff --git a/rust/src/step0_repl.rs b/rust/src/bin/step0_repl.rs
index ac9cf24..030c551 100644
--- a/rust/src/step0_repl.rs
+++ b/rust/src/bin/step0_repl.rs
@@ -1,5 +1,6 @@
-use readline::mal_readline;
-mod readline;
+extern crate mal;
+
+use mal::readline::mal_readline;
// read
fn read(str: String) -> String {
diff --git a/rust/src/step1_read_print.rs b/rust/src/bin/step1_read_print.rs
index 3ce11e6..8be7e0d 100644
--- a/rust/src/step1_read_print.rs
+++ b/rust/src/bin/step1_read_print.rs
@@ -1,15 +1,8 @@
-// support precompiled regexes in reader.rs
-#![feature(phase)]
-#[phase(plugin)]
-extern crate regex_macros;
-extern crate regex;
+extern crate mal;
-use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal};
-mod readline;
-mod types;
-mod env;
-mod reader;
-mod printer;
+use mal::types::{MalVal, MalRet, MalError};
+use mal::types::MalError::{ErrString, ErrMalVal};
+use mal::{readline, reader};
// read
fn read(str: String) -> MalRet {
diff --git a/rust/src/step2_eval.rs b/rust/src/bin/step2_eval.rs
index 2cf7897..3efa51e 100644
--- a/rust/src/step2_eval.rs
+++ b/rust/src/bin/step2_eval.rs
@@ -1,19 +1,12 @@
-// support precompiled regexes in reader.rs
-#![feature(phase)]
-#[phase(plugin)]
-extern crate regex_macros;
-extern crate regex;
+extern crate mal;
use std::collections::HashMap;
-use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str,
- Int,Sym,List,Vector,Hash_Map,
- _nil,_int,list,vector,hash_map,func};
-mod readline;
-mod types;
-mod reader;
-mod printer;
-mod env; // because types uses env
+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 {
@@ -24,8 +17,8 @@ fn read(str: String) -> MalRet {
fn eval_ast(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet {
match *ast {
Sym(ref sym) => {
- match env.find_copy(sym) {
- Some(mv) => Ok(mv),
+ match env.get(sym) {
+ Some(mv) => Ok(mv.clone()),
None => Ok(_nil()),
}
},
@@ -70,7 +63,7 @@ fn eval(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet {
match *el {
List(ref args,_) => {
let ref f = args.clone()[0];
- f.apply(args.slice(1,args.len()).to_vec())
+ f.apply(args[1..].to_vec())
}
_ => err_str("Invalid apply"),
}
@@ -96,7 +89,9 @@ fn rep(str: &str, env: &HashMap<String,MalVal>) -> Result<String,MalError> {
}
}
-fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet {
+fn int_op<F>(f: F, a:Vec<MalVal>) -> MalRet
+ where F: FnOnce(isize, isize) -> isize
+{
match *a[0] {
Int(a0) => match *a[1] {
Int(a1) => Ok(_int(f(a0,a1))),
@@ -120,7 +115,7 @@ fn main() {
loop {
let line = readline::mal_readline("user> ");
match line { None => break, _ => () }
- match rep(line.unwrap().as_slice(), &repl_env) {
+ 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/step3_env.rs b/rust/src/bin/step3_env.rs
index b2d49cd..0e75b26 100644
--- a/rust/src/step3_env.rs
+++ b/rust/src/bin/step3_env.rs
@@ -1,20 +1,13 @@
-// support precompiled regexes in reader.rs
-#![feature(phase)]
-#[phase(plugin)]
-extern crate regex_macros;
-extern crate regex;
+extern crate mal;
use std::collections::HashMap;
-use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str,
- Int,Sym,List,Vector,Hash_Map,
- symbol,_int,list,vector,hash_map,func};
-use env::{Env,env_new,env_set,env_get};
-mod readline;
-mod types;
-mod reader;
-mod printer;
-mod env;
+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 {
@@ -27,7 +20,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet {
match *ast2 {
//match *ast {
Sym(_) => {
- env_get(env.clone(), ast)
+ env_get(&env, &ast)
},
List(ref a,_) | Vector(ref a,_) => {
let mut ast_vec : Vec<MalVal> = vec![];
@@ -74,12 +67,12 @@ fn eval(ast: MalVal, env: Env) -> MalRet {
let (args, a0sym) = match *ast2 {
List(ref args,_) => {
- if args.len() == 0 {
+ if args.len() == 0 {
return Ok(ast);
}
let ref a0 = *args[0];
match *a0 {
- Sym(ref a0sym) => (args, a0sym.as_slice()),
+ Sym(ref a0sym) => (args, &a0sym[..]),
_ => (args, "__<fn*>__"),
}
},
@@ -146,7 +139,7 @@ fn eval(ast: MalVal, env: Env) -> MalRet {
_ => return err_str("Invalid apply"),
};
let ref f = args.clone()[0];
- f.apply(args.slice(1,args.len()).to_vec())
+ f.apply(args[1..].to_vec())
}
};
},
@@ -171,7 +164,9 @@ fn rep(str: &str, env: Env) -> Result<String,MalError> {
}
}
-fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet {
+fn int_op<F>(f: F, a:Vec<MalVal>) -> MalRet
+ where F: FnOnce(isize, isize) -> isize
+{
match *a[0] {
Int(a0) => match *a[1] {
Int(a1) => Ok(_int(f(a0,a1))),
@@ -195,7 +190,7 @@ fn main() {
loop {
let line = readline::mal_readline("user> ");
match line { None => break, _ => () }
- match rep(line.unwrap().as_slice(), repl_env.clone()) {
+ 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/step4_if_fn_do.rs b/rust/src/bin/step4_if_fn_do.rs
index 92abf92..afbf69a 100644
--- a/rust/src/step4_if_fn_do.rs
+++ b/rust/src/bin/step4_if_fn_do.rs
@@ -1,21 +1,13 @@
-// support precompiled regexes in reader.rs
-#![feature(phase)]
-#[phase(plugin)]
-extern crate regex_macros;
-extern crate regex;
+extern crate mal;
use std::collections::HashMap;
-use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str,
- Nil,False,Sym,List,Vector,Hash_Map,
- symbol,_nil,list,vector,hash_map,malfunc};
-use env::{Env,env_new,env_set,env_get};
-mod readline;
-mod types;
-mod reader;
-mod printer;
-mod env;
-mod core;
+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 {
@@ -27,9 +19,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet {
let ast2 = ast.clone();
match *ast2 {
//match *ast {
- Sym(_) => {
- env_get(env.clone(), ast)
- },
+ Sym(_) => env_get(&env, &ast),
List(ref a,_) | Vector(ref a,_) => {
let mut ast_vec : Vec<MalVal> = vec![];
for mv in a.iter() {
@@ -75,12 +65,12 @@ fn eval(ast: MalVal, env: Env) -> MalRet {
let (args, a0sym) = match *ast2 {
List(ref args,_) => {
- if args.len() == 0 {
+ if args.len() == 0 {
return Ok(ast);
}
let ref a0 = *args[0];
match *a0 {
- Sym(ref a0sym) => (args, a0sym.as_slice()),
+ Sym(ref a0sym) => (args, &a0sym[..]),
_ => (args, "__<fn*>__"),
}
},
@@ -139,7 +129,7 @@ fn eval(ast: MalVal, env: Env) -> MalRet {
return eval(a2, let_env.clone());
},
"do" => {
- let el = list(args.slice(1,args.len()).to_vec());
+ let el = list(args[1..].to_vec());
return match eval_ast(el, env.clone()) {
Err(e) => return Err(e),
Ok(el) => {
@@ -188,7 +178,7 @@ fn eval(ast: MalVal, env: Env) -> MalRet {
_ => return err_str("Invalid apply"),
};
let ref f = args.clone()[0];
- f.apply(args.slice(1,args.len()).to_vec())
+ f.apply(args[1..].to_vec())
}
};
},
@@ -217,7 +207,7 @@ 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.as_slice()), v);
+ env_set(&repl_env, symbol(&k), v);
}
// core.mal: defined using the language itself
@@ -226,7 +216,7 @@ fn main() {
loop {
let line = readline::mal_readline("user> ");
match line { None => break, _ => () }
- match rep(line.unwrap().as_slice(), repl_env.clone()) {
+ 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/step5_tco.rs b/rust/src/bin/step5_tco.rs
index 9223cbf..4117634 100644
--- a/rust/src/step5_tco.rs
+++ b/rust/src/bin/step5_tco.rs
@@ -1,21 +1,14 @@
-// support precompiled regexes in reader.rs
-#![feature(phase)]
-#[phase(plugin)]
-extern crate regex_macros;
-extern crate regex;
+extern crate mal;
use std::collections::HashMap;
-use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str,
- Nil,False,Sym,List,Vector,Hash_Map,Func,MalFunc,
- symbol,_nil,list,vector,hash_map,malfunc};
-use env::{Env,env_new,env_bind,env_set,env_get};
-mod readline;
-mod types;
-mod reader;
-mod printer;
-mod env;
-mod core;
+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 {
@@ -27,9 +20,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet {
let ast2 = ast.clone();
match *ast2 {
//match *ast {
- Sym(_) => {
- env_get(env.clone(), ast)
- },
+ Sym(_) => env_get(&env, &ast),
List(ref a,_) | Vector(ref a,_) => {
let mut ast_vec : Vec<MalVal> = vec![];
for mv in a.iter() {
@@ -78,12 +69,12 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
let (args, a0sym) = match *ast2 {
List(ref args,_) => {
- if args.len() == 0 {
+ if args.len() == 0 {
return Ok(ast3);
}
let ref a0 = *args[0];
match *a0 {
- Sym(ref a0sym) => (args, a0sym.as_slice()),
+ Sym(ref a0sym) => (args, &a0sym[..]),
_ => (args, "__<fn*>__"),
}
},
@@ -144,7 +135,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
continue 'tco;
},
"do" => {
- let el = list(args.slice(1,args.len()-1).to_vec());
+ let el = list(args[1..args.len()-1].to_vec());
match eval_ast(el, env.clone()) {
Err(e) => return Err(e),
Ok(_) => {
@@ -193,10 +184,10 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
_ => return err_str("Invalid apply"),
};
match *args.clone()[0] {
- Func(f,_) => f(args.slice(1,args.len()).to_vec()),
+ Func(f,_) => f(args[1..].to_vec()),
MalFunc(ref mf,_) => {
let mfc = mf.clone();
- let alst = list(args.slice(1,args.len()).to_vec());
+ 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(_) => {
@@ -204,7 +195,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
env = new_env;
continue 'tco;
},
- Err(e) => err_str(e.as_slice()),
+ Err(e) => err_str(&e),
}
},
_ => err_str("attempt to call non-function"),
@@ -239,7 +230,7 @@ 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.as_slice()), v);
+ env_set(&repl_env, symbol(&k), v);
}
// core.mal: defined using the language itself
@@ -248,7 +239,7 @@ fn main() {
loop {
let line = readline::mal_readline("user> ");
match line { None => break, _ => () }
- match rep(line.unwrap().as_slice(), repl_env.clone()) {
+ 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/step6_file.rs b/rust/src/bin/step6_file.rs
index 1e87116..8d9a26c 100644
--- a/rust/src/step6_file.rs
+++ b/rust/src/bin/step6_file.rs
@@ -1,22 +1,16 @@
-// support precompiled regexes in reader.rs
-#![feature(phase)]
-#[phase(plugin)]
-extern crate regex_macros;
-extern crate regex;
+#![feature(exit_status)]
+
+extern crate mal;
use std::collections::HashMap;
-use std::os;
+use std::env as stdenv;
-use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str,
- Nil,False,Sym,List,Vector,Hash_Map,Func,MalFunc,
- symbol,_nil,string,list,vector,hash_map,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;
+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 {
@@ -28,9 +22,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet {
let ast2 = ast.clone();
match *ast2 {
//match *ast {
- Sym(_) => {
- env_get(env.clone(), ast)
- },
+ Sym(_) => env_get(&env, &ast),
List(ref a,_) | Vector(ref a,_) => {
let mut ast_vec : Vec<MalVal> = vec![];
for mv in a.iter() {
@@ -79,12 +71,12 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
let (args, a0sym) = match *ast2 {
List(ref args,_) => {
- if args.len() == 0 {
+ if args.len() == 0 {
return Ok(ast3);
}
let ref a0 = *args[0];
match *a0 {
- Sym(ref a0sym) => (args, a0sym.as_slice()),
+ Sym(ref a0sym) => (args, &a0sym[..]),
_ => (args, "__<fn*>__"),
}
},
@@ -145,7 +137,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
continue 'tco;
},
"do" => {
- let el = list(args.slice(1,args.len()-1).to_vec());
+ let el = list(args[1..args.len()-1].to_vec());
match eval_ast(el, env.clone()) {
Err(e) => return Err(e),
Ok(_) => {
@@ -205,10 +197,10 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
_ => return err_str("Invalid apply"),
};
match *args.clone()[0] {
- Func(f,_) => f(args.slice(1,args.len()).to_vec()),
+ Func(f,_) => f(args[1..].to_vec()),
MalFunc(ref mf,_) => {
let mfc = mf.clone();
- let alst = list(args.slice(1,args.len()).to_vec());
+ 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(_) => {
@@ -216,7 +208,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
env = new_env;
continue 'tco;
},
- Err(e) => err_str(e.as_slice()),
+ Err(e) => err_str(&e),
}
},
_ => err_str("attempt to call non-function"),
@@ -251,40 +243,37 @@ 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.as_slice()), v);
+ env_set(&repl_env, symbol(&k), v);
}
// see eval() for definition of "eval"
- env_set(&repl_env, symbol("*ARGV*".as_slice()), list(vec![]));
+ 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 = os::args();
+ let args = stdenv::args();
if args.len() > 1 {
- let mv_args = args.slice(2,args.len()).iter()
- .map(|a| string(a.to_string()))
+ let mv_args = args.skip(2)
+ .map(|a| string(a))
.collect::<Vec<MalVal>>();
- env_set(&repl_env, symbol("*ARGV*".as_slice()), list(mv_args));
- let lf = "(load-file \"".to_string() + args[1] + "\")".to_string();
- match rep(lf.as_slice(), repl_env.clone()) {
- Ok(_) => {
- os::set_exit_status(0);
- return;
- },
+ 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);
- os::set_exit_status(1);
- return;
- },
- }
+ println!("Error: {:?}", str);
+ stdenv::set_exit_status(1);
+ }
+ };
}
loop {
let line = readline::mal_readline("user> ");
match line { None => break, _ => () }
- match rep(line.unwrap().as_slice(), repl_env.clone()) {
+ 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/step7_quote.rs b/rust/src/bin/step7_quote.rs
index b113920..77d5d33 100644
--- a/rust/src/step7_quote.rs
+++ b/rust/src/bin/step7_quote.rs
@@ -1,22 +1,17 @@
-// support precompiled regexes in reader.rs
-#![feature(phase)]
-#[phase(plugin)]
-extern crate regex_macros;
-extern crate regex;
+#![feature(exit_status)]
+
+extern crate mal;
use std::collections::HashMap;
-use std::os;
+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};
-use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str,
- Nil,False,Sym,List,Vector,Hash_Map,Func,MalFunc,
- symbol,_nil,string,list,vector,hash_map,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 {
@@ -57,7 +52,7 @@ fn quasiquote(ast: MalVal) -> MalVal {
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()))])
+ quasiquote(list(args[1..].to_vec()))])
}
},
_ => (),
@@ -66,7 +61,7 @@ fn quasiquote(ast: MalVal) -> MalVal {
_ => (),
}
}
- let rest = list(args.slice(1,args.len()).to_vec());
+ let rest = list(args[1..].to_vec());
return list(vec![symbol("cons"),
quasiquote(a0.clone()),
quasiquote(rest)])
@@ -79,9 +74,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet {
let ast2 = ast.clone();
match *ast2 {
//match *ast {
- Sym(_) => {
- env_get(env.clone(), ast)
- },
+ Sym(_) => env_get(&env, &ast),
List(ref a,_) | Vector(ref a,_) => {
let mut ast_vec : Vec<MalVal> = vec![];
for mv in a.iter() {
@@ -130,12 +123,12 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
let (args, a0sym) = match *ast2 {
List(ref args,_) => {
- if args.len() == 0 {
+ if args.len() == 0 {
return Ok(ast3);
}
let ref a0 = *args[0];
match *a0 {
- Sym(ref a0sym) => (args, a0sym.as_slice()),
+ Sym(ref a0sym) => (args, &a0sym[..]),
_ => (args, "__<fn*>__"),
}
},
@@ -204,7 +197,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
continue 'tco;
},
"do" => {
- let el = list(args.slice(1,args.len()-1).to_vec());
+ let el = list(args[1..args.len()-1].to_vec());
match eval_ast(el, env.clone()) {
Err(e) => return Err(e),
Ok(_) => {
@@ -264,10 +257,10 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
_ => return err_str("Invalid apply"),
};
match *args.clone()[0] {
- Func(f,_) => f(args.slice(1,args.len()).to_vec()),
+ Func(f,_) => f(args[1..].to_vec()),
MalFunc(ref mf,_) => {
let mfc = mf.clone();
- let alst = list(args.slice(1,args.len()).to_vec());
+ 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(_) => {
@@ -275,7 +268,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
env = new_env;
continue 'tco;
},
- Err(e) => err_str(e.as_slice()),
+ Err(e) => err_str(&e),
}
},
_ => err_str("attempt to call non-function"),
@@ -310,40 +303,37 @@ 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.as_slice()), v);
+ env_set(&repl_env, symbol(&k), v);
}
// see eval() for definition of "eval"
- env_set(&repl_env, symbol("*ARGV*".as_slice()), list(vec![]));
+ 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 = os::args();
+ let args = stdenv::args();
if args.len() > 1 {
- let mv_args = args.slice(2,args.len()).iter()
- .map(|a| string(a.to_string()))
+ let mv_args = args.skip(2)
+ .map(|a| string(a))
.collect::<Vec<MalVal>>();
- env_set(&repl_env, symbol("*ARGV*".as_slice()), list(mv_args));
- let lf = "(load-file \"".to_string() + args[1] + "\")".to_string();
- match rep(lf.as_slice(), repl_env.clone()) {
- Ok(_) => {
- os::set_exit_status(0);
- return;
- },
+ 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);
- os::set_exit_status(1);
- return;
- },
- }
+ println!("Error: {:?}", str);
+ stdenv::set_exit_status(1);
+ }
+ };
}
loop {
let line = readline::mal_readline("user> ");
match line { None => break, _ => () }
- match rep(line.unwrap().as_slice(), repl_env.clone()) {
+ 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/step8_macros.rs b/rust/src/bin/step8_macros.rs
index 7450de8..a808926 100644
--- a/rust/src/step8_macros.rs
+++ b/rust/src/bin/step8_macros.rs
@@ -1,22 +1,16 @@
-// support precompiled regexes in reader.rs
-#![feature(phase)]
-#[phase(plugin)]
-extern crate regex_macros;
-extern crate regex;
+#![feature(exit_status)]
+
+extern crate mal;
use std::collections::HashMap;
-use std::os;
+use std::env as stdenv;
-use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str,
- Nil,False,Sym,List,Vector,Hash_Map,Func,MalFunc,
- symbol,_nil,string,list,vector,hash_map,malfunc,malfuncd};
-use env::{Env,env_new,env_bind,env_root,env_find,env_set,env_get};
-mod readline;
-mod types;
-mod reader;
-mod printer;
-mod env;
-mod core;
+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 {
@@ -57,7 +51,7 @@ fn quasiquote(ast: MalVal) -> MalVal {
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()))])
+ quasiquote(list(args[1..].to_vec()))])
}
},
_ => (),
@@ -66,7 +60,7 @@ fn quasiquote(ast: MalVal) -> MalVal {
_ => (),
}
}
- let rest = list(args.slice(1,args.len()).to_vec());
+ let rest = list(args[1..].to_vec());
return list(vec![symbol("cons"),
quasiquote(a0.clone()),
quasiquote(rest)])
@@ -80,8 +74,8 @@ fn is_macro_call(ast: MalVal, env: Env) -> bool {
List(ref lst,_) => {
match *lst[0] {
Sym(_) => {
- if env_find(env.clone(), lst[0].clone()).is_some() {
- match env_get(env, lst[0].clone()) {
+ if env_find(&env, &lst[0]).is_some() {
+ match env_get(&env, &lst[0]) {
Ok(f) => {
match *f {
MalFunc(ref mfd,_) => {
@@ -112,21 +106,11 @@ fn macroexpand(mut ast: MalVal, env: Env) -> MalRet {
};
let ref a0 = args[0];
let mf = match **a0 {
- Sym(_) => {
- match env_get(env.clone(), a0.clone()) {
- Ok(mf) => mf,
- Err(e) => return Err(e),
- }
- },
+ Sym(_) => try!(env_get(&env, &a0)),
_ => break,
};
match *mf {
- MalFunc(_,_) => {
- match mf.apply(args.slice(1,args.len()).to_vec()) {
- Ok(r) => ast = r,
- Err(e) => return Err(e),
- }
- },
+ MalFunc(_,_) => ast = try!(mf.apply(args[1..].to_vec())),
_ => break,
}
}
@@ -137,9 +121,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet {
let ast2 = ast.clone();
match *ast2 {
//match *ast {
- Sym(_) => {
- env_get(env.clone(), ast)
- },
+ Sym(_) => env_get(&env, &ast),
List(ref a,_) | Vector(ref a,_) => {
let mut ast_vec : Vec<MalVal> = vec![];
for mv in a.iter() {
@@ -194,12 +176,12 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
let (args, a0sym) = match *ast2 {
List(ref args,_) => {
- if args.len() == 0 {
+ if args.len() == 0 {
return Ok(ast3);
}
let ref a0 = *args[0];
match *a0 {
- Sym(ref a0sym) => (args, a0sym.as_slice()),
+ Sym(ref a0sym) => (args, &a0sym[..]),
_ => (args, "__<fn*>__"),
}
},
@@ -296,7 +278,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
return macroexpand(a1, env.clone())
},
"do" => {
- let el = list(args.slice(1,args.len()-1).to_vec());
+ let el = list(args[1..args.len()-1].to_vec());
match eval_ast(el, env.clone()) {
Err(e) => return Err(e),
Ok(_) => {
@@ -356,10 +338,10 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
_ => return err_str("Invalid apply"),
};
match *args.clone()[0] {
- Func(f,_) => f(args.slice(1,args.len()).to_vec()),
+ Func(f,_) => f(args[1..].to_vec()),
MalFunc(ref mf,_) => {
let mfc = mf.clone();
- let alst = list(args.slice(1,args.len()).to_vec());
+ 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(_) => {
@@ -367,7 +349,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
env = new_env;
continue 'tco;
},
- Err(e) => err_str(e.as_slice()),
+ Err(e) => err_str(&e),
}
},
_ => err_str("attempt to call non-function"),
@@ -402,10 +384,10 @@ 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.as_slice()), v);
+ env_set(&repl_env, symbol(&k), v);
}
// see eval() for definition of "eval"
- env_set(&repl_env, symbol("*ARGV*".as_slice()), list(vec![]));
+ 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());
@@ -414,31 +396,28 @@ fn main() {
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 = os::args();
+ let args = stdenv::args();
if args.len() > 1 {
- let mv_args = args.slice(2,args.len()).iter()
- .map(|a| string(a.to_string()))
+ let mv_args = args.skip(2)
+ .map(|a| string(a))
.collect::<Vec<MalVal>>();
- env_set(&repl_env, symbol("*ARGV*".as_slice()), list(mv_args));
- let lf = "(load-file \"".to_string() + args[1] + "\")".to_string();
- match rep(lf.as_slice(), repl_env.clone()) {
- Ok(_) => {
- os::set_exit_status(0);
- return;
- },
+ 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);
- os::set_exit_status(1);
- return;
- },
- }
+ 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().as_slice(), repl_env.clone()) {
+ 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/step9_try.rs b/rust/src/bin/step9_try.rs
index 0f6bd88..f6c5dbf 100644
--- a/rust/src/step9_try.rs
+++ b/rust/src/bin/step9_try.rs
@@ -1,22 +1,16 @@
-// support precompiled regexes in reader.rs
-#![feature(phase)]
-#[phase(plugin)]
-extern crate regex_macros;
-extern crate regex;
+#![feature(exit_status)]
+
+extern crate mal;
use std::collections::HashMap;
-use std::os;
+use std::env as stdenv;
-use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str,
- Nil,False,Sym,List,Vector,Hash_Map,Func,MalFunc,
- symbol,_nil,string,list,vector,hash_map,malfunc,malfuncd};
-use env::{Env,env_new,env_bind,env_root,env_find,env_set,env_get};
-mod readline;
-mod types;
-mod reader;
-mod printer;
-mod env;
-mod core;
+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 {
@@ -26,7 +20,7 @@ fn read(str: String) -> MalRet {
// eval
fn is_pair(x: MalVal) -> bool {
match *x {
- List(ref lst,_) | Vector(ref lst,_) => lst.len() > 0,
+ List(ref lst, _) | Vector(ref lst, _) => lst.len() > 0,
_ => false,
}
}
@@ -57,7 +51,7 @@ fn quasiquote(ast: MalVal) -> MalVal {
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()))])
+ quasiquote(list(args[1..].to_vec()))])
}
},
_ => (),
@@ -66,7 +60,7 @@ fn quasiquote(ast: MalVal) -> MalVal {
_ => (),
}
}
- let rest = list(args.slice(1,args.len()).to_vec());
+ let rest = list(args[1..].to_vec());
return list(vec![symbol("cons"),
quasiquote(a0.clone()),
quasiquote(rest)])
@@ -80,8 +74,8 @@ fn is_macro_call(ast: MalVal, env: Env) -> bool {
List(ref lst,_) => {
match *lst[0] {
Sym(_) => {
- if env_find(env.clone(), lst[0].clone()).is_some() {
- match env_get(env, lst[0].clone()) {
+ if env_find(&env, &lst[0]).is_some() {
+ match env_get(&env, &lst[0]) {
Ok(f) => {
match *f {
MalFunc(ref mfd,_) => {
@@ -113,7 +107,7 @@ fn macroexpand(mut ast: MalVal, env: Env) -> MalRet {
let ref a0 = args[0];
let mf = match **a0 {
Sym(_) => {
- match env_get(env.clone(), a0.clone()) {
+ match env_get(&env, &a0) {
Ok(mf) => mf,
Err(e) => return Err(e),
}
@@ -122,7 +116,7 @@ fn macroexpand(mut ast: MalVal, env: Env) -> MalRet {
};
match *mf {
MalFunc(_,_) => {
- match mf.apply(args.slice(1,args.len()).to_vec()) {
+ match mf.apply(args[1..].to_vec()) {
Ok(r) => ast = r,
Err(e) => return Err(e),
}
@@ -138,7 +132,7 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet {
match *ast2 {
//match *ast {
Sym(_) => {
- env_get(env.clone(), ast)
+ env_get(&env, &ast)
},
List(ref a,_) | Vector(ref a,_) => {
let mut ast_vec : Vec<MalVal> = vec![];
@@ -194,12 +188,12 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
let (args, a0sym) = match *ast2 {
List(ref args,_) => {
- if args.len() == 0 {
+ if args.len() == 0 {
return Ok(ast3);
}
let ref a0 = *args[0];
match *a0 {
- Sym(ref a0sym) => (args, a0sym.as_slice()),
+ Sym(ref a0sym) => (args, &a0sym[..]),
_ => (args, "__<fn*>__"),
}
},
@@ -326,7 +320,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
};
}
"do" => {
- let el = list(args.slice(1,args.len()-1).to_vec());
+ let el = list(args[1..args.len()-1].to_vec());
match eval_ast(el, env.clone()) {
Err(e) => return Err(e),
Ok(_) => {
@@ -386,10 +380,10 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
_ => return err_str("Invalid apply"),
};
match *args.clone()[0] {
- Func(f,_) => f(args.slice(1,args.len()).to_vec()),
+ Func(f,_) => f(args[1..].to_vec()),
MalFunc(ref mf,_) => {
let mfc = mf.clone();
- let alst = list(args.slice(1,args.len()).to_vec());
+ 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(_) => {
@@ -397,7 +391,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
env = new_env;
continue 'tco;
},
- Err(e) => err_str(e.as_slice()),
+ Err(e) => err_str(&e),
}
},
_ => err_str("attempt to call non-function"),
@@ -432,10 +426,10 @@ 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.as_slice()), v);
+ env_set(&repl_env, symbol(&k), v);
}
// see eval() for definition of "eval"
- env_set(&repl_env, symbol("*ARGV*".as_slice()), list(vec![]));
+ 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());
@@ -444,31 +438,28 @@ fn main() {
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 = os::args();
+ let args = stdenv::args();
if args.len() > 1 {
- let mv_args = args.slice(2,args.len()).iter()
- .map(|a| string(a.to_string()))
+ let mv_args = args.skip(2)
+ .map(|a| string(a))
.collect::<Vec<MalVal>>();
- env_set(&repl_env, symbol("*ARGV*".as_slice()), list(mv_args));
- let lf = "(load-file \"".to_string() + args[1] + "\")".to_string();
- match rep(lf.as_slice(), repl_env.clone()) {
- Ok(_) => {
- os::set_exit_status(0);
- return;
- },
+ 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);
- os::set_exit_status(1);
- return;
- },
- }
+ 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().as_slice(), repl_env.clone()) {
+ 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..e38b16f
--- /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 == "split-unqoute" => {
+ 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),
+ }
+ }
+}
diff --git a/rust/src/core.rs b/rust/src/core.rs
index 2bc3c39..f7257f3 100644
--- a/rust/src/core.rs
+++ b/rust/src/core.rs
@@ -1,31 +1,30 @@
#![allow(dead_code)]
-extern crate time;
use std::collections::HashMap;
-use std::io::File;
+use std::fs::File;
+use std::io::prelude::*;
+use std::num::ToPrimitive;
+use time;
use types::{MalVal,MalRet,err_val,err_str,err_string,
- Nil,Int,Strn,List,Vector,Hash_Map,Func,MalFunc,Atom,
_nil,_true,_false,_int,string,
list,vector,listm,vectorm,hash_mapm,func,funcm,malfuncd};
+use types::MalType::{Nil, Int, Strn, List, Vector, Hash_Map, Func, MalFunc, Atom};
use types;
use readline;
use reader;
use printer;
// General functions
-fn equal_q(a:Vec<MalVal>) -> MalRet {
+fn equal_q(a: Vec<MalVal>) -> MalRet {
if a.len() != 2 {
return err_str("Wrong arity to equal? call");
}
- match a[0] == a[1] {
- true => Ok(_true()),
- false => Ok(_false()),
- }
+ if a[0] == a[1] {Ok(_true())} else {Ok(_false())}
}
// Errors/Exceptions
-fn throw(a:Vec<MalVal>) -> MalRet {
+fn throw(a: Vec<MalVal>) -> MalRet {
if a.len() != 1 {
return err_str("Wrong arity to throw call");
}
@@ -33,27 +32,27 @@ fn throw(a:Vec<MalVal>) -> MalRet {
}
// String routines
-fn pr_str(a:Vec<MalVal>) -> MalRet {
+fn pr_str(a: Vec<MalVal>) -> MalRet {
Ok(string(printer::pr_list(&a, true, "", "", " ")))
}
-fn str(a:Vec<MalVal>) -> MalRet {
+fn str(a: Vec<MalVal>) -> MalRet {
Ok(string(printer::pr_list(&a, false, "", "", "")))
}
-fn prn(a:Vec<MalVal>) -> MalRet {
- println!("{}", printer::pr_list(&a, true, "", "", " "))
+fn prn(a: Vec<MalVal>) -> MalRet {
+ println!("{}", printer::pr_list(&a, true, "", "", " "));
Ok(_nil())
}
-fn println(a:Vec<MalVal>) -> MalRet {
- println!("{}", printer::pr_list(&a, false, "", "", " "))
+fn println(a: Vec<MalVal>) -> MalRet {
+ println!("{}", printer::pr_list(&a, false, "", "", " "));
Ok(_nil())
}
-fn readline(a:Vec<MalVal>) -> MalRet {
+fn readline(a: Vec<MalVal>) -> MalRet {
match *a[0] {
- Strn(ref a0) => match readline::mal_readline(a0.as_slice()) {
+ Strn(ref a0) => match readline::mal_readline(&a0) {
Some(line) => Ok(string(line)),
None => err_val(_nil()),
},
@@ -61,18 +60,19 @@ fn readline(a:Vec<MalVal>) -> MalRet {
}
}
-fn read_string(a:Vec<MalVal>) -> MalRet {
+fn read_string(a: Vec<MalVal>) -> MalRet {
match *a[0] {
Strn(ref a0) => reader::read_str(a0.to_string()),
_ => err_str("read_string called with non-string"),
}
}
-fn slurp(a:Vec<MalVal>) -> MalRet {
+fn slurp(a: Vec<MalVal>) -> MalRet {
match *a[0] {
Strn(ref a0) => {
- match File::open(&Path::new(a0.as_slice())).read_to_string() {
- Ok(s) => Ok(string(s)),
+ let mut s = String::new();
+ match File::open(a0).and_then(|mut f| f.read_to_string(&mut s)) {
+ Ok(_) => Ok(string(s)),
Err(e) => err_string(e.to_string()),
}
},
@@ -82,7 +82,9 @@ fn slurp(a:Vec<MalVal>) -> MalRet {
// Numeric functions
-fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet {
+fn int_op<F>(f: F, a: Vec<MalVal>) -> MalRet
+ where F: FnOnce(isize, isize) -> isize
+{
match *a[0] {
Int(a0) => match *a[1] {
Int(a1) => Ok(_int(f(a0,a1))),
@@ -92,13 +94,15 @@ fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet {
}
}
-fn bool_op(f: |i:int,j:int|-> bool, a:Vec<MalVal>) -> MalRet {
+fn bool_op<F>(f: F, a: Vec<MalVal>) -> MalRet
+ where F: FnOnce(isize, isize) -> bool
+{
match *a[0] {
Int(a0) => match *a[1] {
Int(a1) => {
match f(a0,a1) {
true => Ok(_true()),
- false => Ok(_false()),
+ false => Ok(_false()),
}
},
_ => err_str("second arg must be an int"),
@@ -107,83 +111,73 @@ fn bool_op(f: |i:int,j:int|-> bool, a:Vec<MalVal>) -> MalRet {
}
}
-pub fn add(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i+j }, a) }
-pub fn sub(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i-j }, a) }
-pub fn mul(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i*j }, a) }
-pub fn div(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i/j }, a) }
+pub fn add(a: Vec<MalVal>) -> MalRet { int_op(|i,j| { i+j }, a) }
+pub fn sub(a: Vec<MalVal>) -> MalRet { int_op(|i,j| { i-j }, a) }
+pub fn mul(a: Vec<MalVal>) -> MalRet { int_op(|i,j| { i*j }, a) }
+pub fn div(a: Vec<MalVal>) -> MalRet { int_op(|i,j| { i/j }, a) }
-pub fn lt (a:Vec<MalVal>) -> MalRet { bool_op(|i,j| { i<j }, a) }
-pub fn lte(a:Vec<MalVal>) -> MalRet { bool_op(|i,j| { i<=j }, a) }
-pub fn gt (a:Vec<MalVal>) -> MalRet { bool_op(|i,j| { i>j }, a) }
-pub fn gte(a:Vec<MalVal>) -> MalRet { bool_op(|i,j| { i>=j }, a) }
+pub fn lt (a: Vec<MalVal>) -> MalRet { bool_op(|i,j| { i<j }, a) }
+pub fn lte(a: Vec<MalVal>) -> MalRet { bool_op(|i,j| { i<=j }, a) }
+pub fn gt (a: Vec<MalVal>) -> MalRet { bool_op(|i,j| { i>j }, a) }
+pub fn gte(a: Vec<MalVal>) -> MalRet { bool_op(|i,j| { i>=j }, a) }
-#[allow(unused_variable)]
-pub fn time_ms(a:Vec<MalVal>) -> MalRet {
+pub fn time_ms(_a: Vec<MalVal>) -> MalRet {
//let x = time::now();
let now = time::get_time();
- let now_ms = (now.sec * 1000).to_int().unwrap() + (now.nsec.to_int().unwrap() / 1000000);
+ let now_ms = (now.sec * 1000).to_isize().unwrap() +
+ (now.nsec.to_isize().unwrap() / 1000000);
Ok(_int(now_ms))
}
// Hash Map functions
-pub fn assoc(a:Vec<MalVal>) -> MalRet {
+pub fn assoc(a: Vec<MalVal>) -> MalRet {
if a.len() < 3 {
return err_str("Wrong arity to assoc call");
}
match *a[0] {
- Hash_Map(ref hm,_) => {
- types::_assoc(hm, a.slice(1,a.len()).to_vec())
- },
- Nil => {
- types::hash_mapv(a.slice(1,a.len()).to_vec())
- }
- _ => return err_str("assoc onto non-hash map"),
+ Hash_Map(ref hm,_) => types::_assoc(hm, a[1..].to_vec()),
+ Nil => types::hash_mapv(a[1..].to_vec()),
+ _ => err_str("assoc onto non-hash map"),
}
}
-pub fn dissoc(a:Vec<MalVal>) -> MalRet {
+pub fn dissoc(a: Vec<MalVal>) -> MalRet {
if a.len() < 2 {
return err_str("Wrong arity to dissoc call");
}
match *a[0] {
- Hash_Map(ref hm,_) => {
- types::_dissoc(hm, a.slice(1,a.len()).to_vec())
- },
- Nil => {
- Ok(_nil())
- }
- _ => return err_str("dissoc onto non-hash map"),
+ Hash_Map(ref hm,_) => types::_dissoc(hm, a[1..].to_vec()),
+ Nil => Ok(_nil()),
+ _ => err_str("dissoc onto non-hash map"),
}
}
-pub fn get(a:Vec<MalVal>) -> MalRet {
+pub fn get(a: Vec<MalVal>) -> MalRet {
if a.len() != 2 {
return err_str("Wrong arity to get call");
}
- let a0 = a[0].clone();
- let hm: &HashMap<String,MalVal> = match *a0 {
+ let hm = match *a[0] {
Hash_Map(ref hm,_) => hm,
Nil => return Ok(_nil()),
_ => return err_str("get on non-hash map"),
};
match *a[1] {
Strn(ref key) => {
- match hm.find_copy(key) {
- Some(v) => Ok(v),
+ match hm.get(key) {
+ Some(v) => Ok(v.clone()),
None => Ok(_nil()),
}
},
- _ => return err_str("get with non-string key"),
+ _ => err_str("get with non-string key"),
}
}
-pub fn contains_q(a:Vec<MalVal>) -> MalRet {
+pub fn contains_q(a: Vec<MalVal>) -> MalRet {
if a.len() != 2 {
return err_str("Wrong arity to contains? call");
}
- let a0 = a[0].clone();
- let hm: &HashMap<String,MalVal> = match *a0 {
+ let hm = match *a[0] {
Hash_Map(ref hm,_) => hm,
Nil => return Ok(_false()),
_ => return err_str("contains? on non-hash map"),
@@ -194,50 +188,37 @@ pub fn contains_q(a:Vec<MalVal>) -> MalRet {
true => Ok(_true()),
false => Ok(_false()),
}
- },
- _ => return err_str("contains? with non-string key"),
+ }
+ _ => err_str("contains? with non-string key"),
}
}
-pub fn keys(a:Vec<MalVal>) -> MalRet {
+pub fn keys(a: Vec<MalVal>) -> MalRet {
if a.len() != 1 {
return err_str("Wrong arity to keys call");
}
- let a0 = a[0].clone();
- let hm: &HashMap<String,MalVal> = match *a0 {
+ let hm = match *a[0] {
Hash_Map(ref hm,_) => hm,
Nil => return Ok(_nil()),
_ => return err_str("contains? on non-hash map"),
};
- //if hm.len() == 0 { return Ok(_nil()); }
- let mut keys = vec![];
- for k in hm.keys() {
- keys.push(string(k.to_string()));
- }
- Ok(list(keys))
+ Ok(list(hm.keys().map(|s| string(s.to_string())).collect()))
}
-pub fn vals(a:Vec<MalVal>) -> MalRet {
+pub fn vals(a: Vec<MalVal>) -> MalRet {
if a.len() != 1 {
return err_str("Wrong arity to values call");
}
- let a0 = a[0].clone();
- let hm: &HashMap<String,MalVal> = match *a0 {
+ let hm = match *a[0] {
Hash_Map(ref hm,_) => hm,
Nil => return Ok(_nil()),
_ => return err_str("contains? on non-hash map"),
};
- //if hm.len() == 0 { return Ok(_nil()); }
- let mut vals = vec![];
- for k in hm.values() {
- vals.push(k.clone());
- }
- Ok(list(vals))
+ Ok(list(hm.values().map(|s| s.clone()).collect()))
}
-
// Sequence functions
-pub fn cons(a:Vec<MalVal>) -> MalRet {
+pub fn cons(a: Vec<MalVal>) -> MalRet {
match *a[1] {
List(ref v,_) | Vector(ref v,_) => {
let mut new_v = v.clone();
@@ -248,32 +229,28 @@ pub fn cons(a:Vec<MalVal>) -> MalRet {
}
}
-pub fn concat(a:Vec<MalVal>) -> MalRet {
- let mut new_v:Vec<MalVal> = vec![];
+pub fn concat(a: Vec<MalVal>) -> MalRet {
+ let mut new_v: Vec<MalVal> = vec![];
for lst in a.iter() {
match **lst {
- List(ref l,_) | Vector(ref l,_) => {
- new_v.push_all(l.as_slice());
- },
+ List(ref l,_) | Vector(ref l,_) => new_v.push_all(l),
_ => return err_str("concat called with non-sequence"),
}
}
Ok(list(new_v))
}
-pub fn nth(a:Vec<MalVal>) -> MalRet {
+pub fn nth(a: Vec<MalVal>) -> MalRet {
if a.len() != 2 {
return err_str("Wrong arity to nth call");
}
- let a0 = a[0].clone();
- let a1 = a[1].clone();
- let seq = match *a0 {
+ let seq = match *a[0] {
List(ref v,_) | Vector(ref v,_) => v,
_ => return err_str("nth called with non-sequence"),
};
- let idx = match *a1 {
+ let idx = match *a[1] {
Int(i) => {
- match i.to_uint() {
+ match i.to_usize() {
Some(ui) => ui,
None => return Ok(_nil()),
}
@@ -281,18 +258,17 @@ pub fn nth(a:Vec<MalVal>) -> MalRet {
_ => return err_str("nth called with non-integer index"),
};
if idx >= seq.len() {
- return err_str("nth: index out of range")
+ err_str("nth: index out of range")
} else {
Ok(seq[idx].clone())
}
}
-pub fn first(a:Vec<MalVal>) -> MalRet {
+pub fn first(a: Vec<MalVal>) -> MalRet {
if a.len() != 1 {
return err_str("Wrong arity to first call");
}
- let a0 = a[0].clone();
- let seq = match *a0 {
+ let seq = match *a[0] {
List(ref v,_) | Vector(ref v,_) => v,
_ => return err_str("first called with non-sequence"),
};
@@ -303,27 +279,26 @@ pub fn first(a:Vec<MalVal>) -> MalRet {
}
}
-pub fn rest(a:Vec<MalVal>) -> MalRet {
+pub fn rest(a: Vec<MalVal>) -> MalRet {
if a.len() != 1 {
return err_str("Wrong arity to rest call");
}
- let a0 = a[0].clone();
- let seq = match *a0 {
+ let seq = match *a[0] {
List(ref v,_) | Vector(ref v,_) => v,
_ => return err_str("rest called with non-sequence"),
};
if seq.len() == 0 {
Ok(list(vec![]))
} else {
- Ok(list(seq.slice(1,seq.len()).to_vec()))
+ Ok(list(seq[1..].to_vec()))
}
}
-pub fn empty_q(a:Vec<MalVal>) -> MalRet {
+pub fn empty_q(a: Vec<MalVal>) -> MalRet {
if a.len() != 1 {
return err_str("Wrong arity to empty? call");
}
- match *a[0].clone() {
+ match *a[0] {
List(ref v,_) | Vector(ref v,_) => {
match v.len() {
0 => Ok(_true()),
@@ -334,48 +309,42 @@ pub fn empty_q(a:Vec<MalVal>) -> MalRet {
}
}
-pub fn count(a:Vec<MalVal>) -> MalRet {
+pub fn count(a: Vec<MalVal>) -> MalRet {
if a.len() != 1 {
return err_str("Wrong arity to count call");
}
- match *a[0].clone() {
- List(ref v,_) | Vector(ref v,_) => {
- Ok(_int(v.len().to_int().unwrap()))
- },
+ match *a[0] {
+ List(ref v,_) | Vector(ref v,_) => Ok(_int(v.len().to_isize().unwrap())),
Nil => Ok(_int(0)),
_ => err_str("count called on non-sequence"),
}
}
-pub fn apply(a:Vec<MalVal>) -> MalRet {
+pub fn apply(a: Vec<MalVal>) -> MalRet {
if a.len() < 2 {
return err_str("apply call needs 2 or more arguments");
}
let ref f = a[0];
- let mut args = a.slice(1,a.len()-1).to_vec();
+ let mut args = a[1..a.len()-1].to_vec();
match *a[a.len()-1] {
- List(ref v,_) | Vector(ref v,_) => {
- args.push_all(v.as_slice());
+ List(ref v, _) | Vector(ref v, _) => {
+ args.push_all(v);
f.apply(args)
},
_ => err_str("apply call with non-sequence"),
}
}
-pub fn map(a:Vec<MalVal>) -> MalRet {
+pub fn map(a: Vec<MalVal>) -> MalRet {
if a.len() != 2 {
return err_str("Wrong arity to map call");
}
let mut results:Vec<MalVal> = vec![];
- let ref f = a[0].clone();
- let seq = a[1].clone();
- match *seq {
+ match *a[1] {
List(ref v,_) | Vector(ref v,_) => {
for mv in v.iter() {
- match f.apply(vec![mv.clone()]) {
- Ok(res) => results.push(res),
- Err(e) => return Err(e),
- }
+ let res = try!(a[0].apply(vec![mv.clone()]));
+ results.push(res);
}
},
_ => return err_str("map call with non-sequence"),
@@ -383,53 +352,52 @@ pub fn map(a:Vec<MalVal>) -> MalRet {
Ok(list(results))
}
-pub fn conj(a:Vec<MalVal>) -> MalRet {
+pub fn conj(a: Vec<MalVal>) -> MalRet {
if a.len() < 2 {
return err_str("Wrong arity to conj call");
}
- let mut new_v:Vec<MalVal> = vec![];
- match *a[0].clone() {
+ let mut new_v: Vec<MalVal> = vec![];
+ match *a[0] {
List(ref l,_) => {
- new_v.push_all(l.as_slice());
+ new_v.push_all(l);
for mv in a.iter().skip(1) {
- new_v.insert(0,mv.clone());
+ new_v.insert(0, mv.clone());
}
Ok(list(new_v))
- },
+ }
Vector(ref l,_) => {
- new_v.push_all(l.as_slice());
+ new_v.push_all(l);
for mv in a.iter().skip(1) {
new_v.push(mv.clone());
}
Ok(vector(new_v))
- },
- _ => return err_str("conj called with non-sequence"),
+ }
+ _ => err_str("conj called with non-sequence"),
}
}
// Metadata functions
-fn with_meta(a:Vec<MalVal>) -> MalRet {
+fn with_meta(a: Vec<MalVal>) -> MalRet {
if a.len() != 2 {
return err_str("Wrong arity to with-meta call");
}
- let mv = a[0].clone();
let meta = a[1].clone();
- match *mv {
- List(ref v,_) => Ok(listm(v.clone(),meta)),
- Vector(ref v,_) => Ok(vectorm(v.clone(),meta)),
- Hash_Map(ref hm,_) => Ok(hash_mapm(hm.clone(),meta)),
- MalFunc(ref mfd,_) => Ok(malfuncd(mfd.clone(),meta)),
- Func(f,_) => Ok(funcm(f,meta)),
+ match *a[0] {
+ List(ref v,_) => Ok(listm(v.clone(), meta)),
+ Vector(ref v,_) => Ok(vectorm(v.clone(), meta)),
+ Hash_Map(ref hm,_) => Ok(hash_mapm(hm.clone(), meta)),
+ MalFunc(ref mfd,_) => Ok(malfuncd(mfd.clone(), meta)),
+ Func(f,_) => Ok(funcm(f, meta)),
_ => err_str("type does not support metadata"),
}
}
-fn meta(a:Vec<MalVal>) -> MalRet {
+fn meta(a: Vec<MalVal>) -> MalRet {
if a.len() != 1 {
return err_str("Wrong arity to meta call");
}
- match *a[0].clone() {
+ match *a[0] {
List(_,ref meta) |
Vector(_,ref meta) |
Hash_Map(_,ref meta) |
@@ -440,53 +408,42 @@ fn meta(a:Vec<MalVal>) -> MalRet {
}
// Atom functions
-fn deref(a:Vec<MalVal>) -> MalRet {
+fn deref(a: Vec<MalVal>) -> MalRet {
if a.len() != 1 {
return err_str("Wrong arity to deref call");
}
- match *a[0].clone() {
- Atom(ref val) => {
- let val_cell = val.borrow();
- Ok(val_cell.clone())
- },
+ match *a[0] {
+ Atom(ref val) => Ok(val.borrow().clone()),
_ => err_str("deref called on non-atom"),
}
}
-fn reset_bang(a:Vec<MalVal>) -> MalRet {
+fn reset_bang(a: Vec<MalVal>) -> MalRet {
if a.len() != 2 {
return err_str("Wrong arity to map call");
}
- let a1 = a[1].clone();
- match *a[0].clone() {
+ match *a[0] {
Atom(ref val) => {
let mut val_cell = val.borrow_mut();
- let atm_mv = val_cell.deref_mut();
- *atm_mv = a1.clone();
- Ok(a1)
+ *val_cell = a[1].clone();
+ Ok(a[1].clone())
},
_ => err_str("reset! called on non-atom"),
}
}
-fn swap_bang(a:Vec<MalVal>) -> MalRet {
+fn swap_bang(a: Vec<MalVal>) -> MalRet {
if a.len() < 2 {
return err_str("Wrong arity to swap_q call");
}
let f = a[1].clone();
- match *a[0].clone() {
+ match *a[0] {
Atom(ref val) => {
let mut val_cell = val.borrow_mut();
- let atm_mv = val_cell.deref_mut();
- let mut args = a.slice(2,a.len()).to_vec();
- args.insert(0, atm_mv.clone());
- match f.apply(args) {
- Ok(new_mv) => {
- *atm_mv = new_mv.clone();
- Ok(new_mv)
- }
- Err(e) => Err(e),
- }
+ let mut args = a[2..].to_vec();
+ args.insert(0, val_cell.clone());
+ *val_cell = try!(f.apply(args));
+ Ok(val_cell.clone())
},
_ => err_str("swap! called on non-atom"),
}
@@ -494,7 +451,7 @@ fn swap_bang(a:Vec<MalVal>) -> MalRet {
pub fn ns() -> HashMap<String,MalVal> {
- let mut ns: HashMap<String,MalVal> = HashMap::new();;
+ let mut ns = HashMap::new();;
ns.insert("=".to_string(), func(equal_q));
ns.insert("throw".to_string(), func(throw));
diff --git a/rust/src/env.rs b/rust/src/env.rs
index e9af154..c27e499 100644
--- a/rust/src/env.rs
+++ b/rust/src/env.rs
@@ -1,11 +1,9 @@
-#![allow(dead_code)]
-
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
-use std::fmt;
-use types::{MalVal,MalRet,Sym,List,Vector,_nil,list,err_string};
+use types::{MalVal, MalRet, _nil, list, err_string};
+use types::MalType::{Sym, List, Vector};
struct EnvType {
data: HashMap<String,MalVal>,
@@ -27,10 +25,10 @@ pub fn env_bind(env: &Env,
match *mexprs {
List(ref exprs,_) | Vector(ref exprs,_) => {
let mut it = binds.iter().enumerate();
- for (i, b) in it {
+ for (i, b) in it.by_ref() {
match **b {
Sym(ref strn) => {
- if *strn == "&".to_string() {
+ if *strn == "&" {
variadic = true;
break;
} else {
@@ -44,7 +42,7 @@ pub fn env_bind(env: &Env,
let (i, sym) = it.next().unwrap();
match **sym {
Sym(_) => {
- let rest = exprs.slice(i-1,exprs.len()).to_vec();
+ let rest = exprs[i-1..].to_vec();
env_set(env, sym.clone(), list(rest));
}
_ => return Err("& bind to non-symbol".to_string()),
@@ -59,14 +57,15 @@ pub fn env_bind(env: &Env,
}
}
-pub fn env_find(env: Env, key: MalVal) -> Option<Env> {
- match *key {
+pub fn env_find(env: &Env, key: &MalVal) -> Option<Env> {
+ match **key {
Sym(ref k) => {
- if env.borrow().data.contains_key(k) {
- Some(env)
+ let map = env.borrow();
+ if map.data.contains_key(k) {
+ Some(env.clone())
} else {
- match env.borrow().outer {
- Some(ref e) => env_find(e.clone(), key.clone()),
+ match map.outer {
+ Some(ref e) => env_find(e, key),
None => None,
}
}
@@ -84,35 +83,24 @@ pub fn env_root(env: &Env) -> Env {
pub fn env_set(env: &Env, key: MalVal, val: MalVal) {
match *key {
- Sym(ref k) => {
- env.borrow_mut().data.insert(k.to_string(), val.clone());
- },
+ Sym(ref k) => { env.borrow_mut().data.insert(k.to_string(), val); }
_ => {},
}
}
-pub fn env_get(env: Env, key: MalVal) -> MalRet {
- match *key {
+pub fn env_get(env: &Env, key: &MalVal) -> MalRet {
+ match **key {
Sym(ref k) => {
- match env_find(env, key.clone()) {
+ match env_find(env, key) {
Some(e) => {
- match e.borrow().data.find_copy(k) {
- Some(v) => Ok(v),
+ match e.borrow().data.get(k) {
+ Some(v) => Ok(v.clone()),
None => Ok(_nil()),
}
},
- None => err_string("'".to_string() + k.to_string() + "' not found".to_string()),
+ None => err_string(format!("'{}' not found", k)),
}
}
_ => err_string("env_get called with non-symbol key".to_string()),
}
}
-
-impl fmt::Show for EnvType {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self.outer {
- Some(ref o) => write!(f, "[{}/outer:{}]", self.data, o.borrow()),
- _ => write!(f, "{}", self.data)
- }
- }
-}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
new file mode 100644
index 0000000..04eda85
--- /dev/null
+++ b/rust/src/lib.rs
@@ -0,0 +1,17 @@
+#![feature(io, fs, core, std_misc, collections)]
+
+extern crate libc;
+extern crate pcre;
+extern crate regex;
+extern crate time;
+
+macro_rules! regex {
+ ($e:expr) => (::regex::Regex::new($e).unwrap())
+}
+
+pub mod core;
+pub mod env;
+pub mod printer;
+pub mod reader;
+pub mod readline;
+pub mod types;
diff --git a/rust/src/printer.rs b/rust/src/printer.rs
index f46b66c..591822b 100644
--- a/rust/src/printer.rs
+++ b/rust/src/printer.rs
@@ -3,7 +3,7 @@ use types::MalVal;
pub fn escape_str(s: &str) -> String {
let mut escaped = String::new();
escaped.push('"');
- for c in s.as_slice().chars() {
+ for c in s.chars() {
let _ = match c {
'"' => escaped.push_str("\\\""),
'\\' => escaped.push_str("\\\\"),
@@ -24,7 +24,7 @@ pub fn escape_str(s: &str) -> String {
pub fn unescape_str(s: &str) -> String {
let re1 = regex!(r#"\\""#);
let re2 = regex!(r#"\n"#);
- re2.replace_all(re1.replace_all(s.as_slice(), "\"").as_slice(), "\n")
+ re2.replace_all(&re1.replace_all(&s, "\""), "\n")
}
pub fn pr_list(lst: &Vec<MalVal>, pr: bool,
@@ -38,7 +38,7 @@ pub fn pr_list(lst: &Vec<MalVal>, pr: bool,
} else {
res.push_str(join);
}
- res.push_str(mv.pr_str(pr).as_slice());
+ res.push_str(&mv.pr_str(pr));
}
res.push_str(end);
res
diff --git a/rust/src/reader.rs b/rust/src/reader.rs
index d7b2b4c..4750c46 100644
--- a/rust/src/reader.rs
+++ b/rust/src/reader.rs
@@ -1,20 +1,14 @@
-//#![feature(phase)]
-//#[phase(plugin)]
-//extern crate regex_macros;
-//extern crate regex;
-
-extern crate pcre;
-
-use types::{MalVal,MalRet,ErrString,ErrMalVal,
- _nil,_true,_false,_int,symbol,string,list,vector,hash_mapv,
- err_str,err_string,err_val};
-use self::pcre::Pcre;
+use types::MalError::{ErrString, ErrMalVal};
+use types::{MalVal, MalRet,
+ _nil, _true, _false, _int, symbol, string, list, vector, hash_mapv,
+ err_str, err_string, err_val};
+use pcre::Pcre;
use super::printer::unescape_str;
-#[deriving(Show, Clone)]
+#[derive(Debug, Clone)]
struct Reader {
- tokens : Vec<String>,
- position : uint,
+ tokens: Vec<String>,
+ position: usize,
}
impl Reader {
@@ -35,15 +29,15 @@ impl Reader {
}
}
-fn tokenize(str :String) -> Vec<String> {
+fn tokenize(str: String) -> Vec<String> {
let mut results = vec![];
let re = match Pcre::compile(r###"[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"###) {
- Err(_) => { fail!("failed to compile regex") },
+ Err(_) => { panic!("failed to compile regex") },
Ok(re) => re
};
- let mut it = re.matches(str.as_slice());
+ let mut it = re.matches(&str);
loop {
let opt_m = it.next();
if opt_m.is_none() { break; }
@@ -61,15 +55,15 @@ fn read_atom(rdr : &mut Reader) -> MalRet {
//println!("read_atom: {}", otoken);
if otoken.is_none() { return err_str("read_atom underflow"); }
let stoken = otoken.unwrap();
- let token = stoken.as_slice();
+ let token = &stoken[..];
if regex!(r"^-?[0-9]+$").is_match(token) {
- let num : Option<int> = from_str(token);
+ let num : Option<isize> = token.parse().ok();
Ok(_int(num.unwrap()))
} else if regex!(r#"^".*"$"#).is_match(token) {
- let new_str = token.slice(1,token.len()-1);
+ let new_str = &token[1..token.len()-1];
Ok(string(unescape_str(new_str)))
} else if regex!(r#"^:"#).is_match(token) {
- Ok(string("\u029e".to_string() + token.slice(1,token.len())))
+ Ok(string(format!("\u{29e}{}", &token[1..])))
} else if token == "nil" {
Ok(_nil())
} else if token == "true" {
@@ -87,19 +81,19 @@ fn read_seq(rdr : &mut Reader, start: &str, end: &str) -> Result<Vec<MalVal>,Str
return Err("read_atom underflow".to_string());
}
let stoken = otoken.unwrap();
- let token = stoken.as_slice();
+ let token = &stoken[..];
if token != start {
- return Err("expected '".to_string() + start.to_string() + "'".to_string());
+ return Err(format!("expected '{}'", start))
}
let mut ast_vec : Vec<MalVal> = vec![];
loop {
let otoken = rdr.peek();
if otoken.is_none() {
- return Err("expected '".to_string() + end.to_string() + "', got EOF".to_string());
+ return Err(format!("expected '{}', got EOF", end));
}
let stoken = otoken.unwrap();
- let token = stoken.as_slice();
+ let token = &stoken[..];
if token == end { break; }
match read_form(rdr) {
@@ -138,7 +132,7 @@ fn read_form(rdr : &mut Reader) -> MalRet {
let otoken = rdr.peek();
//println!("read_form: {}", otoken);
let stoken = otoken.unwrap();
- let token = stoken.as_slice();
+ let token = &stoken[..];
match token {
"'" => {
let _ = rdr.next();
diff --git a/rust/src/readline.rs b/rust/src/readline.rs
index 17d1ed9..37bf674 100644
--- a/rust/src/readline.rs
+++ b/rust/src/readline.rs
@@ -1,10 +1,11 @@
// Based on: https://github.com/shaleh/rust-readline (MIT)
-extern crate libc;
+use libc;
-use std::c_str;
-
-use std::io::{File, Append, Write};
-use std::io::BufferedReader;
+use std::ffi::{CStr, CString};
+use std::fs::{OpenOptions, File};
+use std::io::BufReader;
+use std::io::prelude::*;
+use std::str;
mod ext_readline {
extern crate libc;
@@ -18,19 +19,21 @@ mod ext_readline {
pub fn add_history(line: &str) {
unsafe {
- ext_readline::add_history(line.to_c_str().as_ptr());
+ ext_readline::add_history(CString::new(line).unwrap().as_ptr());
}
}
pub fn readline(prompt: &str) -> Option<String> {
- let cprmt = prompt.to_c_str();
+ let cprmt = CString::new(prompt).unwrap();
unsafe {
- let ret = ext_readline::readline(cprmt.as_ptr());
- if ret.is_null() { // user pressed Ctrl-D
+ let ptr = ext_readline::readline(cprmt.as_ptr());
+ if ptr.is_null() { // user pressed Ctrl-D
None
- }
- else {
- c_str::CString::new(ret, true).as_str().map(|ret| ret.to_string())
+ } else {
+ let ret = str::from_utf8(CStr::from_ptr(ptr).to_bytes());
+ let ret = ret.ok().map(|s| s.to_string());
+ libc::free(ptr as *mut _);
+ return ret;
}
}
}
@@ -38,7 +41,7 @@ pub fn readline(prompt: &str) -> Option<String> {
// --------------------------------------------
static mut history_loaded : bool = false;
-static HISTORY_FILE : &'static str = "/home/joelm/.mal-history";
+static HISTORY_FILE: &'static str = "/home/joelm/.mal-history";
fn load_history() {
unsafe {
@@ -46,31 +49,33 @@ fn load_history() {
history_loaded = true;
}
- let path = Path::new(HISTORY_FILE);
- let mut file = BufferedReader::new(File::open(&path));
+ let file = match File::open(HISTORY_FILE) {
+ Ok(f) => f,
+ Err(..) => return
+ };
+ let file = BufReader::new(file);
for line in file.lines() {
let rt: &[_] = &['\r', '\n'];
let line2 = line.unwrap();
- let line3 = line2.as_slice().trim_right_chars(rt);
+ let line3 = line2.trim_right_matches(rt);
add_history(line3);
}
}
fn append_to_history(line: &str) {
- let path = Path::new("/home/joelm/.mal-history");
- let mut file = File::open_mode(&path, Append, Write);
- let _ = file.write_line(line);
+ let file = OpenOptions::new().append(true).write(true).create(true)
+ .open(HISTORY_FILE);
+ let mut file = match file { Ok(f) => f, Err(..) => return };
+ let _ = file.write_all(line.as_bytes());
+ let _ = file.write_all(b"\n");
}
pub fn mal_readline (prompt: &str) -> Option<String> {
load_history();
let line = readline(prompt);
- match line {
- None => None,
- _ => {
- add_history(line.clone().unwrap().as_slice());
- append_to_history(line.clone().unwrap().as_slice());
- line
- }
+ if let Some(ref s) = line {
+ add_history(s);
+ append_to_history(s);
}
+ line
}
diff --git a/rust/src/stepA_mal.rs b/rust/src/stepA_mal.rs
deleted file mode 100644
index 8e30867..0000000
--- a/rust/src/stepA_mal.rs
+++ /dev/null
@@ -1,479 +0,0 @@
-// support precompiled regexes in reader.rs
-#![feature(phase)]
-#[phase(plugin)]
-extern crate regex_macros;
-extern crate regex;
-
-use std::collections::HashMap;
-use std::os;
-
-use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str,
- Nil,False,Sym,List,Vector,Hash_Map,Func,MalFunc,
- symbol,_nil,string,list,vector,hash_map,malfunc,malfuncd};
-use env::{Env,env_new,env_bind,env_root,env_find,env_set,env_get};
-mod readline;
-mod types;
-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,_) | 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.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 is_macro_call(ast: MalVal, env: Env) -> bool {
- match *ast {
- List(ref lst,_) => {
- match *lst[0] {
- Sym(_) => {
- if env_find(env.clone(), lst[0].clone()).is_some() {
- match env_get(env, lst[0].clone()) {
- 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.clone(), a0.clone()) {
- Ok(mf) => mf,
- Err(e) => return Err(e),
- }
- },
- _ => break,
- };
- match *mf {
- MalFunc(_,_) => {
- match mf.apply(args.slice(1,args.len()).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.clone(), 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.as_slice()),
- _ => (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.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());
- 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.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_str(e.as_slice()),
- }
- },
- _ => 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.as_slice()), v);
- }
- // see eval() for definition of "eval"
- env_set(&repl_env, symbol("*ARGV*".as_slice()), 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 = 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, symbol("*ARGV*".as_slice()), list(mv_args));
- let lf = "(load-file \"".to_string() + args[1] + "\")".to_string();
- match rep(lf.as_slice(), repl_env.clone()) {
- Ok(_) => {
- os::set_exit_status(0);
- return;
- },
- Err(str) => {
- println!("Error: {}", str);
- os::set_exit_status(1);
- return;
- },
- }
- }
-
- // 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().as_slice(), repl_env.clone()) {
- Ok(str) => println!("{}", str),
- Err(ErrMalVal(_)) => (), // Blank line
- Err(ErrString(s)) => println!("Error: {}", s),
- }
- }
-}
diff --git a/rust/src/types.rs b/rust/src/types.rs
index 141c3db..0ad036c 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -7,28 +7,29 @@ use std::fmt;
use super::printer::{escape_str,pr_list};
use super::env::{Env,env_new,env_bind};
-#[deriving(Clone)]
+use self::MalType::*;
+use self::MalError::*;
+
+#[derive(Clone)]
#[allow(non_camel_case_types)]
pub enum MalType {
Nil,
True,
False,
- Int(int),
+ Int(isize),
Strn(String),
Sym(String),
List(Vec<MalVal>, MalVal),
Vector(Vec<MalVal>, MalVal),
Hash_Map(HashMap<String, MalVal>, MalVal),
Func(fn(Vec<MalVal>) -> MalRet, MalVal),
- //Func(fn(&[MalVal]) -> MalRet),
- //Func(|Vec<MalVal>|:'a -> MalRet),
MalFunc(MalFuncData, MalVal),
Atom(RefCell<MalVal>),
}
pub type MalVal = Rc<MalType>;
-#[deriving(Show)]
+#[derive(Debug)]
pub enum MalError {
ErrString(String),
ErrMalVal(MalVal),
@@ -49,16 +50,7 @@ pub fn err_val(mv: MalVal) -> MalRet {
Err(ErrMalVal(mv))
}
-/*
-pub enum MalRet {
- Val(MalVal),
- MalErr(MalVal),
- StringErr(String),
-}
-*/
-
-
-#[deriving(Clone)]
+#[derive(Clone)]
pub struct MalFuncData {
pub eval: fn(MalVal, Env) -> MalRet,
pub exp: MalVal,
@@ -70,59 +62,51 @@ pub struct MalFuncData {
impl MalType {
pub fn pr_str(&self, print_readably: bool) -> String {
let _r = print_readably;
- let mut res = String::new();
match *self {
- Nil => res.push_str("nil"),
- True => res.push_str("true"),
- False => res.push_str("false"),
- Int(v) => res.push_str(v.to_string().as_slice()),
- Sym(ref v) => res.push_str((*v).as_slice()),
+ Nil => "nil".to_string(),
+ True => "true".to_string(),
+ False => "false".to_string(),
+ Int(v) => v.to_string(),
+ Sym(ref v) => v.clone(),
Strn(ref v) => {
- if v.as_slice().starts_with("\u029e") {
- res.push_str(":");
- res.push_str(v.as_slice().slice(2,v.len()))
+ if v.starts_with("\u{29e}") {
+ format!(":{}", &v[2..])
} else if print_readably {
- res.push_str(escape_str((*v).as_slice()).as_slice())
+ escape_str(v)
} else {
- res.push_str(v.as_slice())
+ v.clone()
}
},
List(ref v,_) => {
- res = pr_list(v, _r, "(", ")", " ")
+ pr_list(v, _r, "(", ")", " ")
},
Vector(ref v,_) => {
- res = pr_list(v, _r, "[", "]", " ")
+ pr_list(v, _r, "[", "]", " ")
},
Hash_Map(ref v,_) => {
- let mut first = true;
+ let mut res = String::new();
res.push_str("{");
- for (key, value) in v.iter() {
- if first { first = false; } else { res.push_str(" "); }
- if key.as_slice().starts_with("\u029e") {
+ for (i, (key, value)) in v.iter().enumerate() {
+ if i != 0 { res.push_str(" "); }
+ if key.starts_with("\u{29e}") {
res.push_str(":");
- res.push_str(key.as_slice().slice(2,key.len()))
+ res.push_str(&key[2..])
} else if print_readably {
- res.push_str(escape_str(key.as_slice()).as_slice())
+ res.push_str(&escape_str(key))
} else {
- res.push_str(key.as_slice())
+ res.push_str(key)
}
res.push_str(" ");
- res.push_str(value.pr_str(_r).as_slice());
+ res.push_str(&value.pr_str(_r));
}
- res.push_str("}")
+ res.push_str("}");
+ res
},
// TODO: better native function representation
- Func(_,_) => {
- res.push_str(format!("#<function ...>").as_slice())
- },
- MalFunc(ref mf,_) => {
- res.push_str(format!("(fn* {} {})", mf.params, mf.exp).as_slice())
- },
- Atom(ref v) => {
- res = format!("(atom {})", v.borrow());
- },
- };
- res
+ Func(_, _) => format!("#<function ...>"),
+ MalFunc(ref mf,_) => format!("(fn* {:?} {:?})", mf.params, mf.exp),
+ Atom(ref v) => format!("(atom {:?})", &**v.borrow()),
+ }
}
pub fn apply(&self, args:Vec<MalVal>) -> MalRet {
@@ -161,11 +145,11 @@ impl PartialEq for MalType {
(&Func(_,_), &Func(_,_)) => false,
(&MalFunc(_,_), &MalFunc(_,_)) => false,
_ => return false,
- }
+ }
}
}
-impl fmt::Show for MalType {
+impl fmt::Debug for MalType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.pr_str(true))
}
@@ -206,7 +190,7 @@ pub fn false_q(a:Vec<MalVal>) -> MalRet {
}
}
-pub fn _int(i: int) -> MalVal { Rc::new(Int(i)) }
+pub fn _int(i: isize) -> MalVal { Rc::new(Int(i)) }
// Symbols
@@ -237,11 +221,9 @@ pub fn _keyword(a: Vec<MalVal>) -> MalRet {
if a.len() != 1 {
return err_str("Wrong arity to keyword call");
}
- match *a[0].clone() {
- Strn(ref s) => {
- Ok(Rc::new(Strn("\u029e".to_string() + s.to_string())))
- },
- _ => return err_str("keyword called on non-string"),
+ match *a[0] {
+ Strn(ref s) => Ok(Rc::new(Strn(format!("\u{29e}{}", s)))),
+ _ => err_str("keyword called on non-string"),
}
}
pub fn keyword_q(a:Vec<MalVal>) -> MalRet {
@@ -250,7 +232,7 @@ pub fn keyword_q(a:Vec<MalVal>) -> MalRet {
}
match *a[0].clone() {
Strn(ref s) => {
- if s.as_slice().starts_with("\u029e") {
+ if s.starts_with("\u{29e}") {
Ok(_true())
} else {
Ok(_false())