add lisp prelude_let

This commit is contained in:
Jonas Röger 2024-11-05 17:56:55 +01:00
parent 43ac1cc829
commit d604dcecc5
Signed by: jonas
GPG Key ID: 4000EB35E1AE0F07
3 changed files with 42 additions and 3 deletions

View File

@ -36,6 +36,12 @@ impl EnvironmentLayer {
}
}
impl From<HashMap<String, Expression>> for EnvironmentLayer {
fn from(map: HashMap<String, Expression>) -> Self {
EnvironmentLayer { symbols: map }
}
}
impl<'a> Environment<'a> {
/// Construct an empty `Environment`.
pub fn new() -> Self {

View File

@ -1,4 +1,5 @@
use super::environment::{Environment, EnvironmentLayer};
use std::collections::HashMap;
#[derive(Clone, Debug, PartialEq, PartialOrd)]
/// A sum type of all possible lisp expressions.
@ -175,7 +176,10 @@ fn eval(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
a => Err(EvalError::NotAFunction(a)),
},
Expression::Quote(e) => Ok(*e),
Expression::Symbol(s) => env.get(&s).ok_or(EvalError::SymbolNotBound(s)).cloned(),
Expression::Symbol(s) => eval(
env,
env.get(&s).ok_or(EvalError::SymbolNotBound(s)).cloned()?,
),
x => Ok(x),
}
}
@ -207,6 +211,25 @@ fn prelude_lambda(_env: &Environment, expr: Expression) -> Result<Expression, Ev
})
}
fn prelude_let(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
let [bindings, body] = expr.try_into()?;
let bindings = CellIterator::new(bindings)
.map(|e| {
let (s, e) = e?.try_into()?;
if let Expression::Symbol(s) = s {
Ok((s, eval(env, e)?))
} else {
Err(EvalError::ArgumentError(
"Let bindings must be an alist with elements (symbol . expr)".to_string(),
))
}
})
.collect::<Result<HashMap<String, Expression>, EvalError>>()?;
eval(&env.overlay(bindings.into()), body)
}
fn prelude_if(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
let [predicate, e_then, e_else] = expr.try_into()?;
@ -260,6 +283,7 @@ pub fn eval_prelude(expr: Expression) -> Result<Expression, EvalError> {
prelude.set("==".to_string(), Expression::Function(prelude_eq));
prelude.set("<".to_string(), Expression::Function(prelude_lt));
prelude.set(">".to_string(), Expression::Function(prelude_gt));
prelude.set("let".to_string(), Expression::Function(prelude_let));
eval(&prelude, expr)
}

View File

@ -38,8 +38,17 @@ fn main() {
.into(),
]
.into(),
Expression::Integer(4),
Expression::Integer(7),
Expression::Integer(5),
vec![
Expression::Symbol("let".to_string()),
vec![Expression::Cell(
Box::new(Expression::Symbol("y".to_string())),
Box::new(Expression::Integer(7)),
)]
.into(),
Expression::Symbol("y".to_string()),
]
.into(),
]
.into();