Skip to content
This repository has been archived by the owner on Dec 10, 2024. It is now read-only.

Commit

Permalink
feat: add associating parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
aripiprazole committed Nov 24, 2023
1 parent 50c5519 commit 33b57a5
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 34 deletions.
Binary file added .DS_Store
Binary file not shown.
137 changes: 104 additions & 33 deletions src/eval.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::{
convert::Infallible,
fmt::Display,

Check warning on line 3 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 🧪 Test check (nightly)

unused import: `fmt::Display`

Check failure on line 3 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 👁️‍🗨️ Lint check (nightly)

unused import: `fmt::Display`

Check warning on line 3 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 👁️‍🗨️ Compilation check (nightly)

unused import: `fmt::Display`
ops::{ControlFlow, FromResidual, Try},
sync::{Arc, RwLock},
};

use im::HashMap;
use thiserror::Error;
use Trampoline::{Continue, Done, Raise};

Expand All @@ -18,7 +20,7 @@ pub struct Definition {

#[derive(Clone)]
pub struct Frame {
pub name: Option<String>,
pub name: Option<Expr>,
pub src_pos: SrcPos,
pub definitions: im::HashMap<Keyword, Definition>,
pub is_catching_scope: bool,
Expand All @@ -30,6 +32,7 @@ pub struct Fun {
pub name: Expr,
pub parameters: Vec<Keyword>,
pub body: Expr,
pub environment: Arc<Environment>,
}

/// Bail out of the current evaluation with an error.
Expand Down Expand Up @@ -67,13 +70,35 @@ pub struct Keyword {
pub is_atom: bool,
}

impl Keyword {
pub fn is_keyword(&self, name: &str) -> bool {
self.name == name
}
}

/// The environment in which evaluation takes place.
#[derive(Clone)]
pub struct Environment {
pub global: Value,
pub expanded: bool,
pub frames: Arc<RwLock<im::Vector<Frame>>>,
}

/// Errors that can occur during expansion.
#[derive(Error, Debug, Clone)]
pub enum ExpansionError {
#[error("expected keyword")]
ExpectedKeyword,
}

impl From<ExpansionError> for Expr {
fn from(error: ExpansionError) -> Self {
match error {
ExpansionError::ExpectedKeyword => keyword!("eval.error/expected-keyword"),
}
}
}

/// Errors that can occur during evaluation.
#[derive(Error, Debug, Clone)]
pub enum EvalError {
Expand All @@ -85,6 +110,9 @@ pub enum EvalError {

#[error("expected atomic")]
ExpectedAtomic,

#[error("incorrect arity")]
IncorrectArity,
}

impl From<EvalError> for Expr {
Expand All @@ -95,39 +123,11 @@ impl From<EvalError> for Expr {
}
EvalError::ExpectedFun => keyword!("eval.error/expected-fun"),
EvalError::ExpectedAtomic => keyword!("eval.error/expected-atomic"),
EvalError::IncorrectArity => keyword!("eval.error/incorrect-arity"),
}
}
}

/// Errors that can occur during expansion.
#[derive(Error, Debug, Clone)]
pub enum ExpansionError {
#[error("expected keyword")]
ExpectedKeyword,
}

impl From<ExpansionError> for Expr {
fn from(error: ExpansionError) -> Self {
match error {
ExpansionError::ExpectedKeyword => keyword!("eval.error/expected-keyword"),
}
}
}

impl Environment {
/// Find a definition in the environment.
pub fn find_definition(&self, name: impl Into<Keyword>) -> Option<Definition> {
let name: Keyword = name.into();
for frame in self.frames.read().unwrap().iter().rev() {
if let Some(expr) = frame.definitions.get(&name) {
return Some(expr.clone());
}
}

None
}
}

/// A trampoline for evaluation. It's treated like a result, but it can also
/// contain a continuation.
pub enum Trampoline<T, E = Expr> {
Expand Down Expand Up @@ -157,12 +157,82 @@ impl TryFrom<Value> for Keyword {
}
}

impl Frame {
/// Set a definition in the frame.
pub fn insert_definition(&mut self, name: impl Into<Keyword>, value: Value) {
let keyword: Keyword = name.into();
self.definitions.insert(keyword.clone(), Definition {
is_macro_definition: false,
name: keyword.name,
value,
});
}
}

impl Environment {
/// Find a definition in the environment.
pub fn find_definition(&self, name: impl Into<Keyword>) -> Option<Definition> {
let name: Keyword = name.into();
for frame in self.frames.read().unwrap().iter().rev() {
if let Some(expr) = frame.definitions.get(&name) {
return Some(expr.clone());
}
}

None
}

/// Add frame to the environment.
pub fn push_frame(&self, name: Expr, src_pos: SrcPos) {
self.frames.write().unwrap().push_back(Frame {
src_pos,
name: Some(name),
definitions: im::HashMap::new(),
is_catching_scope: false,
});
}
}

/// Associate parameters with arguments.
fn associate_parameters(
mut parameters: Vec<Keyword>,
mut arguments: Vec<Value>,
) -> Trampoline<HashMap<Keyword, Value>> {
// last two vararg & and the name
let len = parameters.len();
let mut environment = im::HashMap::new();
let vararg_parameter = if len > 2 && parameters[len - 2].is_keyword("&") {
parameters.remove(parameters.len() - 2); // remove &
Some(parameters[parameters.len() - 1].clone())
} else {
None
};

for (index, parameter) in parameters.iter().enumerate() {
match (arguments.first(), vararg_parameter.clone()) {
(Some(_), Some(ref parameter)) if index == parameters.len() - 1 => {
environment.insert(parameter.clone(), Value::List(arguments));
break;
}
(None, _) => bail!(EvalError::IncorrectArity),
(Some(argument), _) => environment.insert(parameter.clone(), argument.clone()),
};

arguments.remove(0);
}

Done(environment)
}

impl Fun {
/// Call the function.
pub fn call(&self, environment: &Environment, arguments: Vec<Value>) -> Trampoline<Value> {
let _ = environment;
let _ = arguments;
todo!()
environment.push_frame(self.name.clone(), SrcPos::default());

loop {
let mut frame = self.environment.frames.write().unwrap().back_mut().unwrap();

Check warning on line 233 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 🧪 Test check (nightly)

unused variable: `frame`

Check warning on line 233 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 🧪 Test check (nightly)

variable does not need to be mutable

Check failure on line 233 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 👁️‍🗨️ Lint check (nightly)

unused variable: `frame`

Check failure on line 233 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 👁️‍🗨️ Lint check (nightly)

variable does not need to be mutable

Check warning on line 233 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 👁️‍🗨️ Compilation check (nightly)

unused variable: `frame`

Check warning on line 233 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 👁️‍🗨️ Compilation check (nightly)

variable does not need to be mutable
let new_environment = associate_parameters(self.parameters.clone(), arguments.clone());

Check warning on line 234 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 🧪 Test check (nightly)

unused variable: `new_environment`

Check failure on line 234 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 👁️‍🗨️ Lint check (nightly)

unused variable: `new_environment`

Check warning on line 234 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 👁️‍🗨️ Compilation check (nightly)

unused variable: `new_environment`
}
}
}

Expand Down Expand Up @@ -219,6 +289,7 @@ fn fun_expand(fun: crate::Fun, environment: &Environment) -> Result<Value, Expr>
.map(|value| value.try_into())
.collect::<Result<Vec<_>, _>>()?,
body: fun.body()?,
environment: Arc::new(environment.clone()),

Check failure on line 292 in src/eval.rs

View workflow job for this annotation

GitHub Actions / 👁️‍🗨️ Lint check (nightly)

usage of an `Arc` that is not `Send` and `Sync`
}))
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ define_builtin!(DefMacro, "defmacro*", 2);
define_builtin!(Def, "def*", 2);
define_builtin!(Recur, "recur");
define_builtin!(Fun, "fun*", 3);
define_builtin!(Quote, "'", 2);
define_builtin!(Quote, "quote", 2);
define_builtin!(Apply, "apply");

/// Semantic errors that can occur during the specialization of an expression.
Expand Down

0 comments on commit 33b57a5

Please sign in to comment.