scheme_rs/
compile.rs

1use crate::{
2    ast,
3    continuation::Continuation,
4    env::Env,
5    error::RuntimeError,
6    eval::Eval,
7    expand::{SyntaxRule, Transformer},
8    gc::Gc,
9    syntax::{Identifier, Span, Syntax},
10    util::{ArcSlice, RequireOne},
11    value::Value,
12};
13use async_trait::async_trait;
14use derive_more::From;
15use std::{
16    collections::{HashMap, HashSet},
17    sync::Arc,
18};
19
20#[derive(From, Debug, Clone)]
21pub enum CompileError {
22    UnexpectedEmptyList(Span),
23    UndefinedVariable(Identifier),
24    RuntimeError(Box<RuntimeError>),
25    NotVariableTransformer,
26    CompileBodyError(CompileBodyError),
27    CompileLetError(CompileLetError),
28    CompileFuncCallError(CompileFuncCallError),
29    CompileIfError(CompileIfError),
30    CompileDefineError(CompileDefineError),
31    CompileDefineSyntaxError(CompileDefineSyntaxError),
32    CompileQuoteError(CompileQuoteError),
33    CompileSetError(CompileSetError),
34    CompileLambdaError(CompileLambdaError),
35    CompileSyntaxError(CompileSyntaxError),
36    CompileSyntaxCaseError(CompileSyntaxCaseError),
37    CompileSyntaxRulesError(CompileSyntaxRulesError),
38    CompileApplyError(CompileApplyError),
39}
40
41impl From<RuntimeError> for CompileError {
42    fn from(re: RuntimeError) -> Self {
43        Self::RuntimeError(Box::new(re))
44    }
45}
46
47macro_rules! impl_from_compile_error {
48    ( $error:ident ) => {
49        impl From<CompileError> for $error {
50            fn from(ce: CompileError) -> Self {
51                Self::CompileError(Box::new(ce))
52            }
53        }
54    };
55}
56
57#[async_trait]
58pub trait Compile: Eval + Sized + 'static
59where
60    CompileError: From<Self::Error>,
61{
62    type Error;
63
64    async fn compile(
65        exprs: &[Syntax],
66        env: &Env,
67        cont: &Option<Arc<Continuation>>,
68        span: &Span,
69    ) -> Result<Self, Self::Error>;
70
71    async fn compile_to_expr(
72        exprs: &[Syntax],
73        env: &Env,
74        cont: &Option<Arc<Continuation>>,
75        span: &Span,
76    ) -> Result<Arc<dyn Eval>, CompileError> {
77        Ok(Arc::new(Self::compile(exprs, env, cont, span).await?))
78    }
79}
80
81#[derive(Debug, Clone)]
82pub enum CompileBodyError {
83    EmptyBody(Span),
84    CompileError(Box<CompileError>),
85}
86
87impl_from_compile_error!(CompileBodyError);
88
89#[async_trait]
90impl Compile for ast::Body {
91    type Error = CompileBodyError;
92
93    async fn compile(
94        exprs: &[Syntax],
95        env: &Env,
96        cont: &Option<Arc<Continuation>>,
97        span: &Span,
98    ) -> Result<Self, CompileBodyError> {
99        if exprs.is_empty() {
100            return Err(CompileBodyError::EmptyBody(span.clone()));
101        }
102        let mut output = Vec::new();
103        for expr in &exprs[..exprs.len() - 1] {
104            output.push(expr.compile(env, cont).await?);
105        }
106        // TODO: what if the body isn't a proper list?
107        Ok(ast::Body::new(output))
108    }
109}
110
111#[derive(Debug, Clone)]
112pub enum CompileLetError {
113    BadForm(Span),
114    CompileBodyError(CompileBodyError),
115    CompileLetBindingError(CompileLetBindingError),
116}
117
118#[async_trait]
119impl Compile for ast::Let {
120    type Error = CompileLetError;
121
122    async fn compile(
123        expr: &[Syntax],
124        env: &Env,
125        cont: &Option<Arc<Continuation>>,
126        span: &Span,
127    ) -> Result<Self, CompileLetError> {
128        match expr {
129            [Syntax::Null { .. }, body @ ..] => compile_let(&[], body, env, cont, span).await,
130            [Syntax::List { list: bindings, .. }, body @ ..] => {
131                compile_let(bindings, body, env, cont, span).await
132            }
133            _ => Err(CompileLetError::BadForm(span.clone())),
134        }
135    }
136}
137
138async fn compile_let(
139    bindings: &[Syntax],
140    body: &[Syntax],
141    env: &Env,
142    cont: &Option<Arc<Continuation>>,
143    span: &Span,
144) -> Result<ast::Let, CompileLetError> {
145    let mut previously_bound = HashMap::new();
146    let mut new_contour = env.new_lexical_contour();
147    let mut compiled_bindings = Vec::new();
148    // TODO: Check that the list of bindings is proper
149    if !bindings.is_empty() {
150        for binding in &bindings[..bindings.len() - 1] {
151            let binding = LetBinding::compile(binding, env, cont, &previously_bound)
152                .await
153                .map_err(CompileLetError::CompileLetBindingError)?;
154            previously_bound.insert(binding.ident.clone(), binding.span.clone());
155            new_contour.def_var(&binding.ident, Gc::new(Value::Undefined));
156            compiled_bindings.push(binding);
157        }
158    }
159
160    let env = Gc::new(new_contour);
161    let body = ast::Body::compile(body, &Env::from(env.clone()), cont, span)
162        .await
163        .map_err(CompileLetError::CompileBodyError)?;
164    Ok(ast::Let {
165        bindings: compiled_bindings
166            .into_iter()
167            .map(|binding| (binding.ident, binding.expr))
168            .collect(),
169        body,
170    })
171}
172
173#[derive(Debug, Clone)]
174pub enum CompileLetBindingError {
175    BadForm(Span),
176    PreviouslyBound {
177        ident: Identifier,
178        first: Span,
179        second: Span,
180    },
181    NotAList(Span),
182    CompileError(Box<CompileError>),
183}
184
185impl_from_compile_error!(CompileLetBindingError);
186
187struct LetBinding {
188    ident: Identifier,
189    span: Span,
190    expr: Arc<dyn Eval>,
191}
192
193impl LetBinding {
194    async fn compile(
195        expr: &Syntax,
196        env: &Env,
197        cont: &Option<Arc<Continuation>>,
198        previously_bound: &HashMap<Identifier, Span>,
199    ) -> Result<LetBinding, CompileLetBindingError> {
200        match expr {
201            Syntax::List { list, span } => match &list[..] {
202                [Syntax::Identifier {
203                    ident,
204                    span: bind_span,
205                    ..
206                }, expr, Syntax::Null { .. }] => {
207                    if let Some(prev_bind) = previously_bound.get(ident) {
208                        return Err(CompileLetBindingError::PreviouslyBound {
209                            ident: ident.clone(),
210                            first: prev_bind.clone(),
211                            second: bind_span.clone(),
212                        });
213                    }
214
215                    let expr = expr.compile(env, cont).await?;
216
217                    Ok(LetBinding {
218                        ident: ident.clone(),
219                        span: bind_span.clone(),
220                        expr,
221                    })
222                }
223                _ => Err(CompileLetBindingError::BadForm(span.clone())),
224            },
225            expr => Err(CompileLetBindingError::NotAList(expr.span().clone())),
226        }
227    }
228}
229
230#[derive(From, Debug, Clone)]
231pub enum CompileFuncCallError {
232    EmptyFunctionCall(Span),
233    CompileError(Box<CompileError>),
234}
235
236impl_from_compile_error!(CompileFuncCallError);
237
238#[async_trait]
239impl Compile for ast::Call {
240    type Error = CompileFuncCallError;
241
242    async fn compile(
243        exprs: &[Syntax],
244        env: &Env,
245        cont: &Option<Arc<Continuation>>,
246        span: &Span,
247    ) -> Result<ast::Call, CompileFuncCallError> {
248        match exprs {
249            [operator, args @ ..] => {
250                // TODO: Support macro expansions in the call position that eventually
251                // resolve into an identifier, that is a macro (or function)
252                let proc_name = match operator {
253                    Syntax::Identifier { ident, .. } => ident.name.clone(),
254                    _ => String::from("<lambda>"),
255                };
256                let operator = operator.compile(env, cont).await?;
257                let mut compiled_args = vec![operator];
258                for arg in &args[..args.len() - 1] {
259                    compiled_args.push(arg.compile(env, cont).await?);
260                }
261                // TODO: what if it's not a proper list?
262                Ok(ast::Call {
263                    // operator,
264                    args: ArcSlice::from(compiled_args),
265                    location: span.clone(),
266                    proc_name,
267                })
268            }
269            [] => Err(CompileFuncCallError::EmptyFunctionCall(span.clone())),
270        }
271    }
272}
273
274#[derive(Debug, Clone)]
275pub enum CompileIfError {
276    ExpectedConditional(Span),
277    ExpectedArgumentAfterConditional(Span),
278    UnexpectedArgument(Span),
279    CompileError(Box<CompileError>),
280}
281
282impl_from_compile_error!(CompileIfError);
283
284#[async_trait]
285impl Compile for ast::If {
286    type Error = CompileIfError;
287
288    async fn compile(
289        exprs: &[Syntax],
290        env: &Env,
291        cont: &Option<Arc<Continuation>>,
292        span: &Span,
293    ) -> Result<Self, CompileIfError> {
294        match exprs {
295            [cond, success, Syntax::Null { .. }] => Ok(ast::If {
296                cond: cond.compile(env, cont).await?,
297                success: success.compile(env, cont).await?,
298                failure: None,
299            }),
300            [cond, success, failure, Syntax::Null { .. }] => Ok(ast::If {
301                cond: cond.compile(env, cont).await?,
302                success: success.compile(env, cont).await?,
303                failure: Some(failure.compile(env, cont).await?),
304            }),
305            [] => Err(CompileIfError::ExpectedConditional(span.clone())),
306            [a1] => Err(CompileIfError::ExpectedArgumentAfterConditional(
307                a1.span().clone(),
308            )),
309            [_, _, _, unexpected, ..] => Err(CompileIfError::UnexpectedArgument(
310                unexpected.span().clone(),
311            )),
312            _ => unreachable!(),
313        }
314    }
315}
316
317#[derive(Debug, Clone)]
318pub enum CompileDefineError {
319    ParameterDefinedMultipleTimes {
320        ident: Identifier,
321        first: Span,
322        second: Span,
323    },
324    ExpectedIdentifier(Span),
325    CompileBodyError(CompileBodyError),
326    BadForm(Span),
327    CompileError(Box<CompileError>),
328}
329
330impl_from_compile_error!(CompileDefineError);
331
332#[async_trait]
333impl Compile for ast::Define {
334    type Error = CompileDefineError;
335
336    async fn compile(
337        exprs: &[Syntax],
338        env: &Env,
339        cont: &Option<Arc<Continuation>>,
340        span: &Span,
341    ) -> Result<Self, Self::Error> {
342        match exprs {
343            [Syntax::Identifier { ident, .. }, expr, Syntax::Null { .. }] => {
344                Ok(ast::Define::DefineVar(ast::DefineVar {
345                    name: ident.clone(),
346                    val: expr.compile(env, cont).await?,
347                }))
348            }
349            [Syntax::List { list, span }, body @ ..] => {
350                match &list[..] {
351                    [] => Err(CompileDefineError::ExpectedIdentifier(span.clone())),
352                    [Syntax::Identifier {
353                        ident: func_name,
354                        span: func_span,
355                        ..
356                    }, args @ ..] => {
357                        let mut bound = HashMap::<Identifier, Span>::new();
358                        let mut fixed = Vec::new();
359                        for arg in &args[..args.len() - 1] {
360                            match arg {
361                                Syntax::Identifier { ident, span, .. } => {
362                                    if let Some(prev_span) = bound.get(ident) {
363                                        return Err(
364                                            CompileDefineError::ParameterDefinedMultipleTimes {
365                                                ident: ident.clone(),
366                                                first: prev_span.clone(),
367                                                second: span.clone(),
368                                            },
369                                        );
370                                    }
371                                    bound.insert(ident.clone(), span.clone());
372                                    fixed.push(ident.clone());
373                                }
374                                x => {
375                                    return Err(CompileDefineError::ExpectedIdentifier(
376                                        x.span().clone(),
377                                    ))
378                                }
379                            }
380                        }
381
382                        let args = if let Some(last) = args.last() {
383                            match last {
384                                Syntax::Null { .. } => {
385                                    ast::Formals::FixedArgs(fixed.into_iter().collect())
386                                }
387                                Syntax::Identifier { ident, span, .. } => {
388                                    if let Some(prev_span) = bound.get(ident) {
389                                        return Err(
390                                            CompileDefineError::ParameterDefinedMultipleTimes {
391                                                ident: ident.clone(),
392                                                first: prev_span.clone(),
393                                                second: span.clone(),
394                                            },
395                                        );
396                                    }
397                                    let remaining = ident.clone();
398                                    ast::Formals::VarArgs {
399                                        fixed: fixed.into_iter().collect(),
400                                        remaining,
401                                    }
402                                }
403                                x => {
404                                    return Err(CompileDefineError::ExpectedIdentifier(
405                                        x.span().clone(),
406                                    ))
407                                }
408                            }
409                        } else {
410                            // If there is no last argument, there are no arguments
411                            ast::Formals::FixedArgs(Vec::new())
412                        };
413                        let body = ast::Body::compile(body, env, cont, func_span)
414                            .await
415                            .map_err(CompileDefineError::CompileBodyError)?;
416                        Ok(ast::Define::DefineFunc(ast::DefineFunc {
417                            name: func_name.clone(),
418                            args,
419                            body,
420                        }))
421                    }
422                    [x, ..] => Err(CompileDefineError::BadForm(x.span().clone())),
423                }
424            }
425            _ => Err(CompileDefineError::BadForm(span.clone())),
426        }
427    }
428}
429
430#[derive(Debug, Clone)]
431pub enum CompileDefineSyntaxError {
432    BadForm(Span),
433    CompileError(Box<CompileError>),
434    RuntimeError(Box<RuntimeError>),
435}
436
437impl_from_compile_error!(CompileDefineSyntaxError);
438
439impl From<RuntimeError> for CompileDefineSyntaxError {
440    fn from(value: RuntimeError) -> Self {
441        Self::RuntimeError(Box::new(value))
442    }
443}
444
445#[async_trait]
446impl Compile for ast::DefineSyntax {
447    type Error = CompileDefineSyntaxError;
448
449    async fn compile(
450        expr: &[Syntax],
451        env: &Env,
452        cont: &Option<Arc<Continuation>>,
453        span: &Span,
454    ) -> Result<ast::DefineSyntax, CompileDefineSyntaxError> {
455        match expr {
456            [Syntax::Identifier { ident, .. }, expr, Syntax::Null { .. }] => {
457                env.def_macro(
458                    ident,
459                    expr.compile(env, cont)
460                        .await?
461                        .eval(env, cont)
462                        .await?
463                        .require_one()?,
464                )
465                .await;
466                Ok(ast::DefineSyntax)
467            }
468            _ => Err(CompileDefineSyntaxError::BadForm(span.clone())),
469        }
470    }
471}
472
473#[derive(Debug, Clone)]
474pub enum CompileQuoteError {
475    ExpectedArgument(Span),
476    UnexpectedArgument(Span),
477    BadForm(Span),
478}
479
480#[async_trait]
481impl Compile for ast::Quote {
482    type Error = CompileQuoteError;
483
484    async fn compile(
485        exprs: &[Syntax],
486        _env: &Env,
487        _cont: &Option<Arc<Continuation>>,
488        span: &Span,
489    ) -> Result<Self, CompileQuoteError> {
490        match exprs {
491            [] => Err(CompileQuoteError::ExpectedArgument(span.clone())),
492            [Syntax::Null { .. }] => Ok(ast::Quote { val: Value::Null }),
493            [expr, Syntax::Null { .. }] => Ok(ast::Quote {
494                val: Value::from_syntax(expr),
495            }),
496            [_, arg, ..] => Err(CompileQuoteError::UnexpectedArgument(arg.span().clone())),
497            _ => Err(CompileQuoteError::BadForm(span.clone())),
498        }
499    }
500}
501
502#[async_trait]
503impl Compile for ast::And {
504    type Error = CompileError;
505
506    async fn compile(
507        exprs: &[Syntax],
508        env: &Env,
509        cont: &Option<Arc<Continuation>>,
510        _span: &Span,
511    ) -> Result<Self, CompileError> {
512        let mut output = Vec::new();
513        // TODO: what if the arguments aren't a proper list?
514        for expr in &exprs[..exprs.len() - 1] {
515            let expr = expr.compile(env, cont).await?;
516            output.push(expr);
517        }
518        Ok(Self::new(output))
519    }
520}
521
522#[async_trait]
523impl Compile for ast::Or {
524    type Error = CompileError;
525
526    async fn compile(
527        exprs: &[Syntax],
528        env: &Env,
529        cont: &Option<Arc<Continuation>>,
530        _span: &Span,
531    ) -> Result<Self, CompileError> {
532        let mut output = Vec::new();
533        // TODO: what if the arguments aren't a proper list?
534        for expr in &exprs[..exprs.len() - 1] {
535            let expr = expr.compile(env, cont).await?;
536            output.push(expr);
537        }
538        Ok(Self::new(output))
539    }
540}
541
542#[derive(Debug, Clone)]
543pub enum CompileSetError {
544    ExpectedArgument(Span),
545    ExpectedIdent(Span),
546    UnexpectedArgument(Span),
547    BadForm(Span),
548    CompileError(Box<CompileError>),
549}
550
551impl_from_compile_error!(CompileSetError);
552
553#[async_trait]
554impl Compile for ast::Set {
555    type Error = CompileSetError;
556
557    async fn compile(
558        exprs: &[Syntax],
559        env: &Env,
560        cont: &Option<Arc<Continuation>>,
561        span: &Span,
562    ) -> Result<Self, CompileSetError> {
563        // TODO: We need to check if the identifier is defined as a variable transformer
564        match exprs {
565            [] => Err(CompileSetError::ExpectedArgument(span.clone())),
566            [Syntax::Identifier { ident, .. }, expr, Syntax::Null { .. }] => Ok(ast::Set {
567                var: ident.clone(),
568                val: expr.compile(env, cont).await?,
569            }),
570            [arg1, _, Syntax::Null { .. }] => {
571                Err(CompileSetError::ExpectedIdent(arg1.span().clone()))
572            }
573            [_, _, arg3, ..] => Err(CompileSetError::UnexpectedArgument(arg3.span().clone())),
574            _ => Err(CompileSetError::BadForm(span.clone())),
575        }
576    }
577}
578
579#[derive(Debug, Clone)]
580pub enum CompileSyntaxError {
581    ExpectedArgument(Span),
582    UnexpectedArgument(Span),
583    BadForm(Span),
584}
585
586#[async_trait]
587impl Compile for ast::SyntaxQuote {
588    type Error = CompileSyntaxError;
589
590    async fn compile(
591        exprs: &[Syntax],
592        env: &Env,
593        _cont: &Option<Arc<Continuation>>,
594        span: &Span,
595    ) -> Result<Self, CompileSyntaxError> {
596        match exprs {
597            [] => Err(CompileSyntaxError::ExpectedArgument(span.clone())),
598            [expr, Syntax::Null { .. }] => Ok(ast::SyntaxQuote {
599                syn: expr.clone(),
600                env: env.clone(),
601            }),
602            [_, arg, ..] => Err(CompileSyntaxError::UnexpectedArgument(arg.span().clone())),
603            _ => Err(CompileSyntaxError::BadForm(span.clone())),
604        }
605    }
606}
607
608#[derive(Debug, Clone)]
609pub enum CompileLambdaError {
610    ExpectedList(Span),
611    ExpectedIdentifier(Span),
612    CompileBodyError(CompileBodyError),
613    ParameterDefinedMultipleTimes {
614        ident: Identifier,
615        first: Span,
616        second: Span,
617    },
618}
619
620#[async_trait]
621impl Compile for ast::Lambda {
622    type Error = CompileLambdaError;
623
624    async fn compile(
625        exprs: &[Syntax],
626        env: &Env,
627        cont: &Option<Arc<Continuation>>,
628        span: &Span,
629    ) -> Result<Self, CompileLambdaError> {
630        match exprs {
631            [Syntax::Null { .. }, body @ ..] => compile_lambda(&[], body, env, cont, span).await,
632            [Syntax::List { list: args, .. }, body @ ..] => {
633                compile_lambda(args, body, env, cont, span).await
634            }
635            [Syntax::Identifier { ident, .. }, body @ ..] => {
636                let mut env = env.new_lexical_contour();
637                env.def_var(ident, Gc::new(Value::Undefined));
638
639                let body = ast::Body::compile(body, &Env::from(Gc::new(env)), cont, span)
640                    .await
641                    .map_err(CompileLambdaError::CompileBodyError)?;
642
643                Ok(ast::Lambda {
644                    args: ast::Formals::VarArgs {
645                        fixed: Vec::new(),
646                        remaining: ident.clone(),
647                    },
648                    body,
649                })
650            }
651            _ => todo!(),
652        }
653    }
654}
655
656async fn compile_lambda(
657    args: &[Syntax],
658    body: &[Syntax],
659    env: &Env,
660    cont: &Option<Arc<Continuation>>,
661    span: &Span,
662) -> Result<ast::Lambda, CompileLambdaError> {
663    let mut bound = HashMap::<Identifier, Span>::new();
664    let mut fixed = Vec::new();
665    if !args.is_empty() {
666        for arg in &args[..args.len() - 1] {
667            match arg {
668                Syntax::Identifier { ident, span, .. } => {
669                    if let Some(prev_span) = bound.get(ident) {
670                        return Err(CompileLambdaError::ParameterDefinedMultipleTimes {
671                            ident: ident.clone(),
672                            first: prev_span.clone(),
673                            second: span.clone(),
674                        });
675                    }
676                    bound.insert(ident.clone(), span.clone());
677                    fixed.push(ident.clone());
678                }
679                x => return Err(CompileLambdaError::ExpectedIdentifier(x.span().clone())),
680            }
681        }
682    }
683    let args = if let Some(last) = args.last() {
684        match last {
685            Syntax::Null { .. } => ast::Formals::FixedArgs(fixed.into_iter().collect()),
686            Syntax::Identifier { ident, span, .. } => {
687                if let Some(prev_span) = bound.get(ident) {
688                    return Err(CompileLambdaError::ParameterDefinedMultipleTimes {
689                        ident: ident.clone(),
690                        first: prev_span.clone(),
691                        second: span.clone(),
692                    });
693                }
694                let remaining = ident.clone();
695                ast::Formals::VarArgs {
696                    fixed: fixed.into_iter().collect(),
697                    remaining,
698                }
699            }
700            x => return Err(CompileLambdaError::ExpectedIdentifier(x.span().clone())),
701        }
702    } else {
703        // If there is no last argument, there are no arguments
704        ast::Formals::FixedArgs(Vec::new())
705    };
706
707    let mut env = env.new_lexical_contour();
708    for bound in bound.into_keys() {
709        env.def_var(&bound, Gc::new(Value::Undefined));
710    }
711
712    let body = ast::Body::compile(body, &Env::from(Gc::new(env)), cont, span)
713        .await
714        .map_err(CompileLambdaError::CompileBodyError)?;
715    Ok(ast::Lambda { args, body })
716}
717
718#[derive(Debug, Clone)]
719pub enum CompileSyntaxCaseError {
720    CompileError(Box<CompileError>),
721    BadForm(Span),
722}
723
724impl_from_compile_error!(CompileSyntaxCaseError);
725
726#[async_trait]
727impl Compile for ast::SyntaxCase {
728    type Error = CompileSyntaxCaseError;
729
730    async fn compile(
731        exprs: &[Syntax],
732        env: &Env,
733        cont: &Option<Arc<Continuation>>,
734        span: &Span,
735    ) -> Result<Self, CompileSyntaxCaseError> {
736        let (arg, keywords, mut rules) = match exprs {
737            [arg, Syntax::List { list, .. }, rules @ ..] => {
738                let mut keywords = HashSet::default();
739                // TODO: ensure keywords_list is proper
740                for keyword in &list[..list.len() - 1] {
741                    if let Syntax::Identifier { ident, .. } = keyword {
742                        keywords.insert(ident.name.clone());
743                    } else {
744                        return Err(CompileSyntaxCaseError::BadForm(keyword.span().clone()));
745                    }
746                }
747                (arg, keywords, rules)
748            }
749            [arg, Syntax::Null { .. }, rules @ ..] => (arg, HashSet::default(), rules),
750            _ => return Err(CompileSyntaxCaseError::BadForm(span.clone())),
751        };
752        let mut syntax_rules = Vec::new();
753        loop {
754            match rules {
755                [Syntax::Null { .. }] => break,
756                [Syntax::List { list, .. }, tail @ ..] => match &list[..] {
757                    [pattern, template, Syntax::Null { .. }] => {
758                        syntax_rules.push(SyntaxRule::compile(&keywords, pattern, template));
759                        rules = tail;
760                    }
761                    _ => return Err(CompileSyntaxCaseError::BadForm(span.clone())),
762                },
763                _ => return Err(CompileSyntaxCaseError::BadForm(span.clone())),
764            }
765        }
766        Ok(ast::SyntaxCase {
767            arg: arg.compile(env, cont).await?,
768            transformer: Transformer {
769                rules: syntax_rules,
770                is_variable_transformer: false,
771            },
772        })
773    }
774}
775
776#[derive(Debug, Clone)]
777pub enum CompileSyntaxRulesError {
778    BadForm(Span),
779}
780
781#[async_trait]
782impl Compile for ast::SyntaxRules {
783    type Error = CompileSyntaxRulesError;
784
785    async fn compile(
786        exprs: &[Syntax],
787        _env: &Env,
788        _cont: &Option<Arc<Continuation>>,
789        span: &Span,
790    ) -> Result<Self, CompileSyntaxRulesError> {
791        let (keywords, mut rules) = match exprs {
792            [Syntax::List { list, .. }, rules @ ..] => {
793                let mut keywords = HashSet::default();
794                // TODO: ensure keywords_list is proper
795                for keyword in &list[..list.len() - 1] {
796                    if let Syntax::Identifier { ident, .. } = keyword {
797                        keywords.insert(ident.name.clone());
798                    } else {
799                        return Err(CompileSyntaxRulesError::BadForm(keyword.span().clone()));
800                    }
801                }
802                (keywords, rules)
803            }
804            [Syntax::Null { .. }, rules @ ..] => (HashSet::default(), rules),
805            _ => return Err(CompileSyntaxRulesError::BadForm(span.clone())),
806        };
807        let mut syntax_rules = Vec::new();
808        loop {
809            match rules {
810                [Syntax::Null { .. }] => break,
811                [Syntax::List { list, .. }, tail @ ..] => match &list[..] {
812                    [pattern, template, Syntax::Null { .. }] => {
813                        syntax_rules.push(SyntaxRule::compile(&keywords, pattern, template));
814                        rules = tail;
815                    }
816                    _ => return Err(CompileSyntaxRulesError::BadForm(span.clone())),
817                },
818                _ => return Err(CompileSyntaxRulesError::BadForm(span.clone())),
819            }
820        }
821
822        Ok(Self {
823            transformer: Transformer {
824                rules: syntax_rules,
825                is_variable_transformer: false,
826            },
827        })
828    }
829}
830
831#[derive(From, Debug, Clone)]
832pub enum CompileApplyError {
833    BadForm(Span),
834    CompileError(Box<CompileError>),
835}
836
837impl_from_compile_error!(CompileApplyError);
838
839#[async_trait]
840impl Compile for ast::Apply {
841    type Error = CompileApplyError;
842
843    async fn compile(
844        exprs: &[Syntax],
845        env: &Env,
846        cont: &Option<Arc<Continuation>>,
847        span: &Span,
848    ) -> Result<Self, CompileApplyError> {
849        match exprs {
850            [operator, args @ .., rest_args, Syntax::Null { .. }] => {
851                let proc_name = match operator {
852                    Syntax::Identifier { ident, .. } => ident.name.clone(),
853                    _ => String::from("<lambda>"),
854                };
855                let operator = operator.compile(env, cont).await?;
856                let mut compiled_args = vec![operator];
857                for arg in args {
858                    compiled_args.push(arg.compile(env, cont).await?);
859                }
860                let rest_args = rest_args.compile(env, cont).await?;
861                Ok(ast::Apply {
862                    proc_name,
863                    location: span.clone(),
864                    args: ArcSlice::from(compiled_args),
865                    rest_args,
866                })
867            }
868            _ => Err(CompileApplyError::BadForm(span.clone())),
869        }
870    }
871}