From 56f652f3d194f934d38273bcf900eaab7ee18bbb Mon Sep 17 00:00:00 2001 From: Matthew Plant Date: Wed, 6 Nov 2024 17:35:19 -0500 Subject: [PATCH] Add `apply`, `values`, `let-values`, among others (#13) --- .github/workflows/rust.yml | 4 +- Cargo.toml | 6 +- proc-macros/src/lib.rs | 4 +- src/ast.rs | 53 ++++-- src/builtin.rs | 2 +- src/compile.rs | 188 +++++++++++++-------- src/continuation.rs | 329 ++++++++++++++++++++++++++++--------- src/env.rs | 64 +++++--- src/eval.rs | 265 ++++++++++++++++++++--------- src/expand.rs | 40 +++-- src/futures.rs | 28 ++-- src/gc.rs | 2 +- src/lex.rs | 19 ++- src/lists.rs | 34 ++-- src/main.rs | 8 +- src/num.rs | 119 ++++++++------ src/proc.rs | 53 ++++-- src/stdlib.scm | 78 +++++++++ src/syntax.rs | 72 ++++---- src/util.rs | 23 +++ src/value.rs | 79 +++++---- 21 files changed, 1014 insertions(+), 456 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 533ee8c..e8559f2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,9 +2,9 @@ name: Rust on: push: - branches: [ "master" ] + branches: [ "main" ] pull_request: - branches: [ "master" ] + branches: [ "main" ] env: CARGO_TERM_COLOR: always diff --git a/Cargo.toml b/Cargo.toml index a417914..9ea61ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] async-trait = "0.1" -derive_more = "0.99" +derive_more = { version = "1.0", features = ["debug", "from"]} dyn-clone = "1.0.13" futures = "0.3" inventory = "0.3" @@ -18,9 +18,9 @@ rand = "0.8" thiserror = "1" tokio = { version = "1", features = ["full"] } unicode_categories = "0.1" -reedline = "0.23" +reedline = "0.36" # TODO: Get rid of this dependency derivative = "2" [profile.release] -lto = true +lto = true \ No newline at end of file diff --git a/proc-macros/src/lib.rs b/proc-macros/src/lib.rs index 6a764f5..d419b09 100644 --- a/proc-macros/src/lib.rs +++ b/proc-macros/src/lib.rs @@ -30,7 +30,7 @@ pub fn builtin(name: TokenStream, item: TokenStream) -> TokenStream { fn #wrapper_name( cont: Option>, args: Vec> - ) -> futures::future::BoxFuture<'static, Result, crate::error::RuntimeError>> { + ) -> futures::future::BoxFuture<'static, Result>, crate::error::RuntimeError>> { Box::pin( async move { #impl_name( @@ -47,7 +47,7 @@ pub fn builtin(name: TokenStream, item: TokenStream) -> TokenStream { fn #wrapper_name( cont: Option>, mut required_args: Vec> - ) -> futures::future::BoxFuture<'static, Result, crate::error::RuntimeError>> { + ) -> futures::future::BoxFuture<'static, Result>, crate::error::RuntimeError>> { let var_args = required_args.split_off(#num_args); Box::pin( async move { diff --git a/src/ast.rs b/src/ast.rs index 231f5f6..b2eebba 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,8 +1,7 @@ use crate::{ - env::{Env, LexicalContour}, + env::Env, eval::Eval, expand::Transformer, - gc::Gc, num::Number, syntax::{Identifier, Mark, Span, Syntax}, util::ArcSlice, @@ -35,7 +34,6 @@ pub struct SyntaxQuote { #[derive(Clone)] pub struct Call { - // pub operator: Arc, pub args: ArcSlice>, pub location: Span, pub proc_name: String, @@ -45,7 +43,6 @@ pub struct Call { pub struct DefineFunc { pub name: Identifier, pub args: Formals, - pub mark: Mark, pub body: Body, } @@ -62,16 +59,12 @@ pub enum Define { } #[derive(Clone)] -pub struct DefineSyntax { - pub name: Identifier, - pub transformer: Arc, -} +pub struct DefineSyntax; #[derive(Clone)] pub struct Lambda { pub args: Formals, pub body: Body, - pub mark: Mark, } #[derive(Debug, Clone)] @@ -92,13 +85,13 @@ impl Formals { } } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Body { - pub exprs: ArcSlice, + pub exprs: ArcSlice>, } impl Body { - pub fn new(exprs: Vec) -> Self { + pub fn new(exprs: Vec>) -> Self { Self { exprs: ArcSlice::from(exprs), } @@ -107,7 +100,6 @@ impl Body { #[derive(Clone)] pub struct Let { - pub scope: Gc, pub bindings: Arc<[(Identifier, Arc)]>, pub body: Body, } @@ -170,6 +162,41 @@ pub struct SyntaxRules { pub transformer: Transformer, } +#[derive(Clone)] +pub struct Apply { + pub proc_name: String, + pub location: Span, + pub args: ArcSlice>, + pub rest_args: Arc, +} + +#[derive(Clone)] +pub struct FetchVar { + pub ident: Identifier, +} + +impl FetchVar { + pub fn new(ident: Identifier) -> Self { + Self { ident } + } +} + +#[derive(Clone)] +pub struct MacroExpansionPoint { + pub mark: Mark, + pub macro_env: Env, + pub expr: Arc, +} + +impl MacroExpansionPoint { + pub fn new(mark: Mark, macro_env: Env, expr: Arc) -> Self { + Self { + mark, + macro_env, + expr, + } + } +} /* struct Export {} diff --git a/src/builtin.rs b/src/builtin.rs index ff61165..4f17a57 100644 --- a/src/builtin.rs +++ b/src/builtin.rs @@ -5,7 +5,7 @@ use crate::{ use futures::future::BoxFuture; use std::sync::Arc; -type ExprFuture = BoxFuture<'static, Result, RuntimeError>>; +type ExprFuture = BoxFuture<'static, Result>, RuntimeError>>; pub struct Builtin { pub name: &'static str, diff --git a/src/compile.rs b/src/compile.rs index b3f87f1..60f5e08 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -6,8 +6,8 @@ use crate::{ eval::Eval, expand::{Pattern, SyntaxRule, Template, Transformer}, gc::Gc, - syntax::{Identifier, Mark, Span, Syntax}, - util::ArcSlice, + syntax::{Identifier, Span, Syntax}, + util::{ArcSlice, RequireOne}, value::Value, }; use async_trait::async_trait; @@ -35,6 +35,7 @@ pub enum CompileError { CompileSyntaxError(CompileSyntaxError), CompileSyntaxCaseError(CompileSyntaxCaseError), CompileSyntaxRulesError(CompileSyntaxRulesError), + CompileApplyError(CompileApplyError), } impl From for CompileError { @@ -80,23 +81,30 @@ where #[derive(Debug, Clone)] pub enum CompileBodyError { EmptyBody(Span), + CompileError(Box), } +impl_from_compile_error!(CompileBodyError); + #[async_trait] impl Compile for ast::Body { type Error = CompileBodyError; async fn compile( exprs: &[Syntax], - _env: &Env, - _cont: &Option>, + env: &Env, + cont: &Option>, span: &Span, ) -> Result { if exprs.is_empty() { return Err(CompileBodyError::EmptyBody(span.clone())); } + let mut output = Vec::new(); + for expr in &exprs[..exprs.len() - 1] { + output.push(expr.compile(env, cont).await?); + } // TODO: what if the body isn't a proper list? - Ok(ast::Body::new(exprs[..exprs.len() - 1].to_vec())) + Ok(ast::Body::new(output)) } } @@ -118,7 +126,7 @@ impl Compile for ast::Let { span: &Span, ) -> Result { match expr { - [Syntax::Nil { .. }, body @ ..] => compile_let(&[], body, env, cont, span).await, + [Syntax::Null { .. }, body @ ..] => compile_let(&[], body, env, cont, span).await, [Syntax::List { list: bindings, .. }, body @ ..] => { compile_let(bindings, body, env, cont, span).await } @@ -135,30 +143,25 @@ async fn compile_let( span: &Span, ) -> Result { let mut previously_bound = HashMap::new(); - let mut new_contour = env.new_lexical_contour(Mark::new()); + let mut new_contour = env.new_lexical_contour(); let mut compiled_bindings = Vec::new(); // TODO: Check that the list of bindings is proper if !bindings.is_empty() { for binding in &bindings[..bindings.len() - 1] { - let binding = - LetBinding::compile(new_contour.mark, binding, env, cont, &previously_bound) - .await - .map_err(CompileLetError::CompileLetBindingError)?; + let binding = LetBinding::compile(binding, env, cont, &previously_bound) + .await + .map_err(CompileLetError::CompileLetBindingError)?; previously_bound.insert(binding.ident.clone(), binding.span.clone()); - new_contour.def_var(&binding.ident, Gc::new(Value::Null)); + new_contour.def_var(&binding.ident, Gc::new(Value::Undefined)); compiled_bindings.push(binding); } } - let mut body = body.to_vec(); - for item in &mut body { - item.mark(new_contour.mark); - } + let env = Gc::new(new_contour); - let body = ast::Body::compile(&body, &Env::from(env.clone()), cont, span) + let body = ast::Body::compile(body, &Env::from(env.clone()), cont, span) .await .map_err(CompileLetError::CompileBodyError)?; Ok(ast::Let { - scope: env, bindings: compiled_bindings .into_iter() .map(|binding| (binding.ident, binding.expr)) @@ -189,7 +192,6 @@ struct LetBinding { impl LetBinding { async fn compile( - mark: Mark, expr: &Syntax, env: &Env, cont: &Option>, @@ -201,12 +203,10 @@ impl LetBinding { ident, span: bind_span, .. - }, expr, Syntax::Nil { .. }] => { - let mut ident = ident.clone(); - ident.mark(mark); - if let Some(prev_bind) = previously_bound.get(&ident) { + }, expr, Syntax::Null { .. }] => { + if let Some(prev_bind) = previously_bound.get(ident) { return Err(CompileLetBindingError::PreviouslyBound { - ident, + ident: ident.clone(), first: prev_bind.clone(), second: bind_span.clone(), }); @@ -215,7 +215,7 @@ impl LetBinding { let expr = expr.compile(env, cont).await?; Ok(LetBinding { - ident, + ident: ident.clone(), span: bind_span.clone(), expr, }) @@ -292,12 +292,12 @@ impl Compile for ast::If { span: &Span, ) -> Result { match exprs { - [cond, success, Syntax::Nil { .. }] => Ok(ast::If { + [cond, success, Syntax::Null { .. }] => Ok(ast::If { cond: cond.compile(env, cont).await?, success: success.compile(env, cont).await?, failure: None, }), - [cond, success, failure, Syntax::Nil { .. }] => Ok(ast::If { + [cond, success, failure, Syntax::Null { .. }] => Ok(ast::If { cond: cond.compile(env, cont).await?, success: success.compile(env, cont).await?, failure: Some(failure.compile(env, cont).await?), @@ -340,7 +340,7 @@ impl Compile for ast::Define { span: &Span, ) -> Result { match exprs { - [Syntax::Identifier { ident, .. }, expr, Syntax::Nil { .. }] => { + [Syntax::Identifier { ident, .. }, expr, Syntax::Null { .. }] => { Ok(ast::Define::DefineVar(ast::DefineVar { name: ident.clone(), val: expr.compile(env, cont).await?, @@ -356,7 +356,7 @@ impl Compile for ast::Define { }, args @ ..] => { let mut bound = HashMap::::new(); let mut fixed = Vec::new(); - let new_mark = Mark::new(); + // println!("compile_define new_mark = {:?}", new_mark); for arg in &args[..args.len() - 1] { match arg { Syntax::Identifier { ident, span, .. } => { @@ -370,8 +370,6 @@ impl Compile for ast::Define { ); } bound.insert(ident.clone(), span.clone()); - let mut ident = ident.clone(); - ident.mark(new_mark); fixed.push(ident.clone()); } x => { @@ -384,7 +382,7 @@ impl Compile for ast::Define { let args = if let Some(last) = args.last() { match last { - Syntax::Nil { .. } => { + Syntax::Null { .. } => { ast::Formals::FixedArgs(fixed.into_iter().collect()) } Syntax::Identifier { ident, span, .. } => { @@ -397,8 +395,7 @@ impl Compile for ast::Define { }, ); } - let mut remaining = ident.clone(); - remaining.mark(new_mark); + let remaining = ident.clone(); ast::Formals::VarArgs { fixed: fixed.into_iter().collect(), remaining, @@ -414,18 +411,13 @@ impl Compile for ast::Define { // If there is no last argument, there are no arguments ast::Formals::FixedArgs(Vec::new()) }; - let mut body = body.to_vec(); - for item in &mut body { - item.mark(new_mark); - } - let body = ast::Body::compile(&body, env, cont, func_span) + let body = ast::Body::compile(body, env, cont, func_span) .await .map_err(CompileDefineError::CompileBodyError)?; Ok(ast::Define::DefineFunc(ast::DefineFunc { name: func_name.clone(), args, body, - mark: new_mark, })) } [x, ..] => Err(CompileDefineError::BadForm(x.span().clone())), @@ -440,10 +432,17 @@ impl Compile for ast::Define { pub enum CompileDefineSyntaxError { BadForm(Span), CompileError(Box), + RuntimeError(Box), } impl_from_compile_error!(CompileDefineSyntaxError); +impl From for CompileDefineSyntaxError { + fn from(value: RuntimeError) -> Self { + Self::RuntimeError(Box::new(value)) + } +} + #[async_trait] impl Compile for ast::DefineSyntax { type Error = CompileDefineSyntaxError; @@ -455,10 +454,18 @@ impl Compile for ast::DefineSyntax { span: &Span, ) -> Result { match expr { - [Syntax::Identifier { ident, .. }, expr, Syntax::Nil { .. }] => Ok(ast::DefineSyntax { - name: ident.clone(), - transformer: expr.compile(env, cont).await?, - }), + [Syntax::Identifier { ident, .. }, expr, Syntax::Null { .. }] => { + env.def_macro( + ident, + expr.compile(env, cont) + .await? + .eval(env, cont) + .await? + .require_one()?, + ) + .await; + Ok(ast::DefineSyntax) + } _ => Err(CompileDefineSyntaxError::BadForm(span.clone())), } } @@ -483,7 +490,7 @@ impl Compile for ast::Quote { ) -> Result { match exprs { [] => Err(CompileQuoteError::ExpectedArgument(span.clone())), - [expr, Syntax::Nil { .. }] => Ok(ast::Quote { + [expr, Syntax::Null { .. }] => Ok(ast::Quote { val: Value::from_syntax(expr), }), [_, arg, ..] => Err(CompileQuoteError::UnexpectedArgument(arg.span().clone())), @@ -556,11 +563,11 @@ impl Compile for ast::Set { // TODO: We need to check if the identifier is defined as a variable transformer match exprs { [] => Err(CompileSetError::ExpectedArgument(span.clone())), - [Syntax::Identifier { ident, .. }, expr, Syntax::Nil { .. }] => Ok(ast::Set { + [Syntax::Identifier { ident, .. }, expr, Syntax::Null { .. }] => Ok(ast::Set { var: ident.clone(), val: expr.compile(env, cont).await?, }), - [arg1, _, Syntax::Nil { .. }] => { + [arg1, _, Syntax::Null { .. }] => { Err(CompileSetError::ExpectedIdent(arg1.span().clone())) } [_, _, arg3, ..] => Err(CompileSetError::UnexpectedArgument(arg3.span().clone())), @@ -588,7 +595,7 @@ impl Compile for ast::SyntaxQuote { ) -> Result { match exprs { [] => Err(CompileSyntaxError::ExpectedArgument(span.clone())), - [expr, Syntax::Nil { .. }] => Ok(ast::SyntaxQuote { + [expr, Syntax::Null { .. }] => Ok(ast::SyntaxQuote { syn: expr.clone(), env: env.clone(), }), @@ -621,7 +628,7 @@ impl Compile for ast::Lambda { span: &Span, ) -> Result { match exprs { - [Syntax::Nil { .. }, body @ ..] => compile_lambda(&[], body, env, cont, span).await, + [Syntax::Null { .. }, body @ ..] => compile_lambda(&[], body, env, cont, span).await, [Syntax::List { list: args, .. }, body @ ..] => { compile_lambda(args, body, env, cont, span).await } @@ -639,7 +646,8 @@ async fn compile_lambda( ) -> Result { let mut bound = HashMap::::new(); let mut fixed = Vec::new(); - let new_mark = Mark::new(); + // let new_mark = Mark::new(); + // println!("compile_lambda new_mark = {:?}", new_mark); if !args.is_empty() { for arg in &args[..args.len() - 1] { match arg { @@ -652,9 +660,7 @@ async fn compile_lambda( }); } bound.insert(ident.clone(), span.clone()); - let mut ident = ident.clone(); - ident.mark(new_mark); - fixed.push(ident); + fixed.push(ident.clone()); } x => return Err(CompileLambdaError::ExpectedIdentifier(x.span().clone())), } @@ -662,7 +668,7 @@ async fn compile_lambda( } let args = if let Some(last) = args.last() { match last { - Syntax::Nil { .. } => ast::Formals::FixedArgs(fixed.into_iter().collect()), + Syntax::Null { .. } => ast::Formals::FixedArgs(fixed.into_iter().collect()), Syntax::Identifier { ident, span, .. } => { if let Some(prev_span) = bound.get(ident) { return Err(CompileLambdaError::ParameterDefinedMultipleTimes { @@ -671,8 +677,7 @@ async fn compile_lambda( second: span.clone(), }); } - let mut remaining = ident.clone(); - remaining.mark(new_mark); + let remaining = ident.clone(); ast::Formals::VarArgs { fixed: fixed.into_iter().collect(), remaining, @@ -685,20 +690,15 @@ async fn compile_lambda( ast::Formals::FixedArgs(Vec::new()) }; - // This heavily relies on the fact that body defers compilation until it is run, - // as lambda does not create a lexical contour until it is run. - let mut body = body.to_vec(); - for item in &mut body { - item.mark(new_mark); + let mut env = env.new_lexical_contour(); + for bound in bound.into_keys() { + env.def_var(&bound, Gc::new(Value::Undefined)); } - let body = ast::Body::compile(&body, env, cont, span) + + let body = ast::Body::compile(body, &Env::from(Gc::new(env)), cont, span) .await .map_err(CompileLambdaError::CompileBodyError)?; - Ok(ast::Lambda { - args, - body, - mark: new_mark, - }) + Ok(ast::Lambda { args, body }) } #[derive(Debug, Clone)] @@ -732,15 +732,15 @@ impl Compile for ast::SyntaxCase { } (arg, keywords, rules) } - [arg, Syntax::Nil { .. }, rules @ ..] => (arg, HashSet::default(), rules), + [arg, Syntax::Null { .. }, rules @ ..] => (arg, HashSet::default(), rules), _ => return Err(CompileSyntaxCaseError::BadForm(span.clone())), }; let mut syntax_rules = Vec::new(); loop { match rules { - [Syntax::Nil { .. }] => break, + [Syntax::Null { .. }] => break, [Syntax::List { list, .. }, tail @ ..] => match &list[..] { - [pattern, template, Syntax::Nil { .. }] => { + [pattern, template, Syntax::Null { .. }] => { syntax_rules.push(SyntaxRule { pattern: Pattern::compile(pattern, &keywords), template: Template::compile(template), @@ -790,15 +790,15 @@ impl Compile for ast::SyntaxRules { } (keywords, rules) } - [Syntax::Nil { .. }, rules @ ..] => (HashSet::default(), rules), + [Syntax::Null { .. }, rules @ ..] => (HashSet::default(), rules), _ => return Err(CompileSyntaxRulesError::BadForm(span.clone())), }; let mut syntax_rules = Vec::new(); loop { match rules { - [Syntax::Nil { .. }] => break, + [Syntax::Null { .. }] => break, [Syntax::List { list, .. }, tail @ ..] => match &list[..] { - [pattern, template, Syntax::Nil { .. }] => { + [pattern, template, Syntax::Null { .. }] => { syntax_rules.push(SyntaxRule { pattern: Pattern::compile(pattern, &keywords), template: Template::compile(template), @@ -819,3 +819,45 @@ impl Compile for ast::SyntaxRules { }) } } + +#[derive(From, Debug, Clone)] +pub enum CompileApplyError { + BadForm(Span), + CompileError(Box), +} + +impl_from_compile_error!(CompileApplyError); + +#[async_trait] +impl Compile for ast::Apply { + type Error = CompileApplyError; + + async fn compile( + exprs: &[Syntax], + env: &Env, + cont: &Option>, + span: &Span, + ) -> Result { + match exprs { + [operator, args @ .., rest_args, Syntax::Null { .. }] => { + let proc_name = match operator { + Syntax::Identifier { ident, .. } => ident.name.clone(), + _ => String::from(""), + }; + let operator = operator.compile(env, cont).await?; + let mut compiled_args = vec![operator]; + for arg in args { + compiled_args.push(arg.compile(env, cont).await?); + } + let rest_args = rest_args.compile(env, cont).await?; + Ok(ast::Apply { + proc_name, + location: span.clone(), + args: ArcSlice::from(compiled_args), + rest_args, + }) + } + _ => Err(CompileApplyError::BadForm(span.clone())), + } + } +} diff --git a/src/continuation.rs b/src/continuation.rs index b4a70aa..e69b6b9 100644 --- a/src/continuation.rs +++ b/src/continuation.rs @@ -5,23 +5,32 @@ use crate::{ ast, env::{Env, LexicalContour}, error::{RuntimeError, RuntimeErrorKind}, - eval::{Eval, ValueOrPreparedCall}, + eval::{Eval, ValuesOrPreparedCall}, expand::Transformer, gc::Gc, + lists::list_to_vec, proc::{Callable, PreparedCall}, - syntax::{Identifier, Syntax}, - util::ArcSlice, + syntax::{Identifier, Span}, + util::{ArcSlice, RequireOne}, value::Value, }; use std::sync::Arc; #[async_trait] pub trait Resumable: Send + Sync { + fn min_args(&self) -> usize { + 1 + } + + fn max_args(&self) -> Option { + Some(1) + } + async fn resume( &self, - arg: Gc, + args: Vec>, cont: &Option>, - ) -> Result, RuntimeError>; + ) -> Result>, RuntimeError>; } #[derive(Clone)] @@ -43,15 +52,15 @@ impl Continuation { impl Resumable for Continuation { async fn resume( &self, - arg: Gc, + args: Vec>, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { if let Some(ref remaining) = self.remaining { let new_cont = Some(Arc::new(Continuation::new(remaining.clone(), cont))); - let resume_result = self.resume_point.resume(arg, &new_cont).await?; + let resume_result = self.resume_point.resume(args, &new_cont).await?; remaining.resume(resume_result, cont).await } else { - self.resume_point.resume(arg, cont).await + self.resume_point.resume(args, cont).await } } } @@ -59,18 +68,22 @@ impl Resumable for Continuation { #[async_trait] impl Callable for Option> { fn min_args(&self) -> usize { - 1 + self.as_ref() + .map(|x| x.resume_point.min_args()) + .unwrap_or(1) } fn max_args(&self) -> Option { - Some(1) + self.as_ref() + .map(|x| x.resume_point.max_args()) + .unwrap_or(None) } async fn call( &self, args: Vec>, _calling_cont: &Self, - ) -> Result { + ) -> Result { Err(RuntimeError::abandon_current_continuation( args, self.clone(), @@ -94,20 +107,20 @@ impl Eval for CatchContinuationCall { &self, env: &Env, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { let mut inner = self.inner.eval(env, cont).await; while let Err(RuntimeError { - kind: RuntimeErrorKind::AbandonCurrentContinuation { mut args, new_cont }, + kind: RuntimeErrorKind::AbandonCurrentContinuation { args, new_cont }, .. }) = inner { // Abandon the current continuation and evaluate the newly returned one // TODO: Retain the backtrace for errors - let arg = args.pop().unwrap(); + // let arg = args.pop().unwrap(); if let Some(new_cont) = new_cont { - inner = new_cont.resume(arg, cont).await; + inner = new_cont.resume(args, cont).await; } else { - return Ok(arg); + return Ok(args); } } inner @@ -116,11 +129,11 @@ impl Eval for CatchContinuationCall { pub struct ResumableBody { env: Env, - remaining: ArcSlice, + remaining: ArcSlice>, } impl ResumableBody { - pub fn new(env: &Env, remaining: &ArcSlice) -> Self { + pub fn new(env: &Env, remaining: &ArcSlice>) -> Self { Self { env: env.clone(), remaining: remaining.clone(), @@ -132,26 +145,20 @@ impl ResumableBody { impl Resumable for ResumableBody { async fn resume( &self, - arg: Gc, + args: Vec>, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { let Some(last) = self.remaining.last() else { - return Ok(arg); + return Ok(args); }; for (expr, tail) in self.remaining.skip_last() { let cont = Some(Arc::new(Continuation::new( Arc::new(ResumableBody::new(&self.env, &tail)), cont, ))); - expr.compile(&self.env, &cont) - .await? - .eval(&self.env, &cont) - .await?; + expr.eval(&self.env, &cont).await?; } - last.compile(&self.env, cont) - .await? - .eval(&self.env, cont) - .await + last.eval(&self.env, cont).await } } @@ -173,9 +180,10 @@ impl ResumableSyntaxCase { impl Resumable for ResumableSyntaxCase { async fn resume( &self, - arg: Gc, + args: Vec>, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { + let arg = args.require_one()?; let arg = arg.read().await; match &*arg { Value::Syntax(syntax) => { @@ -209,10 +217,11 @@ impl ResumableSet { impl Resumable for ResumableSet { async fn resume( &self, - arg: Gc, + args: Vec>, _cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { // TODO: Add try_unwrap to GC to avoid the clone of the inner value + let arg = args.require_one()?; let val = arg.read().await.clone(); *self .env @@ -221,7 +230,7 @@ impl Resumable for ResumableSet { .ok_or_else(|| RuntimeError::undefined_variable(self.var.clone()))? .write() .await = val; - Ok(Gc::new(Value::Null)) + Ok(vec![Gc::new(Value::Null)]) } } @@ -243,16 +252,17 @@ impl ResumableAnd { impl Resumable for ResumableAnd { async fn resume( &self, - arg: Gc, + args: Vec>, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { // This situation should never occur, because we don't create a new continuation // for the last argument let Some(last) = self.args.last() else { - return Ok(arg); + return Ok(args); }; + let arg = args.require_one()?; if !arg.read().await.is_true() { - return Ok(Gc::new(Value::Boolean(false))); + return Ok(vec![Gc::new(Value::Boolean(false))]); } for (arg, tail) in self.args.skip_last() { let cont = Arc::new(Continuation::new( @@ -262,11 +272,12 @@ impl Resumable for ResumableAnd { if !arg .eval(&self.env, &Some(cont)) .await? + .require_one()? .read() .await .is_true() { - return Ok(Gc::new(Value::Boolean(false))); + return Ok(vec![Gc::new(Value::Boolean(false))]); } } last.eval(&self.env, cont).await @@ -291,16 +302,17 @@ impl ResumableOr { impl Resumable for ResumableOr { async fn resume( &self, - arg: Gc, + args: Vec>, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { // This situation should never occur, because we don't create a new continuation // for the last argument let Some(last) = self.args.last() else { - return Ok(arg); + return Ok(args); }; + let arg = args.require_one()?; if arg.read().await.is_true() { - return Ok(Gc::new(Value::Boolean(true))); + return Ok(vec![Gc::new(Value::Boolean(true))]); } for (arg, tail) in self.args.skip_last() { let cont = Arc::new(Continuation::new( @@ -310,11 +322,12 @@ impl Resumable for ResumableOr { if arg .eval(&self.env, &Some(cont)) .await? + .require_one()? .read() .await .is_true() { - return Ok(Gc::new(Value::Boolean(true))); + return Ok(vec![Gc::new(Value::Boolean(true))]); } } last.eval(&self.env, cont).await @@ -348,9 +361,10 @@ impl ResumableLet { impl Resumable for ResumableLet { async fn resume( &self, - arg: Gc, + args: Vec>, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { + let arg = args.require_one()?; let up = { let mut scope = self.scope.write().await; scope.def_var(&self.curr, arg); @@ -361,7 +375,7 @@ impl Resumable for ResumableLet { Arc::new(ResumableLet::new(&self.scope, ident, remaining, &self.body)), cont, )); - let val = expr.eval(&up, &Some(cont)).await?; + let val = expr.eval(&up, &Some(cont)).await?.require_one()?; self.scope.write().await.def_var(ident, val); } self.body.eval(&Env::from(self.scope.clone()), cont).await @@ -388,15 +402,16 @@ impl ResumableIf { impl Resumable for ResumableIf { async fn resume( &self, - arg: Gc, + args: Vec>, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { + let arg = args.require_one()?; if arg.read().await.is_true() { self.success.eval(&self.env, cont).await } else if let Some(ref failure) = self.failure { failure.eval(&self.env, cont).await } else { - Ok(Gc::new(Value::Null)) + Ok(vec![Gc::new(Value::Null)]) } } } @@ -419,76 +434,162 @@ impl ResumableDefineVar { impl Resumable for ResumableDefineVar { async fn resume( &self, - arg: Gc, + args: Vec>, _cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { + let arg = args.require_one()?; self.env.def_var(&self.name, arg).await; - Ok(Gc::new(Value::Null)) + Ok(vec![Gc::new(Value::Null)]) } } -pub struct ResumableDefineSyntax { +pub struct ResumableCall { env: Env, - name: Identifier, + // TODO: Making this a SmallVec of around 10 would probably be a + // performance improvement. + collected: Vec>, + remaining: ArcSlice>, + proc_name: String, + location: Span, } -impl ResumableDefineSyntax { - pub fn new(env: &Env, name: &Identifier) -> Self { +impl ResumableCall { + pub fn new( + proc_name: &str, + location: &Span, + env: &Env, + collected: &[Gc], + remaining: ArcSlice>, + ) -> Self { Self { env: env.clone(), - name: name.clone(), + collected: collected.to_owned(), + remaining, + proc_name: proc_name.to_string(), + location: location.clone(), } } } #[async_trait] -impl Resumable for ResumableDefineSyntax { +impl Resumable for ResumableCall { async fn resume( &self, - arg: Gc, - _cont: &Option>, - ) -> Result, RuntimeError> { - self.env.def_macro(&self.name, arg).await; - Ok(Gc::new(Value::Null)) + args: Vec>, + cont: &Option>, + ) -> Result>, RuntimeError> { + let arg = args.require_one()?; + let mut collected = self.collected.clone(); + collected.push(arg); + for (arg, remaining) in self.remaining.iter() { + let cont = Arc::new(Continuation::new( + Arc::new(ResumableCall::new( + &self.proc_name, + &self.location, + &self.env, + &collected, + remaining, + )), + cont, + )); + let arg = arg + .eval(&self.env, &Some(cont)) + .await + .map_err(|mut err| { + err.push_frame(self.proc_name.clone(), self.location.clone()); + err + })? + .require_one()?; + collected.push(arg); + } + PreparedCall::prepare(&self.proc_name, &self.location, collected) + .eval(cont) + .await } } -pub struct ResumableCall { +pub struct ResumableApply { env: Env, - // TODO: Making this a SmallVec of around 10 would probably be a - // performance improvement. collected: Vec>, remaining: ArcSlice>, + rest_args: Option>, + proc_name: String, + location: Span, } -impl ResumableCall { - pub fn new(env: &Env, collected: &[Gc], remaining: ArcSlice>) -> Self { +impl ResumableApply { + pub fn new( + proc_name: &str, + location: &Span, + env: &Env, + collected: &[Gc], + remaining: ArcSlice>, + rest_args: Option>, + ) -> Self { Self { + proc_name: proc_name.to_string(), + location: location.clone(), env: env.clone(), collected: collected.to_owned(), remaining, + rest_args, } } } #[async_trait] -impl Resumable for ResumableCall { +impl Resumable for ResumableApply { async fn resume( &self, - arg: Gc, + args: Vec>, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { + let arg = args.require_one()?; let mut collected = self.collected.clone(); - collected.push(arg); - for (arg, remaining) in self.remaining.iter() { + if let Some(ref rest_args) = self.rest_args { + collected.push(arg); + + for (arg, remaining) in self.remaining.iter() { + let cont = Arc::new(Continuation::new( + Arc::new(ResumableApply::new( + &self.proc_name, + &self.location, + &self.env, + &collected, + remaining, + Some(rest_args.clone()), + )), + cont, + )); + let arg = arg.eval(&self.env, &Some(cont)).await?.require_one()?; + collected.push(arg); + } + let cont = Arc::new(Continuation::new( - Arc::new(ResumableCall::new(&self.env, &collected, remaining)), + Arc::new(ResumableApply::new( + &self.proc_name, + &self.location, + &self.env, + &collected, + ArcSlice::empty(), + None, + )), cont, )); - let arg = arg.eval(&self.env, &Some(cont)).await?; - collected.push(arg); + let rest_args = rest_args + .eval(&self.env, &Some(cont)) + .await? + .require_one()?; + // TODO: Throw an error if rest_args is not a list + list_to_vec(&rest_args, &mut collected).await; + } else { + // TODO: Throw an error if arg is not a list + list_to_vec(&arg, &mut collected).await; } - PreparedCall::prepare(collected).eval(cont).await + + PreparedCall::prepare(&self.proc_name, &self.location, collected) + .eval(cont) + .await } } @@ -496,7 +597,7 @@ impl Resumable for ResumableCall { pub async fn call_cc( cont: &Option>, proc: &Gc, -) -> Result, RuntimeError> { +) -> Result>, RuntimeError> { let callable = { let proc = proc.read().await; proc.as_callable() @@ -508,3 +609,71 @@ pub async fn call_cc( .eval(cont) .await } + +pub struct CallWithValues { + min_args: usize, + max_args: Option, + consumer: Gc, +} + +#[async_trait] +impl Resumable for CallWithValues { + fn min_args(&self) -> usize { + self.min_args + } + + fn max_args(&self) -> Option { + self.max_args + } + + async fn resume( + &self, + args: Vec>, + cont: &Option>, + ) -> Result>, RuntimeError> { + let callable = { + let proc = self.consumer.read().await; + proc.as_callable().unwrap() + }; + callable.call(args, cont).await?.eval(cont).await + } +} + +#[builtin("call-with-values")] +pub async fn call_with_values( + cont: &Option>, + producer: &Gc, + consumer: &Gc, +) -> Result>, RuntimeError> { + let producer_callable = { + let proc = producer.read().await; + proc.as_callable() + .ok_or_else(|| RuntimeError::invalid_type("procedure", proc.type_name()))? + }; + let consumer_callable = { + let proc = consumer.read().await; + proc.as_callable() + .ok_or_else(|| RuntimeError::invalid_type("procedure", proc.type_name()))? + }; + let producer_cont = Arc::new(Continuation::new( + Arc::new(CallWithValues { + min_args: consumer_callable.min_args(), + max_args: consumer_callable.max_args(), + consumer: consumer.clone(), + }), + cont, + )); + + let producer_result = producer_callable + .call(Vec::new(), &Some(producer_cont.clone())) + .await? + .eval(&Some(producer_cont)) + .await?; + + // Is it correct to use the calling continuation? Probably, whatever. + consumer_callable + .call(producer_result, cont) + .await? + .eval(cont) + .await +} diff --git a/src/env.rs b/src/env.rs index 010dad4..c666ba4 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,5 +1,5 @@ use futures::future::BoxFuture; -use std::{borrow::Cow, collections::HashMap}; +use std::collections::HashMap; use crate::{ builtin::Builtin, @@ -12,14 +12,19 @@ use crate::{ value::Value, }; +#[derive(derive_more::Debug)] pub struct LexicalContour { + #[debug(skip)] pub up: Env, - pub mark: Mark, + // pub mark: Mark, + #[debug("{:?}", vars.keys().cloned().collect::>())] vars: HashMap>, + #[debug("{:?}", macros.keys().cloned().collect::>())] macros: HashMap>, } impl LexicalContour { + /* fn strip<'a>(&self, ident: &'a Identifier) -> Cow<'a, Identifier> { if ident.marks.contains(&self.mark) { let mut stripped = ident.clone(); @@ -41,12 +46,13 @@ impl LexicalContour { self.up.strip_unused_marks(ident).await; }) } + */ pub fn is_bound<'a>(&'a self, ident: &'a Identifier) -> BoxFuture<'a, bool> { Box::pin(async move { self.vars.contains_key(ident) || self.macros.contains_key(ident) - || self.up.is_bound(&self.strip(ident)).await + || self.up.is_bound(ident).await }) } @@ -60,7 +66,7 @@ impl LexicalContour { return Some(var.clone()); } // Check the next lexical scope up - self.up.fetch_var(&self.strip(ident)).await + self.up.fetch_var(ident).await }) } @@ -70,10 +76,7 @@ impl LexicalContour { if let Some(var) = self.macros.get(ident) { return Some(MacroLookup::WithoutEnv(var.clone())); } - self.up - .fetch_macro(&self.strip(ident)) - .await - .map(MacroLookup::WithEnv) + self.up.fetch_macro(ident).await.map(MacroLookup::WithEnv) }) } @@ -102,9 +105,12 @@ impl Trace for LexicalContour { } } +#[derive(derive_more::Debug)] pub struct ExpansionContext { + #[debug(skip)] up: Env, mark: Mark, + #[debug(skip)] macro_env: Env, } @@ -121,20 +127,6 @@ impl ExpansionContext { }) } - pub fn strip_unused_marks<'a>(&'a self, ident: &'a mut Identifier) -> BoxFuture<'a, ()> { - Box::pin(async move { - if ident.marks.contains(&self.mark) { - let mut stripped = ident.clone(); - stripped.mark(self.mark); - self.macro_env.fetch_var(&stripped).await; - stripped.mark(self.mark); - ident.marks = stripped.marks; - } else { - self.up.strip_unused_marks(ident).await; - } - }) - } - pub fn fetch_var<'a>(&'a self, ident: &'a Identifier) -> BoxFuture<'a, Option>> { Box::pin(async move { // If the ident contains this mark, it comes from the macro and @@ -161,6 +153,18 @@ impl ExpansionContext { } else { self.up.fetch_macro(ident).await } + /* + let ident = if ident.marks.contains(&self.mark) { + let stripped = self.strip(ident); + if let result @ Some(_) = self.macro_env.fetch_macro(&stripped).await { + return result; + } + stripped + } else { + Cow::Borrowed(ident) + }; + self.up.fetch_macro(&ident).await + */ }) } } @@ -183,6 +187,7 @@ pub enum Env { } impl Env { + /* pub async fn strip_unused_marks(&self, ident: &mut Identifier) { match self { Self::Expansion(expansion) => expansion.read().await.strip_unused_marks(ident).await, @@ -190,6 +195,7 @@ impl Env { _ => (), } } + */ pub async fn is_bound(&self, ident: &Identifier) -> bool { match self { @@ -220,7 +226,7 @@ impl Env { } pub async fn top() -> Self { - let mut top = Self::Top.new_lexical_contour(Mark::new()); + let mut top = Self::Top.new_lexical_contour(); // Install the builtins: for builtin in inventory::iter:: { builtin.install(&mut top); @@ -231,10 +237,10 @@ impl Env { top } - pub fn new_lexical_contour(&self, mark: Mark) -> LexicalContour { + pub fn new_lexical_contour(&self) -> LexicalContour { LexicalContour { up: self.clone(), - mark, + // mark, vars: HashMap::default(), macros: HashMap::default(), } @@ -279,7 +285,7 @@ impl Env { } /// Evaluate a string, returning all of the results in a Vec - pub async fn eval<'e>(&self, exprs: &'e str) -> Result>, EvalError<'e>> { + pub async fn eval<'e>(&self, exprs: &'e str) -> Result>>, EvalError<'e>> { let tokens = Token::tokenize_str(exprs)?; let sexprs = ParsedSyntax::parse(&tokens)?; let mut results = Vec::new(); @@ -291,6 +297,12 @@ impl Env { } } +impl From> for Env { + fn from(env: Gc) -> Self { + Self::Expansion(env) + } +} + impl From> for Env { fn from(env: Gc) -> Self { Self::LexicalContour(env) diff --git a/src/eval.rs b/src/eval.rs index c7dcbbe..7988f6c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,29 +1,33 @@ use crate::{ ast, continuation::{ - Continuation, ResumableAnd, ResumableBody, ResumableCall, ResumableDefineSyntax, + Continuation, ResumableAnd, ResumableApply, ResumableBody, ResumableCall, ResumableDefineVar, ResumableIf, ResumableLet, ResumableOr, ResumableSet, ResumableSyntaxCase, }, env::Env, error::RuntimeError, gc::Gc, + lists::list_to_vec, proc::{PreparedCall, Procedure}, - util, + util::{self, ArcSlice, RequireOne}, value::Value, }; use async_trait::async_trait; use std::sync::Arc; -pub enum ValueOrPreparedCall { - Value(Gc), +pub enum ValuesOrPreparedCall { + Values(Vec>), PreparedCall(PreparedCall), } -impl ValueOrPreparedCall { - pub async fn eval(self, cont: &Option>) -> Result, RuntimeError> { +impl ValuesOrPreparedCall { + pub async fn eval( + self, + cont: &Option>, + ) -> Result>, RuntimeError> { match self { - Self::Value(val) => Ok(val), + Self::Values(val) => Ok(val), Self::PreparedCall(prepared_call) => prepared_call.eval(cont).await, } } @@ -39,7 +43,7 @@ pub trait Eval: Send + Sync { &self, env: &Env, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { self.tail_eval(env, cont).await?.eval(cont).await } @@ -48,8 +52,8 @@ pub trait Eval: Send + Sync { &self, env: &Env, cont: &Option>, - ) -> Result { - Ok(ValueOrPreparedCall::Value(self.eval(env, cont).await?)) + ) -> Result { + Ok(ValuesOrPreparedCall::Values(self.eval(env, cont).await?)) } } @@ -59,7 +63,18 @@ impl Eval for Gc { &self, _env: &Env, _cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { + Ok(vec![self.clone()]) + } +} + +#[async_trait] +impl Eval for Vec> { + async fn eval( + &self, + _env: &Env, + _cont: &Option>, + ) -> Result>, RuntimeError> { Ok(self.clone()) } } @@ -70,8 +85,8 @@ impl Eval for ast::Literal { &self, _env: &Env, _cont: &Option>, - ) -> Result, RuntimeError> { - Ok(Gc::new(Value::from_literal(self))) + ) -> Result>, RuntimeError> { + Ok(vec![Gc::new(Value::from_literal(self))]) } } @@ -81,8 +96,8 @@ impl Eval for ast::Quote { &self, _env: &Env, _cont: &Option>, - ) -> Result, RuntimeError> { - Ok(Gc::new(self.val.clone())) + ) -> Result>, RuntimeError> { + Ok(vec![Gc::new(self.val.clone())]) } } @@ -92,9 +107,9 @@ impl Eval for ast::Body { &self, env: &Env, cont: &Option>, - ) -> Result { + ) -> Result { let Some(last) = self.exprs.last() else { - return Ok(ValueOrPreparedCall::Value(Gc::new(Value::Null))); + return Ok(ValuesOrPreparedCall::Values(vec![Gc::new(Value::Null)])); }; for (expr, tail) in self.exprs.skip_last() { let cont = Some(Arc::new(Continuation::new( @@ -102,9 +117,9 @@ impl Eval for ast::Body { cont, ))); // Discard values that aren't returned - expr.compile(env, &cont).await?.eval(env, &cont).await?; + expr.eval(env, &cont).await?; } - last.compile(env, cont).await?.tail_eval(env, cont).await + last.tail_eval(env, cont).await } } @@ -112,21 +127,22 @@ impl Eval for ast::Body { impl Eval for ast::Let { async fn tail_eval( &self, - _env: &Env, + env: &Env, cont: &Option>, - ) -> Result { - let up = self.scope.read().await.up.clone(); + ) -> Result { + let scope = Gc::new(env.new_lexical_contour()); for ((ident, expr), remaining) in util::iter_arc(&self.bindings) { let cont = Arc::new(Continuation::new( - Arc::new(ResumableLet::new(&self.scope, ident, remaining, &self.body)), + Arc::new(ResumableLet::new(&scope, ident, remaining, &self.body)), cont, )); - let val = expr.eval(&up, &Some(cont)).await?; - self.scope.write().await.def_var(ident, val); + let val = expr + .eval(&Env::from(scope.clone()), &Some(cont)) + .await? + .require_one()?; + scope.write().await.def_var(ident, val); } - self.body - .tail_eval(&Env::from(self.scope.clone()), cont) - .await + self.body.tail_eval(&Env::from(scope), cont).await } } @@ -136,17 +152,25 @@ impl Eval for ast::Call { &self, env: &Env, cont: &Option>, - ) -> Result { + ) -> Result { let mut collected = Vec::new(); for (arg, remaining) in self.args.iter() { let cont = Arc::new(Continuation::new( - Arc::new(ResumableCall::new(env, &collected, remaining)), + Arc::new(ResumableCall::new( + &self.proc_name, + &self.location, + env, + &collected, + remaining, + )), cont, )); - let arg = arg.eval(env, &Some(cont)).await?; + let arg = arg.eval(env, &Some(cont)).await?.require_one()?; collected.push(arg); } - Ok(ValueOrPreparedCall::PreparedCall(PreparedCall::prepare( + Ok(ValuesOrPreparedCall::PreparedCall(PreparedCall::prepare( + &self.proc_name, + &self.location, collected, ))) } @@ -158,7 +182,7 @@ impl Eval for ast::If { &self, env: &Env, cont: &Option>, - ) -> Result { + ) -> Result { let cond_cont = Arc::new(Continuation::new( Arc::new(ResumableIf::new(env, &self.success, &self.failure)), cont, @@ -167,6 +191,7 @@ impl Eval for ast::If { .cond .eval(env, &Some(cond_cont)) .await? + .require_one()? .read() .await .is_true(); @@ -175,7 +200,7 @@ impl Eval for ast::If { } else if let Some(ref failure) = self.failure { failure.tail_eval(env, cont).await } else { - Ok(ValueOrPreparedCall::Value(Gc::new(Value::Null))) + Ok(ValuesOrPreparedCall::Values(vec![Gc::new(Value::Null)])) } } } @@ -186,18 +211,18 @@ impl Eval for ast::DefineFunc { &self, env: &Env, _cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { let (args, remaining) = self.args.to_args_and_remaining(); let func = Gc::new(Value::Procedure(Procedure { up: env.clone(), args, remaining, - mark: self.mark, + // mark: self.mark, body: self.body.clone(), is_variable_transformer: false, })); env.def_var(&self.name, func).await; - Ok(Gc::new(Value::Null)) + Ok(vec![Gc::new(Value::Null)]) } } @@ -207,14 +232,14 @@ impl Eval for ast::DefineVar { &self, env: &Env, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { let cont = Arc::new(Continuation::new( Arc::new(ResumableDefineVar::new(env, &self.name)), cont, )); - let val = self.val.eval(env, &Some(cont)).await?; + let val = self.val.eval(env, &Some(cont)).await?.require_one()?; env.def_var(&self.name, val).await; - Ok(Gc::new(Value::Null)) + Ok(vec![Gc::new(Value::Null)]) } } @@ -224,7 +249,7 @@ impl Eval for ast::Define { &self, env: &Env, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { match self { ast::Define::DefineFunc(define_func) => define_func.eval(env, cont).await, ast::Define::DefineVar(define_var) => define_var.eval(env, cont).await, @@ -236,16 +261,10 @@ impl Eval for ast::Define { impl Eval for ast::DefineSyntax { async fn eval( &self, - env: &Env, - cont: &Option>, - ) -> Result, RuntimeError> { - let cont = Arc::new(Continuation::new( - Arc::new(ResumableDefineSyntax::new(env, &self.name)), - cont, - )); - let val = self.transformer.eval(env, &Some(cont)).await?; - env.def_macro(&self.name, val).await; - Ok(Gc::new(Value::Null)) + _env: &Env, + _cont: &Option>, + ) -> Result>, RuntimeError> { + Ok(vec![Gc::new(Value::Null)]) } } @@ -255,9 +274,11 @@ impl Eval for ast::And { &self, env: &Env, cont: &Option>, - ) -> Result { + ) -> Result { let Some(last) = self.args.last() else { - return Ok(ValueOrPreparedCall::Value(Gc::new(Value::Boolean(true)))); + return Ok(ValuesOrPreparedCall::Values(vec![Gc::new(Value::Boolean( + true, + ))])); }; for (arg, tail) in self.args.skip_last() { let cont = Arc::new(Continuation::new( @@ -266,8 +287,17 @@ impl Eval for ast::And { )); // If one of the arguments does not evaluate to true, then the result // is false - if !arg.eval(env, &Some(cont)).await?.read().await.is_true() { - return Ok(ValueOrPreparedCall::Value(Gc::new(Value::Boolean(false)))); + if !arg + .eval(env, &Some(cont)) + .await? + .require_one()? + .read() + .await + .is_true() + { + return Ok(ValuesOrPreparedCall::Values(vec![Gc::new(Value::Boolean( + false, + ))])); } } // If all of the other arguments are true, then the result is the last expression @@ -281,9 +311,11 @@ impl Eval for ast::Or { &self, env: &Env, cont: &Option>, - ) -> Result { + ) -> Result { let Some(last) = self.args.last() else { - return Ok(ValueOrPreparedCall::Value(Gc::new(Value::Boolean(false)))); + return Ok(ValuesOrPreparedCall::Values(vec![Gc::new(Value::Boolean( + false, + ))])); }; for (arg, tail) in self.args.skip_last() { let cont = Arc::new(Continuation::new( @@ -291,8 +323,17 @@ impl Eval for ast::Or { cont, )); // If one of the arguments evaluates to true, then the result is true - if arg.eval(env, &Some(cont)).await?.read().await.is_true() { - return Ok(ValueOrPreparedCall::Value(Gc::new(Value::Boolean(true)))); + if arg + .eval(env, &Some(cont)) + .await? + .require_one()? + .read() + .await + .is_true() + { + return Ok(ValuesOrPreparedCall::Values(vec![Gc::new(Value::Boolean( + true, + ))])); } } // If all of the other arguments are false, then the result is the last expression @@ -306,7 +347,7 @@ impl Eval for ast::Vector { &self, _env: &Env, _cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { /* let mut output = Vec::new(); for item in &self.vals { @@ -324,8 +365,8 @@ impl Eval for ast::Nil { &self, _env: &Env, _cont: &Option>, - ) -> Result, RuntimeError> { - Ok(Gc::new(Value::Null)) + ) -> Result>, RuntimeError> { + Ok(vec![Gc::new(Value::Null)]) } } @@ -335,7 +376,7 @@ impl Eval for ast::Set { &self, env: &Env, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { let new_cont = Arc::new(Continuation::new( Arc::new(ResumableSet::new(env, &self.var)), cont, @@ -345,6 +386,7 @@ impl Eval for ast::Set { .val .eval(env, &Some(new_cont)) .await? + .require_one()? .read() .await .clone(); @@ -353,7 +395,7 @@ impl Eval for ast::Set { .ok_or_else(|| RuntimeError::undefined_variable(self.var.clone()))? .write() .await = val; - Ok(Gc::new(Value::Null)) + Ok(vec![Gc::new(Value::Null)]) } } @@ -363,18 +405,18 @@ impl Eval for ast::Lambda { &self, env: &Env, _cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { // TODO: Optimize the AST with smart pointers to prevent constantly // cloning. let (args, remaining) = self.args.to_args_and_remaining(); - Ok(Gc::new(Value::Procedure(Procedure { + Ok(vec![Gc::new(Value::Procedure(Procedure { up: env.clone(), args, remaining, - mark: self.mark, + // mark: self.mark, body: self.body.clone(), is_variable_transformer: false, - }))) + }))]) } } @@ -384,10 +426,8 @@ impl Eval for ast::SyntaxQuote { &self, _env: &Env, _cont: &Option>, - ) -> Result, RuntimeError> { - let mut syntax = self.syn.clone(); - syntax.strip_unused_marks(&self.env).await; - Ok(Gc::new(Value::Syntax(syntax))) + ) -> Result>, RuntimeError> { + Ok(vec![Gc::new(Value::Syntax(self.syn.clone()))]) } } @@ -397,12 +437,12 @@ impl Eval for ast::SyntaxCase { &self, env: &Env, cont: &Option>, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { let new_cont = Arc::new(Continuation::new( Arc::new(ResumableSyntaxCase::new(env, &self.transformer)), cont, )); - let val = self.arg.eval(env, &Some(new_cont)).await?; + let val = self.arg.eval(env, &Some(new_cont)).await?.require_one()?; let val = val.read().await; match &*val { Value::Syntax(syntax) => { @@ -420,7 +460,80 @@ impl Eval for ast::SyntaxRules { &self, _env: &Env, _cont: &Option>, - ) -> Result, RuntimeError> { - Ok(Gc::new(Value::Transformer(self.transformer.clone()))) + ) -> Result>, RuntimeError> { + Ok(vec![Gc::new(Value::Transformer(self.transformer.clone()))]) + } +} + +#[async_trait] +impl Eval for ast::Apply { + async fn tail_eval( + &self, + env: &Env, + cont: &Option>, + ) -> Result { + let mut collected = Vec::new(); + + for (arg, remaining) in self.args.iter() { + let cont = Arc::new(Continuation::new( + Arc::new(ResumableApply::new( + &self.proc_name, + &self.location, + env, + &collected, + remaining, + Some(self.rest_args.clone()), + )), + cont, + )); + let arg = arg.eval(env, &Some(cont)).await?.require_one()?; + collected.push(arg); + } + + let cont = Arc::new(Continuation::new( + Arc::new(ResumableApply::new( + &self.proc_name, + &self.location, + env, + &collected, + ArcSlice::empty(), + None, + )), + cont, + )); + let rest_args = self.rest_args.eval(env, &Some(cont)).await?.require_one()?; + // TODO: Throw an error if rest_args is not a list + list_to_vec(&rest_args, &mut collected).await; + + Ok(ValuesOrPreparedCall::PreparedCall(PreparedCall::prepare( + &self.proc_name, + &self.location, + collected, + ))) + } +} + +#[async_trait] +impl Eval for ast::FetchVar { + async fn eval( + &self, + env: &Env, + _cont: &Option>, + ) -> Result>, RuntimeError> { + Ok(vec![env.fetch_var(&self.ident).await.ok_or_else(|| { + RuntimeError::undefined_variable(self.ident.clone()) + })?]) + } +} + +#[async_trait] +impl Eval for ast::MacroExpansionPoint { + async fn tail_eval( + &self, + env: &Env, + cont: &Option>, + ) -> Result { + let env = Gc::new(env.new_expansion_context(self.mark, self.macro_env.clone())); + self.expr.tail_eval(&Env::from(env), cont).await } } diff --git a/src/expand.rs b/src/expand.rs index 4f16c8e..2056b3b 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -49,7 +49,7 @@ impl SyntaxRule { #[derive(Clone, Debug)] pub enum Pattern { - Nil, + Null, Underscore, Ellipsis(Box), List(Vec), @@ -62,7 +62,7 @@ pub enum Pattern { impl Pattern { pub fn compile(expr: &Syntax, keywords: &HashSet) -> Self { match expr { - Syntax::Nil { .. } => Self::Nil, + Syntax::Null { .. } => Self::Null, Syntax::Identifier { ident, .. } if ident.name == "_" => Self::Underscore, Syntax::Identifier { ident, .. } if keywords.contains(&ident.name) => { Self::Keyword(ident.name.clone()) @@ -129,7 +129,7 @@ impl Pattern { Self::List(list) => match_slice(list, expr, var_binds), Self::Vector(vec) => match_slice(vec, expr, var_binds), // We shouldn't ever see this outside of lists - Self::Nil => expr.is_nil(), + Self::Null => expr.is_nil(), _ => todo!(), } } @@ -140,15 +140,17 @@ fn match_slice( expr: &Syntax, var_binds: &mut HashMap>, ) -> bool { - let mut expr_iter = match expr { - Syntax::List { list, .. } => list.iter().peekable(), - Syntax::Nil { .. } => return true, + let span = expr.span(); + let exprs = match expr { + Syntax::List { list, .. } => list, + Syntax::Null { .. } => return true, _ => return false, }; + let mut expr_iter = exprs.iter().peekable(); let mut pattern_iter = pattern.iter().peekable(); while let Some(item) = pattern_iter.next() { if let Pattern::Ellipsis(ref pattern) = item { - let exprs: Vec<_> = if !matches!(pattern_iter.peek(), Some(Pattern::Nil)) { + let exprs: Vec<_> = if !matches!(pattern_iter.peek(), Some(Pattern::Null)) { // Match backwards let mut rev_expr_iter = expr_iter.rev(); let rev_pattern_iter = pattern_iter.rev(); @@ -170,6 +172,10 @@ fn match_slice( } } return true; + } else if !matches!(item, Pattern::Null) && pattern_iter.peek().is_none() { + // Match to the rest of the expresions: + let exprs = Syntax::new_list(expr_iter.cloned().collect(), span.clone()).normalize(); + return item.matches(&exprs, var_binds); } else if let Some(next_expr) = expr_iter.next() { if !item.matches(next_expr, var_binds) { return false; @@ -184,7 +190,7 @@ fn match_slice( #[derive(Clone, Debug)] pub enum Template { - Nil, + Null, Ellipsis(Box