feat: if statements
This commit is contained in:
parent
bd12bd998b
commit
f93baad338
2 changed files with 40 additions and 20 deletions
|
@ -40,8 +40,7 @@ pub fn core_environment() -> Rc<Environment> {
|
|||
.unwrap_or(Rc::new(Expression::Int(0)));
|
||||
|
||||
Ok(res)
|
||||
})
|
||||
.into(),
|
||||
}),
|
||||
),
|
||||
(
|
||||
"-".to_string(),
|
||||
|
@ -57,8 +56,7 @@ pub fn core_environment() -> Rc<Environment> {
|
|||
.unwrap_or(Rc::new(Expression::Int(0)));
|
||||
|
||||
Ok(res)
|
||||
})
|
||||
.into(),
|
||||
}),
|
||||
),
|
||||
(
|
||||
"*".to_string(),
|
||||
|
@ -74,8 +72,7 @@ pub fn core_environment() -> Rc<Environment> {
|
|||
.unwrap_or(Rc::new(Expression::Int(0)));
|
||||
|
||||
Ok(res)
|
||||
})
|
||||
.into(),
|
||||
}),
|
||||
),
|
||||
(
|
||||
"/".to_string(),
|
||||
|
@ -91,13 +88,12 @@ pub fn core_environment() -> Rc<Environment> {
|
|||
.unwrap_or(Rc::new(Expression::Int(0)));
|
||||
|
||||
Ok(res)
|
||||
})
|
||||
.into(),
|
||||
}),
|
||||
),
|
||||
// Collections
|
||||
(
|
||||
"vector".to_string(),
|
||||
Expression::NativeFunc(|args| Ok(Rc::new(Expression::Vector(args)))).into(),
|
||||
Expression::NativeFunc(|args| Ok(Rc::new(Expression::Vector(args)))),
|
||||
),
|
||||
(
|
||||
"hashmap".to_string(),
|
||||
|
@ -121,8 +117,26 @@ pub fn core_environment() -> Rc<Environment> {
|
|||
.collect();
|
||||
|
||||
Ok(Rc::new(Expression::HashMap(res)))
|
||||
})
|
||||
.into(),
|
||||
}),
|
||||
),
|
||||
// Branching
|
||||
(
|
||||
"if".to_string(),
|
||||
Expression::NativeFunc(|args| {
|
||||
if args.len() != 3 {
|
||||
Err(Error::MismatchedArgCount)?
|
||||
}
|
||||
|
||||
let (cond, consequence, alternative) =
|
||||
(args[0].clone(), args[1].clone(), args[2].clone());
|
||||
|
||||
// If the value is anything other than true or nil, then we return the alternative
|
||||
if *cond == Expression::Boolean(true) || *cond == Expression::Nil {
|
||||
return Ok(consequence);
|
||||
};
|
||||
|
||||
Ok(alternative)
|
||||
}),
|
||||
),
|
||||
// Environment Manipulation
|
||||
(
|
||||
|
@ -143,8 +157,7 @@ pub fn core_environment() -> Rc<Environment> {
|
|||
env.set(key, val.clone());
|
||||
|
||||
Ok(val)
|
||||
})
|
||||
.into(),
|
||||
}),
|
||||
),
|
||||
(
|
||||
"let*".to_string(),
|
||||
|
@ -173,13 +186,14 @@ pub fn core_environment() -> Rc<Environment> {
|
|||
};
|
||||
|
||||
eval_ast_node(Rc::new(new_env), args.next().unwrap())
|
||||
})
|
||||
.into(),
|
||||
}),
|
||||
),
|
||||
];
|
||||
]
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, Rc::new(v)));
|
||||
|
||||
Environment {
|
||||
current: RefCell::new(env.into()),
|
||||
current: RefCell::new(HashMap::from_iter(env)),
|
||||
outer: None,
|
||||
}
|
||||
.into()
|
||||
|
|
|
@ -68,8 +68,8 @@ impl std::fmt::Display for Expression {
|
|||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error("could not find symbol in environment")]
|
||||
NotInEnv,
|
||||
#[error("could not find symbol '{0}' in environment")]
|
||||
NotInEnv(String),
|
||||
#[error("expression does not have a valid operator")]
|
||||
InvalidOperator,
|
||||
#[error("expected symbol")]
|
||||
|
@ -112,7 +112,7 @@ fn eval_ast_node(env: Rc<Environment>, ast_node: Node) -> Result<Rc<Expression>>
|
|||
_ => Err(Error::InvalidOperator)?,
|
||||
}
|
||||
}
|
||||
Node::Symbol(sym) => env.get(&sym).ok_or(Error::NotInEnv)?.to_owned(),
|
||||
Node::Symbol(sym) => env.get(&sym).ok_or(Error::NotInEnv(sym))?.to_owned(),
|
||||
|
||||
Node::Int(i) => Expression::Int(i).into(),
|
||||
Node::Keyword(val) => Expression::Keyword(val).into(),
|
||||
|
@ -161,6 +161,12 @@ mod test {
|
|||
// Environment manipulation
|
||||
#[case("(define! asdf (+ 2 2)) (+ asdf 2)", "4\n6")]
|
||||
#[case("(let* (a 2) (+ a 2))", "4")]
|
||||
// If-else
|
||||
#[case("(if true true false)", "true")]
|
||||
#[case("(if nil true false)", "true")]
|
||||
#[case("(if false true false)", "false")]
|
||||
#[case("(if 4 true false)", "false")]
|
||||
#[case("(if \"blue\" true false)", "false")]
|
||||
fn test_evaluator(#[case] input: &str, #[case] expected: &str) {
|
||||
let env = core_environment();
|
||||
let tokens = lexer::read(input).unwrap();
|
||||
|
|
Loading…
Reference in a new issue