feat: add shared environment/set
This commit is contained in:
parent
5de2230fec
commit
b51e185c21
@ -1,5 +1,10 @@
|
||||
use super::expression::Expression;
|
||||
use std::collections::HashMap;
|
||||
use super::{expression::Expression, prelude::mk_prelude};
|
||||
use std::{
|
||||
borrow::BorrowMut,
|
||||
cell::{RefCell, RefMut},
|
||||
collections::HashMap,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
/// A Environment is a stack of `EnvironmentLayer`s. Each `EnvironmentLayer` is a mapping from
|
||||
@ -9,6 +14,8 @@ pub struct Environment<'a> {
|
||||
layer: EnvironmentLayer,
|
||||
/// The outer _fallback_ mapping.
|
||||
outer: Option<&'a Environment<'a>>,
|
||||
/// A shared layer taking precendence over the outer layer, but not the current layer.
|
||||
shared: Rc<RefCell<EnvironmentLayer>>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
@ -31,8 +38,8 @@ impl EnvironmentLayer {
|
||||
}
|
||||
|
||||
/// Get a value in the `EnvironmentLayer`.
|
||||
pub fn get(&self, key: &str) -> Option<&Expression> {
|
||||
self.symbols.get(key)
|
||||
pub fn get(&self, key: &str) -> Option<Expression> {
|
||||
self.symbols.get(key).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,12 +55,17 @@ impl<'a> Environment<'a> {
|
||||
Environment {
|
||||
layer: EnvironmentLayer::new(),
|
||||
outer: None,
|
||||
shared: Rc::new(RefCell::new(EnvironmentLayer::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct an `Environment` from a `EnvironmentLayer` with no outer `Environment`.
|
||||
pub fn from_layer(layer: EnvironmentLayer) -> Self {
|
||||
Environment { layer, outer: None }
|
||||
Environment {
|
||||
layer,
|
||||
outer: None,
|
||||
shared: Rc::new(RefCell::new(EnvironmentLayer::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a new `Environment` with `self` as the outer `Environment`.
|
||||
@ -61,6 +73,7 @@ impl<'a> Environment<'a> {
|
||||
Environment {
|
||||
layer: EnvironmentLayer::new(),
|
||||
outer: Some(self),
|
||||
shared: self.shared.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,15 +82,43 @@ impl<'a> Environment<'a> {
|
||||
Environment {
|
||||
layer,
|
||||
outer: Some(&self),
|
||||
shared: Rc::new(RefCell::new(EnvironmentLayer::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a value in the shared layer.
|
||||
///
|
||||
/// Panics:
|
||||
/// - if the shared layer cannot be borrowed mutably.
|
||||
pub fn shared_set(&self, key: String, value: Expression) {
|
||||
match self.shared.try_borrow_mut() {
|
||||
Ok(mut shared) => shared.set(key, value),
|
||||
Err(e) => panic!("Cannot borrow shared layer mutably. ({})", e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a value from the shared layer.
|
||||
pub fn shared_get(&self, key: &str) -> Option<Expression> {
|
||||
self.shared.borrow().get(key)
|
||||
}
|
||||
|
||||
/// Get a value from the `Environment`, without looking at the shared layer.
|
||||
pub fn layer_get(&self, key: &str) -> Option<Expression> {
|
||||
if let Some(e) = self.layer.get(key) {
|
||||
Some(e)
|
||||
} else {
|
||||
self.outer?.layer_get(key).clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a value from the `Environment`.
|
||||
pub fn get(&self, key: &str) -> Option<&Expression> {
|
||||
pub fn get(&self, key: &str) -> Option<Expression> {
|
||||
if let Some(e) = self.layer.get(key) {
|
||||
Some(e)
|
||||
} else if let Some(e) = self.shared_get(key) {
|
||||
Some(e)
|
||||
} else {
|
||||
self.outer?.get(key)
|
||||
self.outer?.layer_get(key).clone()
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,6 +128,19 @@ impl<'a> Environment<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Environment<'_> {
|
||||
/// Get the default prelude layer
|
||||
fn default() -> Self {
|
||||
let mut prelude = EnvironmentLayer::new();
|
||||
mk_prelude(&mut prelude);
|
||||
Environment {
|
||||
layer: prelude,
|
||||
outer: None,
|
||||
shared: Rc::new(RefCell::new(EnvironmentLayer::new())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_environment() {
|
||||
let mut env = Environment::new();
|
||||
@ -94,9 +148,9 @@ fn test_environment() {
|
||||
env.set("b".to_string(), Expression::Integer(2));
|
||||
let mut inner = env.mk_inner();
|
||||
inner.set("a".to_string(), Expression::Integer(3));
|
||||
assert_eq!(inner.get("a"), Some(&Expression::Integer(3)));
|
||||
assert_eq!(inner.get("b"), Some(&Expression::Integer(2)));
|
||||
assert_eq!(env.get("a"), Some(&Expression::Integer(1)));
|
||||
assert_eq!(env.get("b"), Some(&Expression::Integer(2)));
|
||||
assert_eq!(inner.get("a"), Some(Expression::Integer(3)));
|
||||
assert_eq!(inner.get("b"), Some(Expression::Integer(2)));
|
||||
assert_eq!(env.get("a"), Some(Expression::Integer(1)));
|
||||
assert_eq!(env.get("b"), Some(Expression::Integer(2)));
|
||||
assert_eq!(env.get("c"), None);
|
||||
}
|
||||
|
||||
94
src/lisp/eval.rs
Normal file
94
src/lisp/eval.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use super::environment::Environment;
|
||||
use super::environment::EnvironmentLayer;
|
||||
use super::expression::Expression;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// All possible evaluation errors
|
||||
pub enum EvalError {
|
||||
SymbolNotBound(String),
|
||||
NotAFunction(Expression),
|
||||
NotANumber(Expression),
|
||||
ArgumentError(String),
|
||||
TypeError(String),
|
||||
NotASymbol(Expression),
|
||||
}
|
||||
|
||||
/// A CellIterator is a convenience struct to iterate a linked cons list.
|
||||
/// The Iterator returns Ok(Expression) as long, as there are elements in the list.
|
||||
/// Err(EvalError) is returned when the right side of a cons cell is not another cons cell or nil.
|
||||
pub struct CellIterator {
|
||||
expr: Option<Expression>,
|
||||
}
|
||||
|
||||
impl CellIterator {
|
||||
pub fn new(expr: Expression) -> CellIterator {
|
||||
CellIterator { expr: Some(expr) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for CellIterator {
|
||||
type Item = Result<Expression, EvalError>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(expr) = self.expr.take() {
|
||||
match expr {
|
||||
Expression::Cell(head, tail) => {
|
||||
self.expr = Some(*tail);
|
||||
return Some(Ok(*head));
|
||||
}
|
||||
Expression::Nil => {
|
||||
return None;
|
||||
}
|
||||
_ => {
|
||||
return Some(Err(EvalError::TypeError(
|
||||
"Expected a cell or nil".to_string(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Dispatch an anonymous function call. Evaluates `body` in `env`, binding `args` to `argument_symbols`
|
||||
fn dispatch_anonymous_function(
|
||||
env: &Environment,
|
||||
argument_symbols: Vec<String>,
|
||||
body: Expression,
|
||||
args: Expression,
|
||||
) -> Result<Expression, EvalError> {
|
||||
let mut args: Vec<Expression> = args.try_into()?;
|
||||
|
||||
let mut overlay = EnvironmentLayer::new();
|
||||
|
||||
if args.len() != argument_symbols.len() {
|
||||
return Err(EvalError::ArgumentError(format!(
|
||||
"Exprected {} arguments, got {}",
|
||||
argument_symbols.len(),
|
||||
args.len()
|
||||
)));
|
||||
}
|
||||
|
||||
for (arg, symbol) in args.iter_mut().zip(argument_symbols.iter()) {
|
||||
overlay.set(symbol.to_owned(), arg.to_owned());
|
||||
}
|
||||
|
||||
eval(&env.overlay(overlay), body)
|
||||
}
|
||||
|
||||
/// Evaluate an expression inside an environment
|
||||
pub fn eval(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
match expr {
|
||||
Expression::Cell(lhs, rhs) => match eval(env, *lhs)? {
|
||||
Expression::Function(f) => f(env, *rhs),
|
||||
Expression::AnonymousFunction {
|
||||
argument_symbols,
|
||||
body,
|
||||
} => dispatch_anonymous_function(env, argument_symbols, *body, *rhs),
|
||||
a => Err(EvalError::NotAFunction(a)),
|
||||
},
|
||||
Expression::Quote(e) => Ok(*e),
|
||||
Expression::Symbol(s) => eval(env, env.get(&s).ok_or(EvalError::SymbolNotBound(s))?),
|
||||
x => Ok(x),
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
use super::environment::{Environment, EnvironmentLayer};
|
||||
use std::collections::HashMap;
|
||||
use super::environment::Environment;
|
||||
use super::eval::CellIterator;
|
||||
use super::eval::EvalError;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
/// A sum type of all possible lisp expressions.
|
||||
@ -29,54 +30,6 @@ pub enum Expression {
|
||||
Nil,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// All possible evaluation errors
|
||||
pub enum EvalError {
|
||||
SymbolNotBound(String),
|
||||
NotAFunction(Expression),
|
||||
NotANumber(Expression),
|
||||
ArgumentError(String),
|
||||
TypeError(String),
|
||||
NotASymbol(Expression),
|
||||
}
|
||||
|
||||
/// A CellIterator is a convenience struct to iterate a linked cons list.
|
||||
/// The Iterator returns Ok(Expression) as long, as there are elements in the list.
|
||||
/// Err(EvalError) is returned when the right side of a cons cell is not another cons cell or nil.
|
||||
pub struct CellIterator {
|
||||
expr: Option<Expression>,
|
||||
}
|
||||
|
||||
impl CellIterator {
|
||||
pub fn new(expr: Expression) -> CellIterator {
|
||||
CellIterator { expr: Some(expr) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for CellIterator {
|
||||
type Item = Result<Expression, EvalError>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(expr) = self.expr.take() {
|
||||
match expr {
|
||||
Expression::Cell(head, tail) => {
|
||||
self.expr = Some(*tail);
|
||||
return Some(Ok(*head));
|
||||
}
|
||||
Expression::Nil => {
|
||||
return None;
|
||||
}
|
||||
_ => {
|
||||
return Some(Err(EvalError::TypeError(
|
||||
"Expected a cell or nil".to_string(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<fn(&Environment, Expression) -> Result<Expression, EvalError>> for Expression {
|
||||
fn from(f: fn(&Environment, Expression) -> Result<Expression, EvalError>) -> Self {
|
||||
Expression::Function(f)
|
||||
@ -138,219 +91,3 @@ impl TryInto<(Expression, Expression)> for Expression {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Dispatch an anonymous function call. Evaluates `body` in `env`, binding `args` to `argument_symbols`
|
||||
fn dispatch_anonymous_function(
|
||||
env: &Environment,
|
||||
argument_symbols: Vec<String>,
|
||||
body: Expression,
|
||||
args: Expression,
|
||||
) -> Result<Expression, EvalError> {
|
||||
let mut args: Vec<Expression> = args.try_into()?;
|
||||
|
||||
let mut overlay = EnvironmentLayer::new();
|
||||
|
||||
if args.len() != argument_symbols.len() {
|
||||
return Err(EvalError::ArgumentError(format!(
|
||||
"Exprected {} arguments, got {}",
|
||||
argument_symbols.len(),
|
||||
args.len()
|
||||
)));
|
||||
}
|
||||
|
||||
for (arg, symbol) in args.iter_mut().zip(argument_symbols.iter()) {
|
||||
overlay.set(symbol.to_owned(), arg.to_owned());
|
||||
}
|
||||
|
||||
eval(&env.overlay(overlay), body)
|
||||
}
|
||||
|
||||
/// Evaluate an expression inside an environment
|
||||
fn eval(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
match expr {
|
||||
Expression::Cell(lhs, rhs) => match eval(env, *lhs)? {
|
||||
Expression::Function(f) => f(env, *rhs),
|
||||
Expression::AnonymousFunction {
|
||||
argument_symbols,
|
||||
body,
|
||||
} => dispatch_anonymous_function(env, argument_symbols, *body, *rhs),
|
||||
a => Err(EvalError::NotAFunction(a)),
|
||||
},
|
||||
Expression::Quote(e) => Ok(*e),
|
||||
Expression::Symbol(s) => eval(
|
||||
env,
|
||||
env.get(&s).ok_or(EvalError::SymbolNotBound(s)).cloned()?,
|
||||
),
|
||||
x => Ok(x),
|
||||
}
|
||||
}
|
||||
|
||||
//==================Prelude evaluation environment==============================
|
||||
|
||||
fn prelude_add(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
|
||||
match eval(env, a)? {
|
||||
Expression::Integer(a) => match eval(env, b)? {
|
||||
Expression::Integer(b) => Ok(Expression::Integer(a + b)),
|
||||
Expression::Float(b) => Ok(Expression::Float(a as f64 + b)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
Expression::Float(a) => match eval(env, b)? {
|
||||
Expression::Float(b) => Ok(Expression::Float(a + b)),
|
||||
Expression::Integer(b) => Ok(Expression::Float(a + b as f64)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
}
|
||||
}
|
||||
|
||||
fn prelude_sub(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
|
||||
match eval(env, a)? {
|
||||
Expression::Integer(a) => match eval(env, b)? {
|
||||
Expression::Integer(b) => Ok(Expression::Integer(a - b)),
|
||||
Expression::Float(b) => Ok(Expression::Float(a as f64 - b)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
Expression::Float(a) => match eval(env, b)? {
|
||||
Expression::Float(b) => Ok(Expression::Float(a - b)),
|
||||
Expression::Integer(b) => Ok(Expression::Float(a - b as f64)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
}
|
||||
}
|
||||
|
||||
fn prelude_mul(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
|
||||
match eval(env, a)? {
|
||||
Expression::Integer(a) => match eval(env, b)? {
|
||||
Expression::Integer(b) => Ok(Expression::Integer(a * b)),
|
||||
Expression::Float(b) => Ok(Expression::Float(a as f64 * b)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
Expression::Float(a) => match eval(env, b)? {
|
||||
Expression::Float(b) => Ok(Expression::Float(a * b)),
|
||||
Expression::Integer(b) => Ok(Expression::Float(a * b as f64)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
}
|
||||
}
|
||||
|
||||
fn prelude_div(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
|
||||
match eval(env, a)? {
|
||||
Expression::Integer(a) => match eval(env, b)? {
|
||||
Expression::Integer(b) => Ok(Expression::Integer(a / b)),
|
||||
Expression::Float(b) => Ok(Expression::Float(a as f64 / b)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
Expression::Float(a) => match eval(env, b)? {
|
||||
Expression::Float(b) => Ok(Expression::Float(a / b)),
|
||||
Expression::Integer(b) => Ok(Expression::Float(a / b as f64)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
}
|
||||
}
|
||||
|
||||
fn prelude_lambda(_env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [args, body] = expr.try_into()?;
|
||||
let mut arg_exprs: Vec<Expression> = args.try_into()?;
|
||||
let argument_symbols: Vec<String> = arg_exprs
|
||||
.iter_mut()
|
||||
.map(|a| match a {
|
||||
Expression::Symbol(s) => Ok(s.to_owned()),
|
||||
x => Err(EvalError::NotASymbol(x.to_owned())),
|
||||
})
|
||||
.collect::<Result<Vec<String>, EvalError>>()?;
|
||||
Ok(Expression::AnonymousFunction {
|
||||
argument_symbols,
|
||||
body: Box::new(body),
|
||||
})
|
||||
}
|
||||
|
||||
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()?;
|
||||
|
||||
match eval(env, predicate)? {
|
||||
Expression::Nil => eval(env, e_else),
|
||||
_ => eval(env, e_then),
|
||||
}
|
||||
}
|
||||
|
||||
fn prelude_eq(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
let a = eval(env, a)?;
|
||||
let b = eval(env, b)?;
|
||||
|
||||
if a == b {
|
||||
Ok(Expression::True)
|
||||
} else {
|
||||
Ok(Expression::Nil)
|
||||
}
|
||||
}
|
||||
|
||||
fn prelude_lt(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
let a = eval(env, a)?;
|
||||
let b = eval(env, b)?;
|
||||
|
||||
if a < b {
|
||||
Ok(Expression::True)
|
||||
} else {
|
||||
Ok(Expression::Nil)
|
||||
}
|
||||
}
|
||||
|
||||
fn prelude_gt(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
let a = eval(env, a)?;
|
||||
let b = eval(env, b)?;
|
||||
|
||||
if a > b {
|
||||
Ok(Expression::True)
|
||||
} else {
|
||||
Ok(Expression::Nil)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_prelude(expr: Expression) -> Result<Expression, EvalError> {
|
||||
let mut prelude = Environment::new();
|
||||
prelude.set("+".to_string(), Expression::Function(prelude_add));
|
||||
prelude.set("-".to_string(), Expression::Function(prelude_sub));
|
||||
prelude.set("*".to_string(), Expression::Function(prelude_mul));
|
||||
prelude.set("/".to_string(), Expression::Function(prelude_div));
|
||||
prelude.set("lambda".to_string(), Expression::Function(prelude_lambda));
|
||||
prelude.set("if".to_string(), Expression::Function(prelude_if));
|
||||
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)
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
pub mod environment;
|
||||
pub mod eval;
|
||||
pub mod expression;
|
||||
pub mod prelude;
|
||||
|
||||
pub use environment::Environment;
|
||||
pub use environment::EnvironmentLayer;
|
||||
pub use expression::eval_prelude;
|
||||
pub use expression::EvalError;
|
||||
pub use eval::eval;
|
||||
pub use eval::EvalError;
|
||||
pub use expression::Expression;
|
||||
|
||||
185
src/lisp/prelude.rs
Normal file
185
src/lisp/prelude.rs
Normal file
@ -0,0 +1,185 @@
|
||||
use super::environment::Environment;
|
||||
use super::environment::EnvironmentLayer;
|
||||
use super::eval::eval;
|
||||
use super::eval::CellIterator;
|
||||
use super::eval::EvalError;
|
||||
use super::expression::Expression;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn prelude_add(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
|
||||
match eval(env, a)? {
|
||||
Expression::Integer(a) => match eval(env, b)? {
|
||||
Expression::Integer(b) => Ok(Expression::Integer(a + b)),
|
||||
Expression::Float(b) => Ok(Expression::Float(a as f64 + b)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
Expression::Float(a) => match eval(env, b)? {
|
||||
Expression::Float(b) => Ok(Expression::Float(a + b)),
|
||||
Expression::Integer(b) => Ok(Expression::Float(a + b as f64)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prelude_sub(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
|
||||
match eval(env, a)? {
|
||||
Expression::Integer(a) => match eval(env, b)? {
|
||||
Expression::Integer(b) => Ok(Expression::Integer(a - b)),
|
||||
Expression::Float(b) => Ok(Expression::Float(a as f64 - b)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
Expression::Float(a) => match eval(env, b)? {
|
||||
Expression::Float(b) => Ok(Expression::Float(a - b)),
|
||||
Expression::Integer(b) => Ok(Expression::Float(a - b as f64)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prelude_mul(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
|
||||
match eval(env, a)? {
|
||||
Expression::Integer(a) => match eval(env, b)? {
|
||||
Expression::Integer(b) => Ok(Expression::Integer(a * b)),
|
||||
Expression::Float(b) => Ok(Expression::Float(a as f64 * b)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
Expression::Float(a) => match eval(env, b)? {
|
||||
Expression::Float(b) => Ok(Expression::Float(a * b)),
|
||||
Expression::Integer(b) => Ok(Expression::Float(a * b as f64)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prelude_div(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
|
||||
match eval(env, a)? {
|
||||
Expression::Integer(a) => match eval(env, b)? {
|
||||
Expression::Integer(b) => Ok(Expression::Integer(a / b)),
|
||||
Expression::Float(b) => Ok(Expression::Float(a as f64 / b)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
Expression::Float(a) => match eval(env, b)? {
|
||||
Expression::Float(b) => Ok(Expression::Float(a / b)),
|
||||
Expression::Integer(b) => Ok(Expression::Float(a / b as f64)),
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
},
|
||||
x => Err(EvalError::NotANumber(x)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prelude_lambda(_env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [args, body] = expr.try_into()?;
|
||||
let mut arg_exprs: Vec<Expression> = args.try_into()?;
|
||||
let argument_symbols: Vec<String> = arg_exprs
|
||||
.iter_mut()
|
||||
.map(|a| match a {
|
||||
Expression::Symbol(s) => Ok(s.to_owned()),
|
||||
x => Err(EvalError::NotASymbol(x.to_owned())),
|
||||
})
|
||||
.collect::<Result<Vec<String>, EvalError>>()?;
|
||||
Ok(Expression::AnonymousFunction {
|
||||
argument_symbols,
|
||||
body: Box::new(body),
|
||||
})
|
||||
}
|
||||
|
||||
pub 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)
|
||||
}
|
||||
|
||||
pub fn prelude_if(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [predicate, e_then, e_else] = expr.try_into()?;
|
||||
|
||||
match eval(env, predicate)? {
|
||||
Expression::Nil => eval(env, e_else),
|
||||
_ => eval(env, e_then),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prelude_eq(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
let a = eval(env, a)?;
|
||||
let b = eval(env, b)?;
|
||||
|
||||
if a == b {
|
||||
Ok(Expression::True)
|
||||
} else {
|
||||
Ok(Expression::Nil)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prelude_lt(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
let a = eval(env, a)?;
|
||||
let b = eval(env, b)?;
|
||||
|
||||
if a < b {
|
||||
Ok(Expression::True)
|
||||
} else {
|
||||
Ok(Expression::Nil)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prelude_gt(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [a, b] = expr.try_into()?;
|
||||
let a = eval(env, a)?;
|
||||
let b = eval(env, b)?;
|
||||
|
||||
if a > b {
|
||||
Ok(Expression::True)
|
||||
} else {
|
||||
Ok(Expression::Nil)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prelude_set(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||
let [s, e] = expr.try_into()?;
|
||||
|
||||
match s {
|
||||
Expression::Symbol(s) => {
|
||||
env.shared_set(s, e);
|
||||
Ok(Expression::Nil)
|
||||
}
|
||||
x => Err(EvalError::NotASymbol(x)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_prelude(layer: &mut EnvironmentLayer) {
|
||||
layer.set("+".to_string(), Expression::Function(prelude_add));
|
||||
layer.set("-".to_string(), Expression::Function(prelude_sub));
|
||||
layer.set("*".to_string(), Expression::Function(prelude_mul));
|
||||
layer.set("/".to_string(), Expression::Function(prelude_div));
|
||||
layer.set("lambda".to_string(), Expression::Function(prelude_lambda));
|
||||
layer.set("if".to_string(), Expression::Function(prelude_if));
|
||||
layer.set("==".to_string(), Expression::Function(prelude_eq));
|
||||
layer.set("<".to_string(), Expression::Function(prelude_lt));
|
||||
layer.set(">".to_string(), Expression::Function(prelude_gt));
|
||||
layer.set("let".to_string(), Expression::Function(prelude_let));
|
||||
layer.set("set".to_string(), Expression::Function(prelude_set));
|
||||
}
|
||||
21
src/main.rs
21
src/main.rs
@ -1,21 +1,32 @@
|
||||
mod lisp;
|
||||
mod parser;
|
||||
use lisp::eval_prelude;
|
||||
use parser::ExpressionStream;
|
||||
|
||||
fn main() {
|
||||
let program = "((lambda (x y) (+ (if (< x 10) (* x 11) x) y)) 2 20)";
|
||||
use crate::lisp::{eval, Environment};
|
||||
|
||||
for r in ExpressionStream::from_char_stream(program.chars()) {
|
||||
fn main() {
|
||||
let program1 = "((lambda (x y) (+ (if (< x 10) (* x 11) x) y)) 2 20)";
|
||||
let program2 = "(set myvar \"hello world!\")";
|
||||
let program3 = "myvar";
|
||||
|
||||
let mut environment = Environment::default();
|
||||
|
||||
for r in ExpressionStream::from_char_stream(
|
||||
program1
|
||||
.chars()
|
||||
.chain(program2.chars())
|
||||
.chain(program3.chars()),
|
||||
) {
|
||||
match r {
|
||||
Err(err) => println!("ParserError: {:?}", err),
|
||||
Ok(expr) => println!(
|
||||
"{:?} \n vvvvvvvvvvv \n {:?}\n",
|
||||
expr.clone(),
|
||||
eval_prelude(expr)
|
||||
eval(&environment, expr)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
println!("Interpreter Done!");
|
||||
println!("Environment: {:?}", environment);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user