feat: add shared environment/set
This commit is contained in:
parent
5de2230fec
commit
b51e185c21
@ -1,5 +1,10 @@
|
|||||||
use super::expression::Expression;
|
use super::{expression::Expression, prelude::mk_prelude};
|
||||||
use std::collections::HashMap;
|
use std::{
|
||||||
|
borrow::BorrowMut,
|
||||||
|
cell::{RefCell, RefMut},
|
||||||
|
collections::HashMap,
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
/// A Environment is a stack of `EnvironmentLayer`s. Each `EnvironmentLayer` is a mapping from
|
/// A Environment is a stack of `EnvironmentLayer`s. Each `EnvironmentLayer` is a mapping from
|
||||||
@ -9,6 +14,8 @@ pub struct Environment<'a> {
|
|||||||
layer: EnvironmentLayer,
|
layer: EnvironmentLayer,
|
||||||
/// The outer _fallback_ mapping.
|
/// The outer _fallback_ mapping.
|
||||||
outer: Option<&'a Environment<'a>>,
|
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)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
@ -31,8 +38,8 @@ impl EnvironmentLayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a value in the `EnvironmentLayer`.
|
/// Get a value in the `EnvironmentLayer`.
|
||||||
pub fn get(&self, key: &str) -> Option<&Expression> {
|
pub fn get(&self, key: &str) -> Option<Expression> {
|
||||||
self.symbols.get(key)
|
self.symbols.get(key).cloned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,12 +55,17 @@ impl<'a> Environment<'a> {
|
|||||||
Environment {
|
Environment {
|
||||||
layer: EnvironmentLayer::new(),
|
layer: EnvironmentLayer::new(),
|
||||||
outer: None,
|
outer: None,
|
||||||
|
shared: Rc::new(RefCell::new(EnvironmentLayer::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct an `Environment` from a `EnvironmentLayer` with no outer `Environment`.
|
/// Construct an `Environment` from a `EnvironmentLayer` with no outer `Environment`.
|
||||||
pub fn from_layer(layer: EnvironmentLayer) -> Self {
|
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`.
|
/// Construct a new `Environment` with `self` as the outer `Environment`.
|
||||||
@ -61,6 +73,7 @@ impl<'a> Environment<'a> {
|
|||||||
Environment {
|
Environment {
|
||||||
layer: EnvironmentLayer::new(),
|
layer: EnvironmentLayer::new(),
|
||||||
outer: Some(self),
|
outer: Some(self),
|
||||||
|
shared: self.shared.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,15 +82,43 @@ impl<'a> Environment<'a> {
|
|||||||
Environment {
|
Environment {
|
||||||
layer,
|
layer,
|
||||||
outer: Some(&self),
|
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`.
|
/// 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) {
|
if let Some(e) = self.layer.get(key) {
|
||||||
Some(e)
|
Some(e)
|
||||||
|
} else if let Some(e) = self.shared_get(key) {
|
||||||
|
Some(e)
|
||||||
} else {
|
} 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]
|
#[test]
|
||||||
fn test_environment() {
|
fn test_environment() {
|
||||||
let mut env = Environment::new();
|
let mut env = Environment::new();
|
||||||
@ -94,9 +148,9 @@ fn test_environment() {
|
|||||||
env.set("b".to_string(), Expression::Integer(2));
|
env.set("b".to_string(), Expression::Integer(2));
|
||||||
let mut inner = env.mk_inner();
|
let mut inner = env.mk_inner();
|
||||||
inner.set("a".to_string(), Expression::Integer(3));
|
inner.set("a".to_string(), Expression::Integer(3));
|
||||||
assert_eq!(inner.get("a"), Some(&Expression::Integer(3)));
|
assert_eq!(inner.get("a"), Some(Expression::Integer(3)));
|
||||||
assert_eq!(inner.get("b"), Some(&Expression::Integer(2)));
|
assert_eq!(inner.get("b"), Some(Expression::Integer(2)));
|
||||||
assert_eq!(env.get("a"), Some(&Expression::Integer(1)));
|
assert_eq!(env.get("a"), Some(Expression::Integer(1)));
|
||||||
assert_eq!(env.get("b"), Some(&Expression::Integer(2)));
|
assert_eq!(env.get("b"), Some(Expression::Integer(2)));
|
||||||
assert_eq!(env.get("c"), None);
|
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 super::environment::Environment;
|
||||||
use std::collections::HashMap;
|
use super::eval::CellIterator;
|
||||||
|
use super::eval::EvalError;
|
||||||
|
|
||||||
#[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.
|
||||||
@ -29,54 +30,6 @@ pub enum Expression {
|
|||||||
Nil,
|
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 {
|
impl From<fn(&Environment, Expression) -> Result<Expression, EvalError>> for Expression {
|
||||||
fn from(f: fn(&Environment, Expression) -> Result<Expression, EvalError>) -> Self {
|
fn from(f: fn(&Environment, Expression) -> Result<Expression, EvalError>) -> Self {
|
||||||
Expression::Function(f)
|
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 environment;
|
||||||
|
pub mod eval;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
|
pub mod prelude;
|
||||||
|
|
||||||
pub use environment::Environment;
|
pub use environment::Environment;
|
||||||
pub use environment::EnvironmentLayer;
|
pub use environment::EnvironmentLayer;
|
||||||
pub use expression::eval_prelude;
|
pub use eval::eval;
|
||||||
pub use expression::EvalError;
|
pub use eval::EvalError;
|
||||||
pub use expression::Expression;
|
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 lisp;
|
||||||
mod parser;
|
mod parser;
|
||||||
use lisp::eval_prelude;
|
|
||||||
use parser::ExpressionStream;
|
use parser::ExpressionStream;
|
||||||
|
|
||||||
fn main() {
|
use crate::lisp::{eval, Environment};
|
||||||
let program = "((lambda (x y) (+ (if (< x 10) (* x 11) x) y)) 2 20)";
|
|
||||||
|
|
||||||
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 {
|
match r {
|
||||||
Err(err) => println!("ParserError: {:?}", err),
|
Err(err) => println!("ParserError: {:?}", err),
|
||||||
Ok(expr) => println!(
|
Ok(expr) => println!(
|
||||||
"{:?} \n vvvvvvvvvvv \n {:?}\n",
|
"{:?} \n vvvvvvvvvvv \n {:?}\n",
|
||||||
expr.clone(),
|
expr.clone(),
|
||||||
eval_prelude(expr)
|
eval(&environment, expr)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Interpreter Done!");
|
println!("Interpreter Done!");
|
||||||
|
println!("Environment: {:?}", environment);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user