feat: if statements

This commit is contained in:
Roman Godmaire 2024-02-16 08:13:10 -05:00
parent bd12bd998b
commit f93baad338
2 changed files with 40 additions and 20 deletions

View file

@ -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()

View file

@ -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();