mirror of
https://github.com/kanaka/mal.git
synced 2024-11-10 02:45:44 +03:00
rust: add step4_if_fn_do
This commit is contained in:
parent
8f5b0f1040
commit
0a4d62f2f8
@ -9,22 +9,27 @@ authors = [ "Your name <you@example.com>" ]
|
||||
|
||||
git = "https://github.com/kanaka/rust-pcre"
|
||||
|
||||
|
||||
#[profile.dev]
|
||||
#
|
||||
#debug = true
|
||||
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "exp"
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "step0_repl"
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "step1_read_print"
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "step2_eval"
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "step3_env"
|
||||
|
||||
[[bin]]
|
||||
name = "step4_if_fn_do"
|
||||
|
147
rust/src/core.rs
Normal file
147
rust/src/core.rs
Normal file
@ -0,0 +1,147 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use types::{MalVal,MalRet,Func,True,False,Int,Strn,List,Nil};
|
||||
use printer;
|
||||
|
||||
// General functions
|
||||
|
||||
fn equal_q(a:Vec<MalVal>) -> MalRet {
|
||||
if a.len() != 2 {
|
||||
return Err("Wrong arity to equal? call".to_string());
|
||||
}
|
||||
match a[0] == a[1] {
|
||||
true => Ok(Rc::new(True)),
|
||||
false => Ok(Rc::new(False)),
|
||||
}
|
||||
}
|
||||
|
||||
// String routines
|
||||
fn pr_str(a:Vec<MalVal>) -> MalRet {
|
||||
Ok(Rc::new(Strn(printer::pr_list(&a, true, "", "", " "))))
|
||||
}
|
||||
|
||||
fn str(a:Vec<MalVal>) -> MalRet {
|
||||
Ok(Rc::new(Strn(printer::pr_list(&a, false, "", "", ""))))
|
||||
}
|
||||
|
||||
fn prn(a:Vec<MalVal>) -> MalRet {
|
||||
println!("{}", printer::pr_list(&a, true, "", "", " "))
|
||||
Ok(Rc::new(Nil))
|
||||
}
|
||||
|
||||
fn println(a:Vec<MalVal>) -> MalRet {
|
||||
println!("{}", printer::pr_list(&a, false, "", "", " "))
|
||||
Ok(Rc::new(Nil))
|
||||
}
|
||||
|
||||
// Numeric functions
|
||||
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 bool_op(f: |i:int,j:int|-> bool, a:Vec<MalVal>) -> MalRet {
|
||||
match *a[0] {
|
||||
Int(a0) => match *a[1] {
|
||||
Int(a1) => {
|
||||
match f(a0,a1) {
|
||||
true => Ok(Rc::new(True)),
|
||||
false => Ok(Rc::new(False)),
|
||||
}
|
||||
//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()),
|
||||
}
|
||||
}
|
||||
|
||||
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) }
|
||||
|
||||
|
||||
// Sequence functions
|
||||
pub fn list(a:Vec<MalVal>) -> MalRet {
|
||||
Ok(Rc::new(List(a)))
|
||||
}
|
||||
|
||||
pub fn list_q(a:Vec<MalVal>) -> MalRet {
|
||||
if a.len() != 1 {
|
||||
return Err("Wrong arity to list? call".to_string());
|
||||
}
|
||||
match *a[0].clone() {
|
||||
List(_) => Ok(Rc::new(True)),
|
||||
_ => Ok(Rc::new(False)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count(a:Vec<MalVal>) -> MalRet {
|
||||
if a.len() != 1 {
|
||||
return Err("Wrong arity to count call".to_string());
|
||||
}
|
||||
match *a[0].clone() {
|
||||
List(ref lst) => {
|
||||
Ok(Rc::new(Int(lst.len().to_int().unwrap())))
|
||||
},
|
||||
_ => Err("count called on non-sequence".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty_q(a:Vec<MalVal>) -> MalRet {
|
||||
if a.len() != 1 {
|
||||
return Err("Wrong arity to empty? call".to_string());
|
||||
}
|
||||
match *a[0].clone() {
|
||||
List(ref lst) => {
|
||||
match lst.len() {
|
||||
0 => Ok(Rc::new(True)),
|
||||
_ => Ok(Rc::new(False)),
|
||||
}
|
||||
},
|
||||
_ => Err("empty? called on non-sequence".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn ns() -> HashMap<String,MalVal> {
|
||||
let mut ns: HashMap<String,MalVal> = HashMap::new();;
|
||||
|
||||
ns.insert("=".to_string(), Rc::new(Func(equal_q)));
|
||||
|
||||
ns.insert("pr-str".to_string(), Rc::new(Func(pr_str)));
|
||||
ns.insert("str".to_string(), Rc::new(Func(str)));
|
||||
ns.insert("prn".to_string(), Rc::new(Func(prn)));
|
||||
ns.insert("println".to_string(), Rc::new(Func(println)));
|
||||
|
||||
ns.insert("<".to_string(), Rc::new(Func(lt)));
|
||||
ns.insert("<=".to_string(), Rc::new(Func(lte)));
|
||||
ns.insert(">".to_string(), Rc::new(Func(gt)));
|
||||
ns.insert(">=".to_string(), Rc::new(Func(gte)));
|
||||
ns.insert("+".to_string(), Rc::new(Func(add)));
|
||||
ns.insert("-".to_string(), Rc::new(Func(sub)));
|
||||
ns.insert("*".to_string(), Rc::new(Func(mul)));
|
||||
ns.insert("/".to_string(), Rc::new(Func(div)));
|
||||
|
||||
ns.insert("list".to_string(), Rc::new(Func(list)));
|
||||
ns.insert("list?".to_string(), Rc::new(Func(list_q)));
|
||||
ns.insert("empty?".to_string(), Rc::new(Func(empty_q)));
|
||||
ns.insert("count".to_string(), Rc::new(Func(count)));
|
||||
|
||||
return ns;
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
use types::{MalVal,MalRet,Nil};
|
||||
use types::{MalVal,MalRet,Nil,Sym,List};
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct EnvType {
|
||||
data: HashMap<String,MalVal>,
|
||||
outer: Option<Env>,
|
||||
@ -11,10 +13,54 @@ struct EnvType {
|
||||
|
||||
pub type Env = Rc<RefCell<EnvType>>;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn env_new(outer: Option<Env>) -> Env {
|
||||
Rc::new(RefCell::new(EnvType{data: HashMap::new(), outer: outer}))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn env_bind(env: &Env,
|
||||
mbinds: MalVal,
|
||||
mexprs: MalVal) -> Result<Env,String> {
|
||||
let mut variadic = false;
|
||||
match *mbinds {
|
||||
List(ref binds) => {
|
||||
match *mexprs {
|
||||
List(ref exprs) => {
|
||||
let mut it = binds.iter().enumerate();
|
||||
for (i, b) in it {
|
||||
match **b {
|
||||
Sym(ref strn) => {
|
||||
if *strn == "&".to_string() {
|
||||
variadic = true;
|
||||
break;
|
||||
} else {
|
||||
env_set(env, strn.clone(), exprs[i].clone());
|
||||
}
|
||||
}
|
||||
_ => return Err("non-symbol bind".to_string()),
|
||||
}
|
||||
}
|
||||
if variadic {
|
||||
let (i, sym) = it.next().unwrap();
|
||||
match **sym {
|
||||
Sym(ref s) => {
|
||||
let rest = exprs.slice(i-1,exprs.len()).to_vec();
|
||||
env_set(env, s.clone(), Rc::new(List(rest)));
|
||||
}
|
||||
_ => return Err("& bind to non-symbol".to_string()),
|
||||
}
|
||||
}
|
||||
Ok(env.clone())
|
||||
},
|
||||
_ => Err("exprs must be a list".to_string()),
|
||||
}
|
||||
},
|
||||
_ => Err("binds must be a list".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn env_find(env: Env, key: String) -> Option<Env> {
|
||||
if env.borrow().data.contains_key(&key) {
|
||||
Some(env)
|
||||
@ -26,10 +72,12 @@ pub fn env_find(env: Env, key: String) -> Option<Env> {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn env_set(env: &Env, key: String, val: MalVal) {
|
||||
env.borrow_mut().data.insert(key, val.clone());
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn env_get(env: Env, key: String) -> MalRet {
|
||||
match env_find(env, key.clone()) {
|
||||
Some(e) => {
|
||||
@ -42,3 +90,11 @@ pub fn env_get(env: Env, key: String) -> MalRet {
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use types::MalVal;
|
||||
|
||||
pub fn escape_str(s: &str) -> String {
|
||||
let mut escaped = String::new();
|
||||
escaped.push('"');
|
||||
@ -24,3 +26,20 @@ pub fn unescape_str(s: &str) -> String {
|
||||
let re2 = regex!(r#"\n"#);
|
||||
re2.replace_all(re1.replace_all(s.as_slice(), "\"").as_slice(), "\n")
|
||||
}
|
||||
|
||||
pub fn pr_list(lst: &Vec<MalVal>, pr: bool,
|
||||
start: &str , end: &str, join: &str) -> String {
|
||||
let mut first = true;
|
||||
let mut res = String::new();
|
||||
res.push_str(start);
|
||||
for mv in lst.iter() {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
res.push_str(join);
|
||||
}
|
||||
res.push_str(mv.pr_str(pr).as_slice());
|
||||
}
|
||||
res.push_str(end);
|
||||
res
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ extern crate regex;
|
||||
use types::{MalVal,MalRet};
|
||||
mod readline;
|
||||
mod types;
|
||||
mod env;
|
||||
mod reader;
|
||||
mod printer;
|
||||
|
||||
|
@ -10,6 +10,7 @@ use std::collections::HashMap;
|
||||
use types::{MalVal,MalRet,Nil,Int,Sym,List,Func};
|
||||
mod readline;
|
||||
mod types;
|
||||
mod env;
|
||||
mod reader;
|
||||
mod printer;
|
||||
|
||||
|
@ -42,9 +42,6 @@ fn eval_ast(ast: MalVal, env: Env) -> MalRet {
|
||||
Ok(ast)
|
||||
}
|
||||
}
|
||||
/*
|
||||
Ok(ast)
|
||||
*/
|
||||
}
|
||||
|
||||
fn eval(ast: MalVal, env: Env) -> MalRet {
|
||||
|
236
rust/src/step4_if_fn_do.rs
Normal file
236
rust/src/step4_if_fn_do.rs
Normal file
@ -0,0 +1,236 @@
|
||||
// support precompiled regexes in reader.rs
|
||||
#![feature(phase)]
|
||||
#[phase(plugin)]
|
||||
extern crate regex_macros;
|
||||
extern crate regex;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use types::{MalVal,MalRet,MalFunc,MalFuncData,
|
||||
Nil,False,Sym,List,Vector,Func};
|
||||
use env::{Env,env_new,env_bind,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 eval_ast(ast: MalVal, env: Env) -> MalRet {
|
||||
let ast2 = ast.clone();
|
||||
match *ast2 {
|
||||
//match *ast {
|
||||
Sym(ref sym) => {
|
||||
env_get(env.clone(), sym.clone())
|
||||
},
|
||||
List(ref a) => {
|
||||
let mut ast_vec : Vec<MalVal> = vec![];
|
||||
for mv in a.iter() {
|
||||
let mv2 = mv.clone();
|
||||
match eval(mv2, env.clone()) {
|
||||
Ok(mv) => { ast_vec.push(mv); },
|
||||
Err(e) => { return Err(e); },
|
||||
}
|
||||
}
|
||||
Ok(Rc::new(List(ast_vec)))
|
||||
},
|
||||
_ => {
|
||||
Ok(ast)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn eval(ast: MalVal, env: Env) -> MalRet {
|
||||
//println!("eval: {}, {}", ast, env.borrow());
|
||||
//println!("eval: {}", ast);
|
||||
let ast2 = ast.clone();
|
||||
match *ast2 {
|
||||
List(_) => (), // continue
|
||||
_ => return eval_ast(ast2, env),
|
||||
}
|
||||
|
||||
// apply list
|
||||
match *ast2 {
|
||||
List(ref args) => {
|
||||
if args.len() == 0 {
|
||||
return Ok(ast);
|
||||
}
|
||||
let ref a0 = *args[0];
|
||||
match *a0 {
|
||||
Sym(ref a0sym) => {
|
||||
match a0sym.as_slice() {
|
||||
"def!" => {
|
||||
let a1 = (*args)[1].clone();
|
||||
let a2 = (*args)[2].clone();
|
||||
let res = eval(a2, env.clone());
|
||||
match res {
|
||||
Ok(r) => {
|
||||
match *a1 {
|
||||
Sym(ref s) => {
|
||||
env_set(&env.clone(), s.clone(), r.clone());
|
||||
return Ok(r);
|
||||
},
|
||||
_ => {
|
||||
return Err("def! of non-symbol".to_string())
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
},
|
||||
"let*" => {
|
||||
let let_env = env_new(Some(env.clone()));
|
||||
let a1 = (*args)[1].clone();
|
||||
let a2 = (*args)[2].clone();
|
||||
match *a1 {
|
||||
List(ref binds) | Vector(ref binds) => {
|
||||
let mut it = binds.iter();
|
||||
while it.len() >= 2 {
|
||||
let b = it.next().unwrap();
|
||||
let exp = it.next().unwrap();
|
||||
match **b {
|
||||
Sym(ref bstr) => {
|
||||
match eval(exp.clone(), let_env.clone()) {
|
||||
Ok(r) => {
|
||||
env_set(&let_env, bstr.clone(), r);
|
||||
},
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
},
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err("let* with non-symbol binding".to_string());
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => return Err("let* with non-list bindings".to_string()),
|
||||
}
|
||||
return eval(a2, let_env.clone());
|
||||
},
|
||||
"do" => {
|
||||
let el = Rc::new(List(args.slice(1,args.len()).to_vec()));
|
||||
match eval_ast(el, env.clone()) {
|
||||
Err(e) => return Err(e),
|
||||
Ok(el) => {
|
||||
match *el {
|
||||
List(ref lst) => {
|
||||
let ref last = lst[lst.len()-1];
|
||||
return Ok(last.clone());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"if" => {
|
||||
let a1 = (*args)[1].clone();
|
||||
let cond = eval(a1, env.clone());
|
||||
if cond.is_err() { return cond; }
|
||||
match *cond.unwrap() {
|
||||
False | Nil => {
|
||||
if args.len() >= 4 {
|
||||
let a3 = (*args)[3].clone();
|
||||
return eval(a3, env.clone());
|
||||
} else {
|
||||
return Ok(Rc::new(Nil));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
let a2 = (*args)[2].clone();
|
||||
return eval(a2, env.clone());
|
||||
},
|
||||
}
|
||||
},
|
||||
"fn*" => {
|
||||
let a1 = (*args)[1].clone();
|
||||
let a2 = (*args)[2].clone();
|
||||
return Ok(Rc::new(MalFunc(MalFuncData{
|
||||
exp: a2,
|
||||
env: env.clone(),
|
||||
params: a1})));
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
// function call
|
||||
match eval_ast(ast, env.clone()) {
|
||||
Err(e) => Err(e),
|
||||
Ok(el) => {
|
||||
match *el {
|
||||
List(ref args) => {
|
||||
// TODO: make this work
|
||||
//match args.as_slice() {
|
||||
// [&Func(f), rest..] => {
|
||||
// (*f)(rest.to_vec())
|
||||
// },
|
||||
// _ => Err("attempt to call non-function".to_string()),
|
||||
//}
|
||||
let args2 = args.clone();
|
||||
match *args2[0] {
|
||||
Func(f) => f(args.slice(1,args.len()).to_vec()),
|
||||
MalFunc(ref mf) => {
|
||||
let mfc = mf.clone();
|
||||
let alst = List(args.slice(1,args.len()).to_vec());
|
||||
let new_env = env_new(Some(mfc.env.clone()));
|
||||
match env_bind(&new_env, mfc.params,
|
||||
Rc::new(alst)) {
|
||||
Ok(_) => return eval(mfc.exp, new_env),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
},
|
||||
_ => Err("attempt to call non-function".to_string()),
|
||||
}
|
||||
}
|
||||
_ => Err("Invalid apply".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Err("Expected list".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
// print
|
||||
fn print(exp: MalVal) -> String {
|
||||
exp.pr_str(true)
|
||||
}
|
||||
|
||||
fn rep(str: String, env: Env) -> Result<String,String> {
|
||||
match read(str) {
|
||||
Err(e) => Err(e),
|
||||
Ok(ast) => {
|
||||
//println!("read: {}", ast);
|
||||
match eval(ast, env) {
|
||||
Err(e) => Err(e),
|
||||
Ok(exp) => Ok(print(exp)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let repl_env = env_new(None);
|
||||
for (k, v) in core::ns().into_iter() { env_set(&repl_env, k, v); }
|
||||
|
||||
let _ = rep("(def! not (fn* (a) (if a false true)))".to_string(),
|
||||
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(str) => println!("Error: {}", str),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
use std::rc::Rc;
|
||||
use std::collections;
|
||||
use std::fmt;
|
||||
use super::printer::escape_str;
|
||||
use super::printer::{escape_str,pr_list};
|
||||
use super::env::Env;
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub enum MalType {
|
||||
@ -17,12 +18,20 @@ pub enum MalType {
|
||||
Func(fn(Vec<MalVal>) -> MalRet),
|
||||
//Func(fn(&[MalVal]) -> MalRet),
|
||||
//Func(|Vec<MalVal>|:'a -> MalRet),
|
||||
MalFunc(MalFuncData),
|
||||
}
|
||||
|
||||
pub type MalVal = Rc<MalType>;
|
||||
|
||||
pub type MalRet = Result<MalVal,String>;
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct MalFuncData {
|
||||
pub exp: MalVal,
|
||||
pub env: Env,
|
||||
pub params: MalVal,
|
||||
}
|
||||
|
||||
|
||||
impl MalType {
|
||||
pub fn pr_str(&self, print_readably: bool) -> String {
|
||||
@ -40,49 +49,61 @@ impl MalType {
|
||||
} else {
|
||||
res.push_str(v.as_slice())
|
||||
}
|
||||
}
|
||||
},
|
||||
List(ref v) => {
|
||||
res = pr_list(v, _r, "(", ")", " ")
|
||||
},
|
||||
Vector(ref v) => {
|
||||
res = pr_list(v, _r, "[", "]", " ")
|
||||
},
|
||||
HashMap(ref v) => {
|
||||
let mut first = true;
|
||||
res.push_str("(");
|
||||
for item in v.iter() {
|
||||
res.push_str("{");
|
||||
for (key, value) in v.iter() {
|
||||
if first { first = false; } else { res.push_str(" "); }
|
||||
res.push_str(item.pr_str(_r).as_slice());
|
||||
res.push_str(key.as_slice());
|
||||
res.push_str(" ");
|
||||
res.push_str(value.pr_str(_r).as_slice());
|
||||
}
|
||||
res.push_str(")")
|
||||
}
|
||||
// TODO: better function representation
|
||||
res.push_str("}")
|
||||
},
|
||||
// TODO: better native function representation
|
||||
//Func(ref v) => {
|
||||
Func(_) => {
|
||||
res.push_str(format!("#<function ...>").as_slice())
|
||||
}
|
||||
},
|
||||
MalFunc(ref mf) => {
|
||||
res.push_str(format!("(fn* {} {})", mf.params, mf.exp).as_slice())
|
||||
},
|
||||
/*
|
||||
Vector(ref v) => {
|
||||
let mut first = true;
|
||||
write!(f, "[");
|
||||
for item in v.iter() {
|
||||
if first { first = false; } else { write!(f, " ") }
|
||||
item.fmt(f);
|
||||
}
|
||||
write!(f, "]");
|
||||
}
|
||||
Hash_Map(ref v) => {
|
||||
let mut first = true;
|
||||
write!(f, "{}", "{");
|
||||
for (key, value) in v.iter() {
|
||||
if first { first = false; } else { write!(f, " ") }
|
||||
write!(f, "\"{}\"", *key);
|
||||
write!(f, " ");
|
||||
value.fmt(f);
|
||||
}
|
||||
write!(f, "{}", "}");
|
||||
}
|
||||
|
||||
// Atom(ref v) => v.fmt(f),
|
||||
*/
|
||||
_ => { res.push_str("#<unknown type>") }
|
||||
//_ => { res.push_str("#<unknown type>") },
|
||||
};
|
||||
res
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl PartialEq for MalType {
|
||||
fn eq(&self, other: &MalType) -> bool {
|
||||
match (self, other) {
|
||||
(&Nil, &Nil) |
|
||||
(&True, &True) |
|
||||
(&False, &False) => true,
|
||||
(&Int(ref a), &Int(ref b)) => a == b,
|
||||
(&Strn(ref a), &Strn(ref b)) => a == b,
|
||||
(&Sym(ref a), &Sym(ref b)) => a == b,
|
||||
(&List(ref a), &List(ref b)) |
|
||||
(&Vector(ref a), &Vector(ref b)) => a == b,
|
||||
(&HashMap(ref a), &HashMap(ref b)) => a == b,
|
||||
// TODO: fix this
|
||||
(&Func(_), &Func(_)) => false,
|
||||
(&MalFunc(_), &MalFunc(_)) => false,
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Show for MalType {
|
||||
|
Loading…
Reference in New Issue
Block a user