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)));
|
.unwrap_or(Rc::new(Expression::Int(0)));
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
})
|
}),
|
||||||
.into(),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"-".to_string(),
|
"-".to_string(),
|
||||||
|
@ -57,8 +56,7 @@ pub fn core_environment() -> Rc<Environment> {
|
||||||
.unwrap_or(Rc::new(Expression::Int(0)));
|
.unwrap_or(Rc::new(Expression::Int(0)));
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
})
|
}),
|
||||||
.into(),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"*".to_string(),
|
"*".to_string(),
|
||||||
|
@ -74,8 +72,7 @@ pub fn core_environment() -> Rc<Environment> {
|
||||||
.unwrap_or(Rc::new(Expression::Int(0)));
|
.unwrap_or(Rc::new(Expression::Int(0)));
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
})
|
}),
|
||||||
.into(),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"/".to_string(),
|
"/".to_string(),
|
||||||
|
@ -91,13 +88,12 @@ pub fn core_environment() -> Rc<Environment> {
|
||||||
.unwrap_or(Rc::new(Expression::Int(0)));
|
.unwrap_or(Rc::new(Expression::Int(0)));
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
})
|
}),
|
||||||
.into(),
|
|
||||||
),
|
),
|
||||||
// Collections
|
// Collections
|
||||||
(
|
(
|
||||||
"vector".to_string(),
|
"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(),
|
"hashmap".to_string(),
|
||||||
|
@ -121,8 +117,26 @@ pub fn core_environment() -> Rc<Environment> {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(Rc::new(Expression::HashMap(res)))
|
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
|
// Environment Manipulation
|
||||||
(
|
(
|
||||||
|
@ -143,8 +157,7 @@ pub fn core_environment() -> Rc<Environment> {
|
||||||
env.set(key, val.clone());
|
env.set(key, val.clone());
|
||||||
|
|
||||||
Ok(val)
|
Ok(val)
|
||||||
})
|
}),
|
||||||
.into(),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"let*".to_string(),
|
"let*".to_string(),
|
||||||
|
@ -173,13 +186,14 @@ pub fn core_environment() -> Rc<Environment> {
|
||||||
};
|
};
|
||||||
|
|
||||||
eval_ast_node(Rc::new(new_env), args.next().unwrap())
|
eval_ast_node(Rc::new(new_env), args.next().unwrap())
|
||||||
})
|
}),
|
||||||
.into(),
|
|
||||||
),
|
),
|
||||||
];
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (k, Rc::new(v)));
|
||||||
|
|
||||||
Environment {
|
Environment {
|
||||||
current: RefCell::new(env.into()),
|
current: RefCell::new(HashMap::from_iter(env)),
|
||||||
outer: None,
|
outer: None,
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
|
|
|
@ -68,8 +68,8 @@ impl std::fmt::Display for Expression {
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("could not find symbol in environment")]
|
#[error("could not find symbol '{0}' in environment")]
|
||||||
NotInEnv,
|
NotInEnv(String),
|
||||||
#[error("expression does not have a valid operator")]
|
#[error("expression does not have a valid operator")]
|
||||||
InvalidOperator,
|
InvalidOperator,
|
||||||
#[error("expected symbol")]
|
#[error("expected symbol")]
|
||||||
|
@ -112,7 +112,7 @@ fn eval_ast_node(env: Rc<Environment>, ast_node: Node) -> Result<Rc<Expression>>
|
||||||
_ => Err(Error::InvalidOperator)?,
|
_ => 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::Int(i) => Expression::Int(i).into(),
|
||||||
Node::Keyword(val) => Expression::Keyword(val).into(),
|
Node::Keyword(val) => Expression::Keyword(val).into(),
|
||||||
|
@ -161,6 +161,12 @@ mod test {
|
||||||
// Environment manipulation
|
// Environment manipulation
|
||||||
#[case("(define! asdf (+ 2 2)) (+ asdf 2)", "4\n6")]
|
#[case("(define! asdf (+ 2 2)) (+ asdf 2)", "4\n6")]
|
||||||
#[case("(let* (a 2) (+ a 2))", "4")]
|
#[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) {
|
fn test_evaluator(#[case] input: &str, #[case] expected: &str) {
|
||||||
let env = core_environment();
|
let env = core_environment();
|
||||||
let tokens = lexer::read(input).unwrap();
|
let tokens = lexer::read(input).unwrap();
|
||||||
|
|
Loading…
Reference in a new issue