add lisp prelude_let
This commit is contained in:
parent
43ac1cc829
commit
d604dcecc5
@ -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> {
|
impl<'a> Environment<'a> {
|
||||||
/// Construct an empty `Environment`.
|
/// Construct an empty `Environment`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use super::environment::{Environment, EnvironmentLayer};
|
use super::environment::{Environment, EnvironmentLayer};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
/// A sum type of all possible lisp expressions.
|
/// 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)),
|
a => Err(EvalError::NotAFunction(a)),
|
||||||
},
|
},
|
||||||
Expression::Quote(e) => Ok(*e),
|
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),
|
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> {
|
fn prelude_if(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||||
let [predicate, e_then, e_else] = expr.try_into()?;
|
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_eq));
|
||||||
prelude.set("<".to_string(), Expression::Function(prelude_lt));
|
prelude.set("<".to_string(), Expression::Function(prelude_lt));
|
||||||
prelude.set(">".to_string(), Expression::Function(prelude_gt));
|
prelude.set(">".to_string(), Expression::Function(prelude_gt));
|
||||||
|
prelude.set("let".to_string(), Expression::Function(prelude_let));
|
||||||
|
|
||||||
eval(&prelude, expr)
|
eval(&prelude, expr)
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/main.rs
13
src/main.rs
@ -38,8 +38,17 @@ fn main() {
|
|||||||
.into(),
|
.into(),
|
||||||
]
|
]
|
||||||
.into(),
|
.into(),
|
||||||
Expression::Integer(4),
|
Expression::Integer(5),
|
||||||
Expression::Integer(7),
|
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();
|
.into();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user