diff options
| author | Joel Martin <github@martintribe.org> | 2014-10-25 12:41:24 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-01-06 21:58:57 -0600 |
| commit | 0ab374bc261f871ab8fbbc13e0096f44225e2a3f (patch) | |
| tree | 18bf694e55ee767e5d55edf73819affa3f0214b5 /rust/src | |
| parent | abdd56ebc0e01cd92f694ef2bcafcc394453d055 (diff) | |
| download | mal-0ab374bc261f871ab8fbbc13e0096f44225e2a3f.tar.gz mal-0ab374bc261f871ab8fbbc13e0096f44225e2a3f.zip | |
rust: add step2_eval.
Diffstat (limited to 'rust/src')
| -rw-r--r-- | rust/src/printer.rs | 26 | ||||
| -rw-r--r-- | rust/src/reader.rs | 10 | ||||
| -rw-r--r-- | rust/src/step1_read_print.rs | 7 | ||||
| -rw-r--r-- | rust/src/step2_eval.rs | 125 | ||||
| -rw-r--r-- | rust/src/types.rs | 13 |
5 files changed, 170 insertions, 11 deletions
diff --git a/rust/src/printer.rs b/rust/src/printer.rs new file mode 100644 index 0000000..59821ec --- /dev/null +++ b/rust/src/printer.rs @@ -0,0 +1,26 @@ +pub fn escape_str(s: &str) -> String { + let mut escaped = String::new(); + escaped.push('"'); + for c in s.as_slice().chars() { + let _ = match c { + '"' => escaped.push_str("\\\""), + '\\' => escaped.push_str("\\\\"), + '\x08' => escaped.push_str("\\b"), + '\x0c' => escaped.push_str("\\f"), + '\n' => escaped.push_str("\\n"), + '\r' => escaped.push_str("\\r"), + '\t' => escaped.push_str("\\t"), + _ => escaped.push(c), + }; + }; + + escaped.push('"'); + + escaped +} + +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") +} diff --git a/rust/src/reader.rs b/rust/src/reader.rs index 9ad129b..035cfde 100644 --- a/rust/src/reader.rs +++ b/rust/src/reader.rs @@ -6,7 +6,7 @@ extern crate pcre; use std::rc::Rc; -use types::{MalVal,Nil,True,False,Int,Strn,Sym,List}; +use types::{MalVal,MalRet,Nil,True,False,Int,Strn,Sym,List}; use self::pcre::Pcre; use super::printer::unescape_str; @@ -54,7 +54,7 @@ fn tokenize(str :String) -> Vec<String> { results } -fn read_atom(rdr : &mut Reader) -> Result<MalVal,String> { +fn read_atom(rdr : &mut Reader) -> MalRet { let otoken = rdr.next(); //println!("read_atom: {}", otoken); if otoken.is_none() { return Err("read_atom underflow".to_string()); } @@ -77,7 +77,7 @@ fn read_atom(rdr : &mut Reader) -> Result<MalVal,String> { } } -fn read_list(rdr : &mut Reader) -> Result<MalVal,String> { +fn read_list(rdr : &mut Reader) -> MalRet { let otoken = rdr.next(); if otoken.is_none() { return Err("read_atom underflow".to_string()); } let stoken = otoken.unwrap(); @@ -103,7 +103,7 @@ fn read_list(rdr : &mut Reader) -> Result<MalVal,String> { Ok(Rc::new(List(ast_vec))) } -fn read_form(rdr : &mut Reader) -> Result<MalVal,String> { +fn read_form(rdr : &mut Reader) -> MalRet { let otoken = rdr.peek(); //println!("read_form: {}", otoken); let stoken = otoken.unwrap(); @@ -115,7 +115,7 @@ fn read_form(rdr : &mut Reader) -> Result<MalVal,String> { } } -pub fn read_str(str :String) -> Result<MalVal,String> { +pub fn read_str(str :String) -> MalRet { let tokens = tokenize(str); if tokens.len() == 0 { return Err("<empty line>".to_string()); diff --git a/rust/src/step1_read_print.rs b/rust/src/step1_read_print.rs index c6f87d0..bc4827d 100644 --- a/rust/src/step1_read_print.rs +++ b/rust/src/step1_read_print.rs @@ -4,20 +4,19 @@ extern crate regex_macros; extern crate regex; -use std::rc::Rc; -use types::{MalVal,List,Vector,Int,Nil}; +use types::{MalVal,MalRet}; mod readline; mod types; mod reader; mod printer; // read -fn read(str: String) -> Result<MalVal,String> { +fn read(str: String) -> MalRet { reader::read_str(str) } // eval -fn eval(ast: MalVal) -> Result<MalVal,String> { +fn eval(ast: MalVal) -> MalRet { Ok(ast) } diff --git a/rust/src/step2_eval.rs b/rust/src/step2_eval.rs new file mode 100644 index 0000000..5df9a94 --- /dev/null +++ b/rust/src/step2_eval.rs @@ -0,0 +1,125 @@ +// support precompiled regexes in reader.rs +#![feature(phase)] +#[phase(plugin)] +extern crate regex_macros; +extern crate regex; + +use std::rc::Rc; +use std::collections::HashMap; +use types::{MalVal,MalRet,Nil,Int,Sym,List,Func}; +mod readline; +mod types; +mod reader; +mod printer; + +// 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).find_copy(sym) { + Some(mv) => Ok(mv), + None => Ok(Rc::new(Nil)), + } + }, + List(ref a) => { + let mut ast_vec : Vec<MalVal> = vec![]; + for mv in a.iter() { + let mv2 = mv.clone(); + match eval(mv2, env) { + Ok(mv) => { ast_vec.push(mv); }, + Err(e) => { return Err(e); }, + } + } + Ok(Rc::new(List(ast_vec))) + }, + _ => { + 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) => { + // TODO: make this work + //match args.as_slice() { + // [&Func(f), rest..] => { + // (*f)(rest.to_vec()) + // }, + // _ => Err("attempt to call non-function".to_string()), + //} + let args2 = args.clone(); + match *args2[0] { + Func(f) => f(args.slice(1,args.len()).to_vec()), + _ => Err("attempt to call non-function".to_string()), + } + } + _ => Err("Invalid apply".to_string()), + } + } + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: String, env: &HashMap<String,MalVal>) -> Result<String,String> { + match read(str) { + Err(e) => Err(e), + Ok(ast) => { + //println!("read: {}", ast); + match eval(ast, env) { + Err(e) => Err(e), + Ok(exp) => Ok(print(exp)), + } + } + } +} + +fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet { + match *a[0] { + Int(a0) => match *a[1] { + Int(a1) => Ok(Rc::new(Int(f(a0,a1)))), + _ => Err("second arg must be an int".to_string()), + }, + _ => Err("first arg must be an int".to_string()), + } +} +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(), Rc::new(Func(add))); + repl_env.insert("-".to_string(), Rc::new(Func(sub))); + repl_env.insert("*".to_string(), Rc::new(Func(mul))); + repl_env.insert("/".to_string(), Rc::new(Func(div))); + + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(line.unwrap(), &repl_env) { + Ok(str) => println!("{}", str), + Err(str) => println!("Error: {}", str), + } + } +} diff --git a/rust/src/types.rs b/rust/src/types.rs index 3e0e027..75aecbc 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -14,10 +14,16 @@ pub enum MalType { List(Vec<MalVal>), Vector(Vec<MalVal>), HashMap(collections::HashMap<String, MalVal>), + Func(fn(Vec<MalVal>) -> MalRet), + //Func(fn(&[MalVal]) -> MalRet), + //Func(|Vec<MalVal>|:'a -> MalRet), } pub type MalVal = Rc<MalType>; +pub type MalRet = Result<MalVal,String>; + + impl MalType { pub fn pr_str(&self, print_readably: bool) -> String { let _r = print_readably; @@ -44,8 +50,11 @@ impl MalType { } res.push_str(")") } -/* -*/ + // TODO: better function representation + //Func(ref v) => { + Func(_) => { + res.push_str(format!("#<function ...>").as_slice()) + } /* Vector(ref v) => { let mut first = true; |
