use std::str::FromStr; #[derive(PartialEq, Debug, Clone, Copy)] pub enum Op { Add, Sub, Mul, Div, Modulo, Equals, Greater, GrEqTo, Less, LsEqTo, Define, } impl FromStr for Op { type Err = String; fn from_str(s: &str) -> Result { match s { "+" => Ok(Op::Add), "-" => Ok(Op::Sub), "*" => Ok(Op::Mul), "/" => Ok(Op::Div), "%" => Ok(Op::Modulo), "=" => Ok(Op::Equals), ">" => Ok(Op::Greater), ">=" => Ok(Op::GrEqTo), "<" => Ok(Op::Less), "<=" => Ok(Op::LsEqTo), "define" => Ok(Op::Define), x => Err(format!("{} is not an operator", x)) } } } #[derive(PartialEq, Debug, Clone)] pub enum Number { Int(isize), Float(f32) } #[derive(PartialEq, Debug, Clone)] pub enum Type { Bool(bool), Number(Number), Str(String), Symbol(String), Operator(Op), } #[derive(PartialEq, Debug)] pub enum SEXP { Atom(Type), Sexpr(Vec) } #[test] fn construct() { let atom1 = SEXP::Atom(Type::Number(Number::Int(1))); let atom2 = SEXP::Atom(Type::Number(Number::Int(2))); let atom3 = SEXP::Atom(Type::Number(Number::Int(3))); let atom4 = SEXP::Atom(Type::Number(Number::Int(4))); let sexp = SEXP::Sexpr(vec!(atom1, atom2, atom3, atom4)); match sexp { SEXP::Sexpr(ref x) => { assert_eq!(x[0], SEXP::Atom(Type::Number(Number::Int(1)))); }, _ => panic!("What") } } #[test] fn mutability() { let atom1 = SEXP::Atom(Type::Number(Number::Int(1))); let atom2 = SEXP::Atom(Type::Number(Number::Int(2))); let atom3 = SEXP::Atom(Type::Number(Number::Int(3))); let atom4 = SEXP::Atom(Type::Number(Number::Int(4))); let mut sexp = SEXP::Sexpr(vec!(atom1, atom2, atom3, atom4)); match sexp { SEXP::Sexpr(ref mut x) => match x[0] { SEXP::Atom(Type::Number(Number::Int(ref mut x))) => *x += 7, _ => panic!("What") }, _ => panic!("What") } match sexp { SEXP::Sexpr(ref x) => { assert_eq!(x[0], SEXP::Atom(Type::Number(Number::Int(8)))); }, _ => panic!("What") } }