~gagbo/rseven

9df947a58889364e163f48c47a718b563d544ee8 — Gerry Agbobada 2 months ago e72e67e feat/cps master
Start huge multi value refactoring

all started by looking at the output of `(values 2 3)` in guile scheme,
meaning that the infrastructure to pass values around and to get an
handle over continuations needed change. This has been done by starting
to change the analysis to make a CPS transformation on top of the
lexical analysis.

For the time being it's just a raw design, that will probably need to be
changed completely a few times before the stack is in a decent spot

- Remove all R7EvalResult
- Change R7Result to Result<Vec<_>>, R7Error>
- Make everything keep compiling
- Rename tests to make them less redundant
- Add test for lexical capture in closures (lambda expressions)
- Give each statement in a sequence its own environment.
- Make R7Proc::Closure an enum that holds multiple variants
  + the enum is only for variants that need to live in a Slot, AND
  + must be traceable by the Gc (it's a root for the values it
    captures/points to)
M core/Cargo.toml => core/Cargo.toml +1 -0
@@ 31,6 31,7 @@ tracing = { version = "0.1.23", default-features = false, features = ["std", "lo
paste = "1.0.4"
tracing-subscriber = { version = "0.3.15", features = ["env-filter"] }
thiserror = "1.0.35"
once_cell = "1.15.0"

[dev-dependencies]
pretty_assertions = "1.2"

A core/src/analyze/continuations.rs => core/src/analyze/continuations.rs +43 -0
@@ 0,0 1,43 @@
// SPDX-FileCopyrightText: 2022 Gerry Agbobada <git@gagbo.net>
//
// SPDX-License-Identifier: LGPL-3.0-only

use gc::{Finalize, Gc, Trace};

use crate::{
    env::ManagedR7Env,
    types::{ManagedR7Value, R7Error, R7Result},
};

use super::{EvalInEnv, ManagedAnalysis};

pub trait Continuate: Trace {
    fn continuate(&self, values: R7Result) -> R7Result;
}

impl Continuate for Continuation {
    fn continuate(&self, values: R7Result) -> R7Result {
        self.cont.continuate(values)
    }
}

#[derive(Trace, Finalize)]
pub struct Continuation {
    /// The captured environment
    env: ManagedR7Env,
    /// The continuation analysed and ready to be applied
    cont: Box<dyn Continuate>,
}
pub type ManagedContinuation = Gc<Continuation>;

impl Continuation {
    pub fn managed<T: Continuate + 'static>(
        current_env: ManagedR7Env,
        inner: T,
    ) -> ManagedContinuation {
        Gc::new(Self {
            env: current_env,
            cont: Box::new(inner),
        })
    }
}

A core/src/analyze/hollywood.rs => core/src/analyze/hollywood.rs +1759 -0
@@ 0,0 1,1759 @@
// SPDX-FileCopyrightText: 2022 Gerry Agbobada <git@gagbo.net>
//
// SPDX-License-Identifier: LGPL-3.0-only

//! "Don't call us, we'll call you": a CPS transformed analysis.

use gc::{Finalize, Gc, GcCell, Trace};
use parser::Rule;
use tracing::debug;

use super::{Analysis, AnalyzeError, AnalyzeResult, EvalInEnv};
use crate::{
    analyze::ManagedAnalysis,
    env::ManagedR7Env,
    eval::literal::eval_number,
    types::{
        Closure, ManagedClosure, ManagedR7Value, R7Error, R7Pair, R7Result, R7SingleResult,
        R7Value, RustClosure,
    },
};

/// A trait for objects that can execute runtime statements on a given
/// enviroment, using Continuation Passing Style
///
/// This trait is a [Trace] supertrait to allow such objects to be tracked in a
/// garbage collected environment.
pub trait EvalInEnvWithExplicitContinuation: Trace {
    fn call_with_continuation(&self, env: ManagedR7Env, cont: ManagedClosure) -> R7Result;
}

#[derive(Trace, Finalize)]
pub struct CpsAnalysis {
    cont: ManagedClosure,
    inner: Box<dyn EvalInEnv>,
}

impl Default for CpsAnalysis {
    fn default() -> Self {
        Self {
            cont: Closure::identity_continuation(),
            inner: Box::new(R7Error::UninitClosureSlot),
        }
    }
}

pub type ManagedCpsAnalysis = Gc<CpsAnalysis>;

impl EvalInEnv for CpsAnalysis {
    fn call(&self, env: ManagedR7Env) -> R7Result {
        self.cont.call_with_values(self.inner.call(env)?)
    }
}

impl CpsAnalysis {
    pub fn managed<T: EvalInEnv + 'static>(inner: T, cont: ManagedClosure) -> ManagedCpsAnalysis {
        Gc::new(Self {
            cont,
            inner: Box::new(inner),
        })
    }
}

impl std::fmt::Debug for CpsAnalysis {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("CpsAnalysis")
            .field("cont", &"explicit current Continuation")
            .field("inner", &"type erased EvalInEnv")
            .finish()
    }
}

#[derive(Default)]
pub struct CpsAnalyzer {
    quotation_level: usize,
}

impl CpsAnalyzer {
    #[tracing::instrument(skip(self, ast))]
    fn analyze_r7rs(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the r7rs".to_string(),
            )),
            |acc, pair| match pair.as_rule() {
                Rule::r7rs => {
                    unreachable!("The r7rs rule is not matched within itself")
                }
                Rule::EOI | Rule::COMMENT | Rule::atmosphere | Rule::WHITESPACE => acc,
                Rule::program => self.analyze_program(pair, cont.clone()),
                Rule::library => {
                    todo!("library")
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_program(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        sequence(
            ast.into_inner()
                .map(|pair| match pair.as_rule() {
                    Rule::command_or_definition => {
                        self.analyze_command_or_definition(pair, cont.clone())
                    }
                    unhandled_rule => {
                        todo!("Unhandled rule: {:#?}", unhandled_rule)
                    }
                })
                .collect::<AnalyzeResult<Vec<_>>>()?
                .into_iter(),
            cont,
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_command_or_definition(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        sequence(
            ast.into_inner()
                .map(|pair| match pair.as_rule() {
                    Rule::expression => self.analyze_expression(pair, cont.clone()),
                    Rule::definition => self.analyze_definition(pair, cont.clone()),
                    Rule::command_or_definition => {
                        self.analyze_command_or_definition(pair, cont.clone())
                    }
                    unhandled_rule => {
                        todo!("Unhandled rule: {:#?}", unhandled_rule)
                    }
                })
                .collect::<AnalyzeResult<Vec<_>>>()?
                .into_iter(),
            cont,
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_definition(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        let mut ast_iter = ast.into_inner();
        let definition_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| AnalyzeError::Syntax("lexer can't find a definition".into()))?;
        match definition_kind {
            Rule::single_value_definition => {
                #[derive(Trace, Finalize)]
                struct Analyzed {
                    val_proc: ManagedCpsAnalysis,
                    symbol: String,
                    quotation_level: usize,
                }

                impl EvalInEnv for Analyzed {
                    fn call(&self, env: ManagedR7Env) -> R7Result {
                        let cont = Gc::new(Closure::native(
                            None,
                            EnvDefineContinuation {
                                env: env.clone(),
                                symbol: self.symbol.clone(),
                            },
                        ));
                        self.val_proc.call_with_continuation(env, cont)
                    }
                }

                let symbol = ast_iter.next().unwrap().as_str().to_string();
                let val_proc = self.analyze_expression(
                    ast_iter
                        .next()
                        .ok_or_else(|| AnalyzeError::Syntax("expected expression".to_string()))?,
                    Closure::identity_continuation(),
                )?;
                let quotation_level = self.quotation_level;

                Ok(CpsAnalysis::managed(
                    Analyzed {
                        val_proc,
                        symbol,
                        quotation_level,
                    },
                    cont,
                ))
            }
            Rule::lambda_definition => {
                #[derive(Trace, Finalize)]
                struct Analyzed {
                    docstring: Option<String>,
                    locals: Vec<String>,
                    name: R7Value,
                    body: ManagedCpsAnalysis,
                    last_arg_is_list: bool,
                }

                impl EvalInEnv for Analyzed {
                    fn call(&self, env: ManagedR7Env) -> R7Result {
                        let proc = R7Value::procedure(Closure::analysed_cps(
                            self.docstring.clone(),
                            self.locals.clone(),
                            self.body.clone(),
                            env.clone(),
                            self.last_arg_is_list,
                        ));
                        env.borrow_mut()
                            .define(&self.name.symbol_name()?, proc.into())
                            .map(|val| vec![val])
                    }
                }

                let docstring: Option<String> = None;
                let mut locals: Vec<String> = Vec::new();
                let mut name = R7Value::null();
                let mut body = ManagedCpsAnalysis::default();
                let mut last_arg_is_list = false;
                for (i, elem) in ast_iter.enumerate() {
                    // The first element is the name of the lambda
                    if i == 0 {
                        debug_assert_eq!(elem.as_rule(), Rule::identifier);
                        debug!("Defining {} lambda", elem.as_str());
                        name = R7Value::symbol(elem.as_str());
                    } else if i == 1 {
                        debug_assert_eq!(elem.as_rule(), Rule::def_formals);
                        elem.into_inner().for_each(|formal| {
                            if formal.as_rule() == Rule::rest_identifier {
                                last_arg_is_list = true;
                                locals.push(formal.as_str().into());
                                return;
                            }
                            debug_assert_eq!(formal.as_rule(), Rule::identifier);
                            debug!("Adding {} to formal argument list", formal.as_str());
                            locals.push(formal.as_str().into());
                        })
                    } else {
                        debug_assert_eq!(elem.as_rule(), Rule::body);
                        body = sequence(
                            elem.into_inner()
                                .map(|part| self.analyze(part, Closure::identity_continuation()))
                                .collect::<AnalyzeResult<Vec<_>>>()?
                                .into_iter(),
                            Closure::identity_continuation(),
                        )?
                    }
                }

                Ok(CpsAnalysis::managed(
                    Analyzed {
                        docstring,
                        locals,
                        name,
                        body,
                        last_arg_is_list,
                    },
                    cont,
                ))
            }
            Rule::syntax_definition => {
                todo!("syntax_definition")
            }
            Rule::multiple_values_definition => {
                todo!("multiple_values_definition")
            }
            Rule::record_definition => {
                todo!("record_definition")
            }
            Rule::multiple_definitions => sequence(
                ast_iter
                    .map(|pair| self.analyze_definition(pair, Closure::identity_continuation()))
                    .collect::<AnalyzeResult<Vec<_>>>()?
                    .into_iter(),
                Closure::identity_continuation(),
            ),
            _ => Err(AnalyzeError::Syntax("unknown definition pattern".into())),
        }
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_expression(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the expression".into(),
            )),
            |_acc, pair| -> AnalyzeResult<ManagedCpsAnalysis> {
                match pair.as_rule() {
                    Rule::identifier => {
                        let variable_name = pair.as_str().to_string();
                        if self.quotation_level == 0 {
                            #[derive(Trace, Finalize)]
                            struct Analyzed {
                                variable_name: String,
                            }

                            impl EvalInEnv for Analyzed {
                                fn call(&self, env: ManagedR7Env) -> R7Result {
                                    env.borrow().get(&self.variable_name).map(|val| vec![val])
                                }
                            }
                            Ok(CpsAnalysis::managed(
                                Analyzed { variable_name },
                                cont.clone(),
                            ))
                        } else {
                            Ok(CpsAnalysis::managed(
                                ManagedR7Value::from(R7Value::symbol(&variable_name)),
                                cont.clone(),
                            ))
                        }
                    }
                    Rule::expression => {
                        // Recursive call because eval_lambda calls eval_expression on the body, which usually is a sequence, i.e. a {expression+}
                        self.analyze_expression(pair, cont.clone())
                    }
                    Rule::literal => self.analyze_literal(pair, cont.clone()),
                    // assignment and procedure_call cases almost share the same code,
                    // as set! is defined as a native proc in the default environment
                    Rule::assignment => {
                        #[derive(Trace, Finalize)]
                        struct Analyzed {
                            symbol: String,
                            val_proc: ManagedCpsAnalysis,
                            quot: usize,
                        }

                        impl EvalInEnv for Analyzed {
                            fn call(&self, env: ManagedR7Env) -> R7Result {
                                let cont = Gc::new(Closure::native(
                                    None,
                                    EnvSetContinuation {
                                        env: env.clone(),
                                        symbol: self.symbol.clone(),
                                    },
                                ));
                                self.val_proc.call_with_continuation(env, cont)
                            }
                        }

                        let mut ast_iter = pair.into_inner();
                        let symbol = ast_iter
                            .next()
                            .ok_or_else(|| AnalyzeError::Syntax("expected a symbol".into()))?
                            .as_str()
                            .to_string();
                        let val_proc = self.analyze_expression(
                            ast_iter
                                .next()
                                .ok_or_else(|| AnalyzeError::Syntax("expected a value".into()))?,
                            Closure::identity_continuation(),
                        )?;
                        let quot = self.quotation_level;

                        Ok(CpsAnalysis::managed(
                            Analyzed {
                                symbol,
                                val_proc,
                                quot,
                            },
                            Closure::identity_continuation(),
                        ))
                    }
                    Rule::procedure_call => {
                        let mut elements: Vec<ManagedCpsAnalysis> = Vec::new();
                        for elem in pair.into_inner() {
                            elements.push(
                                self.analyze_expression(elem, Closure::identity_continuation())?,
                            );
                        }
                        if self.quotation_level == 0 {
                            let (operator, operands) = elements
                                .split_first()
                                .expect("The parser/lexer found at least one operator.");
                            analyze_application(
                                operator.clone(),
                                operands.iter().cloned(),
                                0,
                                Closure::identity_continuation(),
                            )
                        } else {
                            collect_list(elements.into_iter(), self.quotation_level, cont.clone())
                        }
                    }
                    Rule::operator => self.analyze_expression(pair, cont.clone()),
                    Rule::operand => self.analyze_expression(pair, cont.clone()),
                    Rule::lambda_expression => self.analyze_lambda(pair, cont.clone()),
                    Rule::conditional => self.analyze_conditional(pair, cont.clone()),
                    Rule::derived_expression => self.analyze_derived_expr(pair, cont.clone()),
                    unhandled_rule => {
                        todo!("Unhandled rule: {:#?}", unhandled_rule)
                    }
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_literal(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        use crate::eval::literal::*;
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the literal".into(),
            )),
            |_acc, pair| match pair.as_rule() {
                Rule::boolean => {
                    let res = eval_boolean(pair);
                    Ok(CpsAnalysis::managed(res, cont.clone()))
                }
                Rule::character => {
                    let res = eval_character(pair);
                    Ok(CpsAnalysis::managed(res, cont.clone()))
                }
                Rule::bytevector => {
                    let res = eval_bytevector(pair);
                    Ok(CpsAnalysis::managed(res, cont.clone()))
                }
                Rule::number => {
                    let res = eval_number(pair);
                    Ok(CpsAnalysis::managed(res, cont.clone()))
                }
                Rule::quotation => self.analyze_quotation(pair, cont.clone()),
                unhandled_rule => {
                    todo!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_quotation(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax("No evaluable code in the r7rs".into())),
            |_acc, pair| match pair.as_rule() {
                Rule::datum => {
                    self.quotation_level += 1;
                    let res = self.analyze_datum(pair, cont.clone());
                    self.quotation_level -= 1;
                    res
                }
                // As per parser/src/r7rs.pest grammar definition,
                // if we call this function only in case we hit a quotation
                // node, then all other cases are unreachable
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_datum(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        use crate::eval::literal::*;
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the datum".into(),
            )),
            |_acc, pair| match pair.as_rule() {
                Rule::boolean => Ok(CpsAnalysis::managed(eval_boolean(pair), cont.clone())),
                Rule::character => Ok(CpsAnalysis::managed(eval_character(pair), cont.clone())),
                Rule::number => Ok(CpsAnalysis::managed(eval_number(pair), cont.clone())),
                Rule::symbol => Ok(CpsAnalysis::managed(
                    ManagedR7Value::from(R7Value::symbol(pair.as_str())),
                    cont.clone(),
                )),
                Rule::list => {
                    let elems = pair
                        .into_inner()
                        .map(|elem| self.analyze_datum(elem, Closure::identity_continuation()))
                        .collect::<AnalyzeResult<Vec<_>>>()?;
                    let quot = self.quotation_level;

                    collect_list(elems.into_iter(), quot, cont.clone())
                }
                unhandled_rule => {
                    todo!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_lambda(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        #[derive(Trace, Finalize)]
        struct Analyzed {
            locals: Vec<String>,
            docstring: Option<String>,
            body: ManagedCpsAnalysis,
            last_arg_is_list: bool,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                Ok(vec![R7Value::procedure(Closure::analysed_cps(
                    self.docstring.clone(),
                    self.locals.clone(),
                    self.body.clone(),
                    env,
                    self.last_arg_is_list,
                ))
                .into()])
            }
        }

        let mut locals: Vec<String> = Vec::new();
        let docstring: Option<String> = None;
        let mut body = ManagedCpsAnalysis::default();
        let mut last_arg_is_list = false;
        for pair in ast.into_inner() {
            match pair.as_rule() {
                Rule::formals => {
                    // If the formals are just "identifier", then it means the only locals should
                    // be bound as a list
                    if !pair.as_str().starts_with('(') {
                        last_arg_is_list = true;
                    }
                    pair.into_inner().for_each(|formal| {
                        if formal.as_rule() == Rule::rest_identifier {
                            last_arg_is_list = true;
                            locals.push(formal.as_str().into());
                            return;
                        }
                        debug_assert_eq!(formal.as_rule(), Rule::identifier);
                        locals.push(formal.as_str().into());
                    })
                }
                Rule::body => {
                    // FIXME: Handle definitions at the beginning of the body

                    // False positive because of the extra Clone trait bound on
                    // sequence argument
                    #[allow(clippy::needless_collect)]
                    let body_parts: Vec<_> = pair
                        .into_inner()
                        .map(|part| self.analyze(part, Closure::identity_continuation()))
                        .collect::<AnalyzeResult<_>>()?;
                    body = sequence(body_parts.into_iter(), Closure::identity_continuation())?;
                }
                _ => {
                    return Err(AnalyzeError::Syntax("unexpected token".into()));
                }
            }
        }

        Ok(CpsAnalysis::managed(
            Analyzed {
                locals,
                docstring,
                body,
                last_arg_is_list,
            },
            Closure::identity_continuation(),
        ))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_sequence(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        let ast_iter = ast.into_inner();
        // False positive because of the extra Clone trait bound on
        // sequence argument
        #[allow(clippy::needless_collect)]
        let body_parts: Vec<_> = ast_iter
            .map(|part| self.analyze(part, Closure::identity_continuation()))
            .collect::<AnalyzeResult<_>>()?;
        sequence(body_parts.into_iter(), cont)
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_conditional(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        #[derive(Trace, Finalize)]
        struct Analyzed {
            test: ManagedCpsAnalysis,
            consequent: ManagedCpsAnalysis,
            alternate: ManagedCpsAnalysis,
        }
        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let predicate = self.test.call(env.clone())?[0].clone();
                if predicate.borrow().as_bool() {
                    self.consequent.call(env)
                } else {
                    self.alternate.call(env)
                }
            }
        }

        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::conditional_if);
        let mut test = ManagedCpsAnalysis::default();
        let mut consequent = ManagedCpsAnalysis::default();
        // This decides the default value when there is no alternate
        let mut alternate = CpsAnalysis::managed(
            ManagedR7Value::from(R7Value::f()),
            Closure::identity_continuation(),
        );
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    test = self.analyze(elem, Closure::identity_continuation())?;
                }
                Rule::consequent => {
                    consequent = self.analyze(elem, Closure::identity_continuation())?;
                }
                Rule::alternate => {
                    alternate = self.analyze(elem, Closure::identity_continuation())?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(CpsAnalysis::managed(
            Analyzed {
                test,
                consequent,
                alternate,
            },
            cont,
        ))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        // TODO: Get rid of that clone
        let mut ast_iter = ast.clone().into_inner();
        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| AnalyzeError::Syntax("lexer can't find a derived expression".into()))?;
        match expr_kind {
            Rule::derived_expr_case_no_else | Rule::derived_expr_case => {
                self.analyze_derived_expr_case(ast, cont)
            }
            Rule::derived_expr_cond | Rule::derived_expr_cond_no_else => {
                self.analyze_derived_expr_cond(ast, cont)
            }
            Rule::derived_expr_and => self.analyze_derived_expr_and(ast, cont),
            Rule::derived_expr_or => self.analyze_derived_expr_or(ast, cont),
            Rule::derived_expr_when => self.analyze_derived_expr_when(ast, cont),
            Rule::derived_expr_unless => self.analyze_derived_expr_unless(ast, cont),
            Rule::binding_let => self.analyze_derived_expr_binding_let(ast, false, cont),
            Rule::binding_let_star => self.analyze_derived_expr_binding_let(ast, true, cont),
            // REVIEW: "star" has NO effect on the letrec analyses. Maybe there's something
            // I didn't get in the semantics that's really important?
            Rule::binding_letrec => self.analyze_derived_expr_binding_letrec(ast, false, cont),
            Rule::binding_letrec_star => self.analyze_derived_expr_binding_letrec(ast, true, cont),
            unhandled_rule => {
                todo!("Unhandled rule: {:#?}", unhandled_rule)
            }
        }
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_case(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        let mut ast_iter = ast.into_inner().peekable();
        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        debug_assert!(matches!(
            expr_kind,
            Rule::derived_expr_case_no_else | Rule::derived_expr_case
        ));

        #[derive(Trace, Finalize)]
        struct Analyzed {
            case_expr: ManagedCpsAnalysis,
            case_clauses: Vec<(
                /* test */ ManagedCpsAnalysis,
                /* consequent */ ManagedCpsAnalysis,
            )>,
            else_clause: ManagedCpsAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                for (test, consequent) in self.case_clauses.iter() {
                    if test.call(env.clone())?[0].borrow().as_bool() {
                        return consequent.call(env);
                    }
                }
                self.else_clause.call(env)
            }
        }

        let mut case_expr = ManagedCpsAnalysis::default();
        let mut case_clauses = Vec::new();
        // This default value controls the output when there is no else clause.
        let mut else_clause = CpsAnalysis::managed(
            ManagedR7Value::from(R7Value::f()),
            Closure::identity_continuation(),
        );

        while let Some(elem) = ast_iter.next() {
            match elem.as_rule() {
                Rule::expression => {
                    case_expr = self.analyze_expression(elem, Closure::identity_continuation())?
                }
                Rule::case_clause => {
                    case_clauses.push(self.analyze_case_clause(
                        case_expr.clone(),
                        elem,
                        Closure::identity_continuation(),
                    )?);
                }
                Rule::derived_expr_else => {
                    let else_val = ast_iter.next().ok_or_else(|| {
                        AnalyzeError::Syntax("Missing sequence after else clause".into())
                    })?;
                    match else_val.as_rule() {
                        Rule::sequence => {
                            else_clause =
                                self.analyze(else_val, Closure::identity_continuation())?;
                        }
                        Rule::recipient => {
                            let proc = self.analyze(else_val, Closure::identity_continuation())?;
                            else_clause = analyze_application(
                                proc,
                                std::iter::once(case_expr.clone()),
                                self.quotation_level,
                                Closure::identity_continuation(),
                            )?;
                        }
                        unhandled_rule => {
                            return Err(AnalyzeError::Syntax(format!(
                                "Unhandled rule: expecting sequence or recipient {:#?}",
                                unhandled_rule
                            )))
                        }
                    }
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(CpsAnalysis::managed(
            Analyzed {
                case_expr,
                case_clauses,
                else_clause,
            },
            cont,
        ))
    }

    #[tracing::instrument(skip(self, ast, target))]
    fn analyze_case_clause<'ast>(
        &mut self,
        target: ManagedCpsAnalysis,
        ast: parser::Pair<'ast, Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<(ManagedCpsAnalysis, ManagedCpsAnalysis)> {
        let mut clause_value_set: Vec<ManagedCpsAnalysis> = Vec::new();

        let ast_iter = ast.into_inner();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::datum => {
                    let clause_value =
                        self.analyze_datum(elem, Closure::identity_continuation())?;
                    clause_value_set.push(clause_value);
                }
                Rule::recipient => {
                    let proc = self.analyze(elem, Closure::identity_continuation())?;
                    let test = CpsAnalysis::managed(
                        ManagedR7Value::from(R7Value::t()),
                        Closure::identity_continuation(),
                    );

                    return Ok((
                        test,
                        analyze_application(
                            proc,
                            std::iter::once(target),
                            self.quotation_level,
                            Closure::identity_continuation(),
                        )?,
                    ));
                }
                Rule::sequence => {
                    let consequent =
                        self.analyze_sequence(elem, Closure::identity_continuation())?;

                    #[derive(Trace, Finalize)]
                    struct Analyzed {
                        clause_value_set: Vec<ManagedCpsAnalysis>,
                        target: ManagedCpsAnalysis,
                    }

                    impl EvalInEnv for Analyzed {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            let targ_val = self.target.call(env.clone())?;
                            Ok(vec![ManagedR7Value::from(R7Value::from(
                                self.clause_value_set.iter().any(|test| {
                                    test.call(env.clone()).map_or(false, |val| val == targ_val)
                                }),
                            ))])
                        }
                    }

                    return Ok((
                        CpsAnalysis::managed(
                            Analyzed {
                                clause_value_set,
                                target,
                            },
                            cont,
                        ),
                        consequent,
                    ));
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }
        unreachable!("No sequence on that call. Should be an error instead of a panic here.")
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_cond(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        let mut ast_iter = ast.into_inner().peekable();
        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        debug_assert!(matches!(
            expr_kind,
            Rule::derived_expr_cond_no_else | Rule::derived_expr_cond
        ));

        #[derive(Trace, Finalize)]
        struct Analyzed {
            cond_clauses: Vec<(
                /* test */ ManagedCpsAnalysis,
                /* consequent */ ManagedCpsAnalysis,
            )>,
            else_clause: ManagedCpsAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                for (test, consequent) in self.cond_clauses.iter() {
                    if test.call(env.clone())?[0].borrow().as_bool() {
                        return consequent.call(env);
                    }
                }
                self.else_clause.call(env)
            }
        }

        let mut cond_clauses = Vec::new();
        // This default value controls the output when there is no else clause.
        let mut else_clause = CpsAnalysis::managed(
            ManagedR7Value::from(R7Value::f()),
            Closure::identity_continuation(),
        );

        while let Some(elem) = ast_iter.next() {
            match elem.as_rule() {
                Rule::cond_clause => {
                    cond_clauses
                        .push(self.analyze_cond_clause(elem, Closure::identity_continuation())?);
                }
                Rule::derived_expr_else => {
                    let else_val = ast_iter.next().ok_or_else(|| {
                        AnalyzeError::Syntax("Missing sequence after else clause".into())
                    })?;
                    match else_val.as_rule() {
                        Rule::sequence => {
                            else_clause =
                                self.analyze(else_val, Closure::identity_continuation())?;
                        }
                        unhandled_rule => {
                            return Err(AnalyzeError::Syntax(format!(
                                "Unhandled rule: expecting sequence {:#?}",
                                unhandled_rule
                            )))
                        }
                    }
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(CpsAnalysis::managed(
            Analyzed {
                cond_clauses,
                else_clause,
            },
            cont,
        ))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_cond_clause<'ast>(
        &mut self,
        ast: parser::Pair<'ast, Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<(
        /* test */ ManagedCpsAnalysis,
        /* consequent */ ManagedCpsAnalysis,
    )> {
        let mut ast_iter = ast.into_inner();
        let test_ast = ast_iter
            .next()
            .ok_or_else(|| AnalyzeError::Syntax("Expecting a test for the cond".into()))?;
        let test = self.analyze(test_ast, Closure::identity_continuation())?;

        let consequent = ast_iter.next().map_or_else(
            || Ok(test.clone()),
            |cons_ast| match cons_ast.as_rule() {
                Rule::sequence => self.analyze(cons_ast, Closure::identity_continuation()),
                Rule::recipient => {
                    let proc = self.analyze(cons_ast, Closure::identity_continuation())?;
                    let quotation_level = self.quotation_level;
                    let target = test.clone();
                    analyze_application(
                        proc,
                        std::iter::once(target),
                        quotation_level,
                        Closure::identity_continuation(),
                    )
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )?;

        Ok((test, consequent))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_and(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_and);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            arguments: Vec<ManagedCpsAnalysis>,
        }
        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let mut args_iter = self.arguments.iter().peekable();
                while let Some(arg) = args_iter.next() {
                    let val = arg.call(env.clone())?;
                    if !val[0].borrow().as_bool() {
                        return Ok(vec![R7Value::f().into()]);
                    }
                    if args_iter.peek().is_none() {
                        return Ok(val);
                    }
                }
                // This is reached only if there are _no_ arguments
                // so "(and)" => #true
                Ok(vec![R7Value::t().into()])
            }
        }

        let mut arguments = Vec::new();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    arguments.push(self.analyze(elem, Closure::identity_continuation())?);
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }
        Ok(CpsAnalysis::managed(Analyzed { arguments }, cont))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_or(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_or);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            arguments: Vec<ManagedCpsAnalysis>,
        }
        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let mut args_iter = self.arguments.iter().peekable();
                while let Some(arg) = args_iter.next() {
                    let val = arg.call(env.clone())?;
                    if val[0].borrow().as_bool() {
                        return Ok(vec![val[0].clone()]);
                    }
                    if args_iter.peek().is_none() {
                        return Ok(val);
                    }
                }
                // This is reached only if there are _no_ arguments
                // so "(or)" => #false
                Ok(vec![R7Value::f().into()])
            }
        }

        let mut arguments = Vec::new();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    arguments.push(self.analyze(elem, Closure::identity_continuation())?);
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(CpsAnalysis::managed(Analyzed { arguments }, cont))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_when(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_when);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            test: ManagedCpsAnalysis,
            seq: ManagedCpsAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                if self.test.call(env.clone())?[0].borrow().as_bool() {
                    self.seq.call(env)
                } else {
                    Ok(vec![R7Value::f().into()])
                }
            }
        }

        let mut seq = ManagedCpsAnalysis::default();
        let mut test = ManagedCpsAnalysis::default();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    test = self.analyze(elem, Closure::identity_continuation())?;
                }
                Rule::sequence => {
                    seq = self.analyze(elem, Closure::identity_continuation())?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }
        Ok(CpsAnalysis::managed(Analyzed { test, seq }, cont))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_unless(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_when);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            test: ManagedCpsAnalysis,
            seq: ManagedCpsAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                if !self.test.call(env.clone())?[0].borrow().as_bool() {
                    self.seq.call(env)
                } else {
                    Ok(vec![R7Value::f().into()])
                }
            }
        }

        let mut seq = ManagedCpsAnalysis::default();
        let mut test = ManagedCpsAnalysis::default();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    test = self.analyze(elem, Closure::identity_continuation())?;
                }
                Rule::sequence => {
                    seq = self.analyze(elem, Closure::identity_continuation())?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(CpsAnalysis::managed(Analyzed { test, seq }, cont))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_binding_let(
        &mut self,
        ast: parser::Pair<Rule>,
        star: bool,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        let mut ast_iter = ast.into_inner().peekable();

        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        match star {
            true => debug_assert!(matches!(expr_kind, Rule::binding_let_star)),
            false => debug_assert!(matches!(expr_kind, Rule::binding_let)),
        }

        #[derive(Trace, Finalize)]
        struct Analyzed {
            binds: Vec<ManagedCpsAnalysis>,
            body: ManagedCpsAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let binds_env: ManagedR7Env = crate::env::R7Env::new((&env).into()).into();

                for binding in self.binds.iter() {
                    binding.call(binds_env.clone())?;
                }

                self.body.call(binds_env)
            }
        }

        let mut binds = Vec::new();
        let mut body = CpsAnalysis::managed(
            ManagedR7Value::from(R7Value::null()),
            Closure::identity_continuation(),
        );

        for elem in ast_iter {
            match elem.as_rule() {
                Rule::binding_spec => {
                    #[derive(Trace, Finalize)]
                    struct AnalyzedBind {
                        symbol: String,
                        val_proc: ManagedCpsAnalysis,
                        // the difference between let and let*
                        eval_in_parent: bool,
                    }
                    impl EvalInEnv for AnalyzedBind {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            let val = self.val_proc.call(if self.eval_in_parent {
                                env.borrow().parent().ok_or_else(|| {
                                    R7Error::Unknown(
                                        "No parent environment to evaluate binding in".to_string(),
                                    )
                                })?
                            } else {
                                env.clone()
                            })?;
                            debug_assert_eq!(val.len(), 1);
                            (&mut *env.borrow_mut())
                                .define(&self.symbol, val[0].clone())
                                .map(|val| vec![val])
                        }
                    }

                    let mut binding = elem.into_inner();
                    let ident = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(ident.as_rule(), Rule::identifier);
                    let symbol = ident.as_str().to_string();
                    let value = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(value.as_rule(), Rule::expression);
                    let val_proc =
                        self.analyze_expression(value, Closure::identity_continuation())?;

                    binds.push(CpsAnalysis::managed(
                        AnalyzedBind {
                            symbol,
                            val_proc,
                            eval_in_parent: !star,
                        },
                        Closure::identity_continuation(),
                    ));
                }
                Rule::body => {
                    body = self.analyze_sequence(
                        elem.into_inner().next().unwrap(),
                        Closure::identity_continuation(),
                    )?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(CpsAnalysis::managed(Analyzed { body, binds }, cont))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_binding_letrec(
        &mut self,
        ast: parser::Pair<Rule>,
        star: bool,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        let mut ast_iter = ast.clone().into_inner();

        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        match star {
            true => debug_assert!(matches!(expr_kind, Rule::binding_letrec_star)),
            false => debug_assert!(matches!(expr_kind, Rule::binding_letrec)),
        }

        #[derive(Trace, Finalize)]
        struct Analyzed {
            init_binds: Vec<ManagedCpsAnalysis>,
            binds: Vec<ManagedCpsAnalysis>,
            body: ManagedCpsAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let binds_env: ManagedR7Env = crate::env::R7Env::new((&env).into()).into();

                for binding in self.init_binds.iter() {
                    binding.call(binds_env.clone())?;
                }

                for binding in self.binds.iter() {
                    binding.call(binds_env.clone())?;
                }

                self.body.call(binds_env)
            }
        }

        let mut binds = Vec::new();
        let mut init_binds = Vec::new();
        let mut body = CpsAnalysis::managed(
            ManagedR7Value::from(R7Value::null()),
            Closure::identity_continuation(),
        );

        // First loop to accumulate initial bindings
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::binding_spec => {
                    #[derive(Trace, Finalize)]
                    struct AnalyzedInitBind {
                        symbol: String,
                        eval_in_parent: bool,
                    }
                    impl EvalInEnv for AnalyzedInitBind {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            (&mut *env.borrow_mut())
                                .define(
                                    &self.symbol,
                                    R7Value::DynamicBinding(self.symbol.clone()).into(),
                                )
                                .map(|val| vec![val])
                        }
                    }

                    let mut binding = elem.into_inner();
                    let ident = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(ident.as_rule(), Rule::identifier);
                    let symbol = ident.as_str().to_string();
                    let value = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(value.as_rule(), Rule::expression);

                    init_binds.push(CpsAnalysis::managed(
                        AnalyzedInitBind {
                            symbol: symbol.clone(),
                            eval_in_parent: !star,
                        },
                        Closure::identity_continuation(),
                    ));
                }
                Rule::body => {
                    break;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        // Skipping the letrec keyword
        for elem in ast.into_inner().into_iter().skip(1) {
            match elem.as_rule() {
                Rule::binding_spec => {
                    #[derive(Trace, Finalize)]
                    struct AnalyzedBind {
                        symbol: String,
                        val_proc: ManagedCpsAnalysis,
                        init_binds: Vec<ManagedCpsAnalysis>,
                        // the difference between let and let*
                        eval_in_parent: bool,
                    }
                    impl EvalInEnv for AnalyzedBind {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            let val = self.val_proc.call(env.clone())?;
                            debug_assert_eq!(val.len(), 1);
                            (&mut *env.borrow_mut())
                                .set(&self.symbol, val[0].clone())
                                .map(|val| vec![val])
                        }
                    }

                    let mut binding = elem.into_inner();
                    let ident = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(ident.as_rule(), Rule::identifier);
                    let symbol = ident.as_str().to_string();
                    let value = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(value.as_rule(), Rule::expression);
                    let val_proc =
                        self.analyze_expression(value, Closure::identity_continuation())?;

                    binds.push(CpsAnalysis::managed(
                        AnalyzedBind {
                            symbol,
                            init_binds: init_binds.clone(),
                            val_proc,
                            eval_in_parent: !star,
                        },
                        Closure::identity_continuation(),
                    ));
                }
                Rule::body => {
                    body = self.analyze_sequence(
                        elem.into_inner().next().unwrap(),
                        Closure::identity_continuation(),
                    )?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(CpsAnalysis::managed(
            Analyzed {
                body,
                binds,
                init_binds,
            },
            cont,
        ))
    }

    /// Analyze a parsed tree to return a procedure that can
    /// be use to evaluate the result multiple times according
    /// to the environment.
    #[tracing::instrument(skip(self, ast))]
    pub fn analyze(
        &mut self,
        ast: parser::Pair<Rule>,
        cont: ManagedClosure,
    ) -> AnalyzeResult<ManagedCpsAnalysis> {
        match ast.as_rule() {
            Rule::EOI => Ok(CpsAnalysis::managed(
                ManagedR7Value::from(R7Value::null()),
                cont,
            )),
            Rule::r7rs => self.analyze_r7rs(ast, cont),
            Rule::number => Ok(CpsAnalysis::managed(eval_number(ast), cont)),
            Rule::datum => self.analyze_datum(ast, cont),
            Rule::literal => self.analyze_literal(ast, cont),
            Rule::suffix
            | Rule::infnan
            | Rule::exponent_marker
            | Rule::exactness
            | Rule::radix_2
            | Rule::radix_8
            | Rule::radix_10
            | Rule::radix_16
            | Rule::sign
            | Rule::num_2
            | Rule::complex_2
            | Rule::real_2
            | Rule::ureal_2
            | Rule::uinteger_2
            | Rule::prefix_2
            | Rule::num_8
            | Rule::complex_8
            | Rule::real_8
            | Rule::ureal_8
            | Rule::uinteger_8
            | Rule::prefix_8
            | Rule::num_10
            | Rule::complex_10
            | Rule::real_10
            | Rule::ureal_10
            | Rule::uinteger_10
            | Rule::prefix_10
            | Rule::decimal_10
            | Rule::num_16
            | Rule::complex_16
            | Rule::real_16
            | Rule::ureal_16
            | Rule::uinteger_16
            | Rule::prefix_16 => unreachable!(
                "Inner number rule during analysis phase: {:?}",
                ast.as_rule()
            ),
            Rule::sequence => self.analyze_sequence(ast, cont),
            Rule::expression => self.analyze_expression(ast, cont),
            // Basic "{ expression }" aliases
            Rule::test
            | Rule::cond_test
            | Rule::consequent
            | Rule::alternate
            | Rule::operator
            | Rule::operand
            | Rule::recipient
            | Rule::init
            | Rule::step
            | Rule::qq_template_0 => self.analyze(ast.into_inner().next().unwrap(), cont),
            unhandled_rule => {
                todo!("Unhandled rule: {:#?}", unhandled_rule)
            }
        }
    }
}

/// Analyze a sequence of analysis.
///
/// Equivalent to calling all the analyses in order inconditionnally; or
/// equivalent to "bind"ing the analyses in a monadic way
fn sequence<T, A>(analyses: T, cont: ManagedClosure) -> AnalyzeResult<ManagedCpsAnalysis>
where
    T: Iterator<Item = A>,
    A: EvalInEnv + 'static,
{
    #[derive(Trace, Finalize)]
    struct Analyzed {
        parts: Vec<ManagedAnalysis>,
    }

    impl EvalInEnv for Analyzed {
        fn call(&self, env: ManagedR7Env) -> R7Result {
            use crate::env::R7Env;
            let mut folded = Vec::new();
            let mut new_env = env;
            for analysed in self.parts.iter() {
                folded = analysed.call(new_env.clone())?;
                new_env = R7Env::new(Some(&new_env)).into();
            }
            Ok(folded)
        }
    }

    // Force eager collection to root objects and assert static ownership
    Ok(CpsAnalysis::managed(
        Analyzed {
            parts: analyses.map(Analysis::managed).collect(),
        },
        cont,
    ))
}

/// Collect a sequence of analysis.
///
/// This takes a sequence of analysis and calls the continuation
/// cont with a single argument being a R7Pair of all analyses in order.
fn collect_list<T, A>(
    analyses: T,
    quotation_level: usize,
    cont: ManagedClosure,
) -> AnalyzeResult<ManagedCpsAnalysis>
where
    T: Iterator<Item = A>,
    A: EvalInEnv + 'static,
{
    #[derive(Trace, Finalize)]
    struct Analyzed {
        elems: Vec<ManagedAnalysis>,
        quot: usize,
    }

    impl EvalInEnv for Analyzed {
        fn call(&self, env: ManagedR7Env) -> R7Result {
            let mut res = R7Pair::default_with_quotation_level(self.quot);
            for elem in self.elems.iter() {
                res.list_append(elem.call(env.clone())?[0].clone());
            }
            // NOTE: The eval is necessary to eat the quote that
            // was seen during analysis
            res.eval(env)
        }
    }

    // Force eager collection to root objects and assert static ownership
    Ok(CpsAnalysis::managed(
        Analyzed {
            elems: analyses.map(Analysis::managed).collect(),
            quot: quotation_level,
        },
        cont,
    ))
}

/// Analyze an application ("apply", or procedure call)
fn analyze_application<A, B, F>(
    operator: B,
    operands: A,
    quotation_level: usize,
    cont: ManagedClosure,
) -> AnalyzeResult<ManagedCpsAnalysis>
where
    A: Iterator<Item = F>,
    F: EvalInEnv + 'static,
    B: EvalInEnv + 'static,
{
    #[derive(Trace, Finalize)]
    struct Analyzed {
        operator: ManagedAnalysis,
        operands: Vec<ManagedAnalysis>,
        quotation_level: usize,
    }

    impl EvalInEnv for Analyzed {
        fn call(&self, env: ManagedR7Env) -> R7Result {
            let operator = self.operator.call(env.clone())?[0].clone();
            let operands = self.operands.iter().try_fold(
                R7Pair::default_with_quotation_level(self.quotation_level),
                |mut acc, operand_proc| -> Result<R7Pair, R7Error> {
                    acc.list_append(operand_proc.call(env.clone())?[0].clone());
                    Ok(acc)
                },
            )?;

            if matches!(&*operator.borrow(), R7Value::Slot(_)) {
                operator
                    .borrow()
                    .as_proc_ref_and_then(|inner_proc| inner_proc.call_1(R7Value::pair(operands)))
            } else if let R7Value::NativeProc(proc) = &*operator.borrow() {
                proc(env, operands)
            } else {
                unreachable!("proc is either a Slot holding a procedure or a native procedure, instead got {operator:#?}.")
            }
        }
    }

    Ok(CpsAnalysis::managed(
        Analyzed {
            operator: Analysis::managed(operator),
            operands: operands.map(Analysis::managed).collect(),
            quotation_level,
        },
        cont,
    ))
}

impl EvalInEnvWithExplicitContinuation for ManagedR7Value {
    fn call_with_continuation(&self, env: ManagedR7Env, cont: ManagedClosure) -> R7Result {
        cont.call_with_values(self.borrow().evaluate(env)?)
    }
}

impl EvalInEnvWithExplicitContinuation for R7Error {
    fn call_with_continuation(&self, _env: ManagedR7Env, cont: ManagedClosure) -> R7Result {
        cont.call_1(Err(self.clone())?)
    }
}

impl EvalInEnvWithExplicitContinuation for R7Result {
    fn call_with_continuation(&self, _env: ManagedR7Env, cont: ManagedClosure) -> R7Result {
        cont.call_with_values(self.clone()?)
    }
}

impl EvalInEnvWithExplicitContinuation for R7SingleResult {
    fn call_with_continuation(&self, _env: ManagedR7Env, cont: ManagedClosure) -> R7Result {
        cont.call_with_values(self.clone().map(|v| vec![v])?)
    }
}

impl<T> EvalInEnvWithExplicitContinuation for Gc<T>
where
    T: EvalInEnv,
{
    fn call_with_continuation(&self, env: ManagedR7Env, cont: ManagedClosure) -> R7Result {
        cont.call_with_values(self.as_ref().call(env)?)
    }
}

impl<T> EvalInEnvWithExplicitContinuation for GcCell<T>
where
    T: EvalInEnv,
{
    fn call_with_continuation(&self, env: ManagedR7Env, cont: ManagedClosure) -> R7Result {
        cont.call_with_values(self.borrow().call(env)?)
    }
}

#[derive(Trace, Finalize)]
struct EnvDefineContinuation {
    env: ManagedR7Env,
    symbol: String,
}

impl RustClosure for EnvDefineContinuation {
    fn call_fn(&self, args: Vec<ManagedR7Value>) -> R7Result {
        self.check_args(&args)?;
        self.env
            .borrow_mut()
            .define(&self.symbol, args.get(0).unwrap().clone())
            .map(|val| vec![val])
    }

    fn expected_args_count(&self) -> Option<usize> {
        Some(1)
    }
}

#[derive(Trace, Finalize)]
struct EnvSetContinuation {
    env: ManagedR7Env,
    symbol: String,
}

impl RustClosure for EnvSetContinuation {
    fn call_fn(&self, args: Vec<ManagedR7Value>) -> R7Result {
        self.check_args(&args)?;
        self.env
            .borrow_mut()
            .set(&self.symbol, args.get(0).unwrap().clone())
            .map(|val| vec![val])
    }

    fn expected_args_count(&self) -> Option<usize> {
        Some(1)
    }
}

M core/src/analyze/mod.rs => core/src/analyze/mod.rs +11 -1485
@@ 2,22 2,23 @@
//
// SPDX-License-Identifier: LGPL-3.0-only

use parser::Rule;
use tracing::{debug, warn};
// mod continuations;
mod hollywood;
mod no_cps;

use crate::env::ManagedR7Env;
use crate::eval::literal::eval_number;
use crate::types::{ManagedR7Value, R7Error, R7Pair, R7Proc, R7Result, R7Value};
use gc::{Finalize, Gc, GcCell, Trace};
use gc::{Finalize, Trace};

pub trait CloseOnEnv: Trace {
    // TODO: Add parameter for an optional continuation
    fn call(&self, env: ManagedR7Env) -> R7Result;
}
pub use hollywood::{
    CpsAnalysis, CpsAnalyzer, EvalInEnvWithExplicitContinuation, ManagedCpsAnalysis,
};
pub use no_cps::{Analysis, Analyzer, EvalInEnv, ManagedAnalysis};

/// Error that happens during analysis
#[derive(Debug, Clone, Trace, Finalize)]
pub enum AnalyzeError {
    /// Incorrect syntax detected at lexing time.
    Syntax(String),
    /// Other error.
    Unknown(String),
}



@@ 32,1478 33,3 @@ impl std::fmt::Display for AnalyzeError {
}

pub type AnalyzeResult<T> = std::result::Result<T, AnalyzeError>;

#[derive(Trace, Finalize)]
pub struct Closure {
    inner: Box<dyn CloseOnEnv>,
}
pub type ManagedClosure = Gc<Closure>;

impl CloseOnEnv for Closure {
    fn call(&self, env: ManagedR7Env) -> R7Result {
        self.inner.call(env)
    }
}

impl Closure {
    pub fn managed<T: CloseOnEnv + 'static>(inner: T) -> ManagedClosure {
        Gc::new(Self {
            inner: Box::new(inner),
        })
    }
}

impl std::fmt::Debug for Closure {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Closure")
            .field("inner", &"type erased CloseOnEnv")
            .finish()
    }
}

impl Default for Closure {
    fn default() -> Self {
        Self {
            inner: Box::new(R7Error::UninitClosureSlot),
        }
    }
}

#[derive(Default)]
pub struct Analyzer {
    quotation_level: usize,
}

impl Analyzer {
    #[tracing::instrument(skip(self, ast))]
    fn analyze_r7rs(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the r7rs".to_string(),
            )),
            |acc, pair| match pair.as_rule() {
                Rule::r7rs => {
                    unreachable!("The r7rs rule is not matched within itself")
                }
                Rule::EOI | Rule::COMMENT | Rule::atmosphere | Rule::WHITESPACE => acc,
                Rule::program => Ok(Closure::managed(self.analyze_program(pair)?)),
                Rule::library => {
                    todo!("library")
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_program(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        sequence(
            ast.into_inner()
                .map(|pair| match pair.as_rule() {
                    Rule::command_or_definition => self
                        .analyze_command_or_definition(pair)
                        .map(Closure::managed),
                    unhandled_rule => {
                        todo!("Unhandled rule: {:#?}", unhandled_rule)
                    }
                })
                .collect::<AnalyzeResult<Vec<_>>>()?
                .into_iter(),
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_command_or_definition(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedClosure> {
        sequence(
            ast.into_inner()
                .map(|pair| match pair.as_rule() {
                    Rule::expression => self.analyze_expression(pair).map(Closure::managed),
                    Rule::definition => self.analyze_definition(pair).map(Closure::managed),
                    Rule::command_or_definition => self
                        .analyze_command_or_definition(pair)
                        .map(Closure::managed),
                    unhandled_rule => {
                        todo!("Unhandled rule: {:#?}", unhandled_rule)
                    }
                })
                .collect::<AnalyzeResult<Vec<_>>>()?
                .into_iter(),
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_definition(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        let mut ast_iter = ast.into_inner();
        let definition_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| AnalyzeError::Syntax("lexer can't find a definition".into()))?;
        match definition_kind {
            Rule::single_value_definition => {
                #[derive(Trace, Finalize)]
                struct Analyzed {
                    val_proc: ManagedClosure,
                    symbol: String,
                    quotation_level: usize,
                }

                impl CloseOnEnv for Analyzed {
                    fn call(&self, env: ManagedR7Env) -> R7Result {
                        let value = self.val_proc.call(env.clone())?;
                        env.borrow_mut().define(&self.symbol, value)
                    }
                }

                let symbol = ast_iter.next().unwrap().as_str().to_string();
                let val_proc =
                    Closure::managed(self.analyze_expression(ast_iter.next().ok_or_else(
                        || AnalyzeError::Syntax("expected expression".to_string()),
                    )?)?);
                let quotation_level = self.quotation_level;

                Ok(Closure::managed(Analyzed {
                    val_proc,
                    symbol,
                    quotation_level,
                }))
            }
            Rule::lambda_definition => {
                #[derive(Trace, Finalize)]
                struct Analyzed {
                    docstring: String,
                    locals: Vec<String>,
                    name: R7Value,
                    body: ManagedClosure,
                    last_arg_is_list: bool,
                }

                impl CloseOnEnv for Analyzed {
                    fn call(&self, env: ManagedR7Env) -> R7Result {
                        let proc = R7Value::procedure(R7Proc::new(
                            self.docstring.clone(),
                            self.locals.clone(),
                            self.body.clone(),
                            env.clone(),
                            self.last_arg_is_list,
                        ));
                        env.borrow_mut()
                            .define(&self.name.symbol_name()?, proc.into())
                    }
                }

                let docstring: String = String::new();
                let mut locals: Vec<String> = Vec::new();
                let mut name = R7Value::null();
                let mut body = ManagedClosure::default();
                let mut last_arg_is_list = false;
                for (i, elem) in ast_iter.enumerate() {
                    // The first element is the name of the lambda
                    if i == 0 {
                        debug_assert_eq!(elem.as_rule(), Rule::identifier);
                        debug!("Defining {} lambda", elem.as_str());
                        name = R7Value::symbol(elem.as_str());
                    } else if i == 1 {
                        debug_assert_eq!(elem.as_rule(), Rule::def_formals);
                        elem.into_inner().for_each(|formal| {
                            if formal.as_rule() == Rule::rest_identifier {
                                last_arg_is_list = true;
                                locals.push(formal.as_str().into());
                                return;
                            }
                            debug_assert_eq!(formal.as_rule(), Rule::identifier);
                            debug!("Adding {} to formal argument list", formal.as_str());
                            locals.push(formal.as_str().into());
                        })
                    } else {
                        debug_assert_eq!(elem.as_rule(), Rule::body);
                        body = sequence(
                            elem.into_inner()
                                .map(|part| self.analyze(part).map(Closure::managed))
                                .collect::<AnalyzeResult<Vec<_>>>()?
                                .into_iter(),
                        )?
                    }
                }

                Ok(Closure::managed(Analyzed {
                    docstring,
                    locals,
                    name,
                    body,
                    last_arg_is_list,
                }))
            }
            Rule::syntax_definition => {
                todo!("syntax_definition")
            }
            Rule::multiple_values_definition => {
                todo!("multiple_values_definition")
            }
            Rule::record_definition => {
                todo!("record_definition")
            }
            Rule::multiple_definitions => sequence(
                ast_iter
                    .map(|pair| self.analyze_definition(pair).map(Closure::managed))
                    .collect::<AnalyzeResult<Vec<_>>>()?
                    .into_iter(),
            ),
            _ => Err(AnalyzeError::Syntax("unknown definition pattern".into())),
        }
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_expression(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the expression".into(),
            )),
            |_acc, pair| -> AnalyzeResult<ManagedClosure> {
                match pair.as_rule() {
                    Rule::identifier => {
                        let variable_name = pair.as_str().to_string();
                        if self.quotation_level == 0 {
                            #[derive(Trace, Finalize)]
                            struct Analyzed {
                                variable_name: String,
                            }

                            impl CloseOnEnv for Analyzed {
                                fn call(&self, env: ManagedR7Env) -> R7Result {
                                    env.borrow().get(&self.variable_name)
                                }
                            }
                            Ok(Closure::managed(Analyzed { variable_name }))
                        } else {
                            Ok(Closure::managed(ManagedR7Value::from(R7Value::symbol(
                                &variable_name,
                            ))))
                        }
                    }
                    Rule::expression => {
                        // Recursive call because eval_lambda calls eval_expression on the body, which usually is a sequence, i.e. a {expression+}
                        self.analyze_expression(pair)
                    }
                    Rule::literal => self.analyze_literal(pair),
                    // assignment and procedure_call cases almost share the same code,
                    // as set! is defined as a native proc in the default environment
                    Rule::assignment => {
                        #[derive(Trace, Finalize)]
                        struct Analyzed {
                            symbol: ManagedR7Value,
                            val_proc: ManagedClosure,
                            quot: usize,
                        }

                        impl CloseOnEnv for Analyzed {
                            fn call(&self, env: ManagedR7Env) -> R7Result {
                                let mut elements = R7Pair::default_with_quotation_level(self.quot);
                                elements.list_append(self.symbol.clone());
                                elements.list_append(self.val_proc.call(env.clone())?);
                                crate::stdlib::base::set(env, elements).map(|tup| tup.0)
                            }
                        }

                        let mut ast_iter = pair.into_inner();
                        let symbol = ManagedR7Value::from(R7Value::symbol(
                            ast_iter
                                .next()
                                .ok_or_else(|| AnalyzeError::Syntax("expected a symbol".into()))?
                                .as_str(),
                        ));
                        let val_proc = self.analyze_expression(
                            ast_iter
                                .next()
                                .ok_or_else(|| AnalyzeError::Syntax("expected a value".into()))?,
                        )?;
                        let quot = self.quotation_level;

                        Ok(Closure::managed(Analyzed {
                            symbol,
                            val_proc,
                            quot,
                        }))
                    }
                    Rule::procedure_call => {
                        let mut elements: Vec<ManagedClosure> = Vec::new();
                        for elem in pair.into_inner() {
                            elements.push(self.analyze_expression(elem)?);
                        }
                        if self.quotation_level == 0 {
                            let (operator, operands) = elements
                                .split_first()
                                .expect("The parser/lexer found at least one operator.");
                            analyze_application(operator.clone(), operands.iter().cloned(), 0)
                        } else {
                            #[derive(Trace, Finalize)]
                            struct Analyzed {
                                elements: Vec<ManagedClosure>,
                            }

                            impl CloseOnEnv for Analyzed {
                                fn call(&self, env: ManagedR7Env) -> R7Result {
                                    self.elements
                                        .iter()
                                        .try_fold(R7Pair::default(), |mut acc, operand_proc| {
                                            acc.list_append(operand_proc.call(env.clone())?);
                                            Ok(acc)
                                        })
                                        .map(|pair| ManagedR7Value::from(R7Value::from(pair)))
                                }
                            }

                            Ok(Closure::managed(Analyzed { elements }))
                        }
                    }
                    Rule::operator => self.analyze_expression(pair),
                    Rule::operand => self.analyze_expression(pair),
                    Rule::lambda_expression => self.analyze_lambda(pair),
                    Rule::conditional => self.analyze_conditional(pair),
                    Rule::derived_expression => self.analyze_derived_expr(pair),
                    unhandled_rule => {
                        todo!("Unhandled rule: {:#?}", unhandled_rule)
                    }
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_literal(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        use crate::eval::literal::*;
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the literal".into(),
            )),
            |_acc, pair| match pair.as_rule() {
                Rule::boolean => {
                    let res = eval_boolean(pair);
                    Ok(Closure::managed(res))
                }
                Rule::character => {
                    let res = eval_character(pair);
                    Ok(Closure::managed(res))
                }
                Rule::bytevector => {
                    let res = eval_bytevector(pair);
                    Ok(Closure::managed(res))
                }
                Rule::number => {
                    let res = eval_number(pair);
                    Ok(Closure::managed(res))
                }
                Rule::quotation => self.analyze_quotation(pair),
                unhandled_rule => {
                    todo!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_quotation(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax("No evaluable code in the r7rs".into())),
            |_acc, pair| match pair.as_rule() {
                Rule::datum => {
                    self.quotation_level += 1;
                    let res = self.analyze_datum(pair);
                    self.quotation_level -= 1;
                    res
                }
                // As per parser/src/r7rs.pest grammar definition,
                // if we call this function only in case we hit a quotation
                // node, then all other cases are unreachable
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_datum(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        use crate::eval::literal::*;
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the datum".into(),
            )),
            |_acc, pair| match pair.as_rule() {
                Rule::boolean => Ok(Closure::managed(eval_boolean(pair))),
                Rule::character => Ok(Closure::managed(eval_character(pair))),
                Rule::number => Ok(Closure::managed(eval_number(pair))),
                Rule::symbol => Ok(Closure::managed(ManagedR7Value::from(R7Value::symbol(
                    pair.as_str(),
                )))),
                Rule::list => {
                    #[derive(Trace, Finalize)]
                    struct Analyzed {
                        elems: Vec<ManagedClosure>,
                        quot: usize,
                    }

                    impl CloseOnEnv for Analyzed {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            let mut res = R7Pair::default_with_quotation_level(self.quot);
                            for elem in self.elems.iter() {
                                res.list_append(elem.call(env.clone())?);
                            }
                            // NOTE: The eval is necessary to eat the quote that
                            // was seen during analysis
                            res.eval(env).map(|tup| tup.0)
                        }
                    }

                    let elems = pair
                        .into_inner()
                        .map(|elem| self.analyze_datum(elem))
                        .collect::<AnalyzeResult<Vec<_>>>()?;
                    let quot = self.quotation_level;

                    Ok(Closure::managed(Analyzed { elems, quot }))
                }
                unhandled_rule => {
                    todo!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_lambda(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        #[derive(Trace, Finalize)]
        struct Analyzed {
            locals: Vec<String>,
            docstring: String,
            body: ManagedClosure,
            last_arg_is_list: bool,
        }

        impl CloseOnEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                Ok(R7Value::procedure(R7Proc::new(
                    self.docstring.clone(),
                    self.locals.clone(),
                    self.body.clone(),
                    env,
                    self.last_arg_is_list,
                ))
                .into())
            }
        }

        let mut locals: Vec<String> = Vec::new();
        let docstring: String = String::new();
        let mut body = ManagedClosure::default();
        let mut last_arg_is_list = false;
        for pair in ast.into_inner() {
            match pair.as_rule() {
                Rule::formals => {
                    // If the formals are just "identifier", then it means the only locals should
                    // be bound as a list
                    if !pair.as_str().starts_with('(') {
                        last_arg_is_list = true;
                    }
                    pair.into_inner().for_each(|formal| {
                        if formal.as_rule() == Rule::rest_identifier {
                            last_arg_is_list = true;
                            locals.push(formal.as_str().into());
                            return;
                        }
                        debug_assert_eq!(formal.as_rule(), Rule::identifier);
                        locals.push(formal.as_str().into());
                    })
                }
                Rule::body => {
                    // FIXME: Handle definitions at the beginning of the body

                    // False positive because of the extra Clone trait bound on
                    // sequence argument
                    #[allow(clippy::needless_collect)]
                    let body_parts: Vec<_> = pair
                        .into_inner()
                        .map(|part| self.analyze(part))
                        .collect::<AnalyzeResult<_>>()?;
                    body = sequence(body_parts.into_iter())?;
                }
                _ => {
                    return Err(AnalyzeError::Syntax("unexpected token".into()));
                }
            }
        }

        Ok(Closure::managed(Analyzed {
            locals,
            docstring,
            body,
            last_arg_is_list,
        }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_sequence(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        let ast_iter = ast.into_inner();
        // False positive because of the extra Clone trait bound on
        // sequence argument
        #[allow(clippy::needless_collect)]
        let body_parts: Vec<_> = ast_iter
            .map(|part| self.analyze(part))
            .collect::<AnalyzeResult<_>>()?;
        sequence(body_parts.into_iter())
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_conditional(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        #[derive(Trace, Finalize)]
        struct Analyzed {
            test: ManagedClosure,
            consequent: ManagedClosure,
            alternate: ManagedClosure,
        }
        impl CloseOnEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let predicate = self.test.call(env.clone())?;
                if predicate.borrow().as_bool() {
                    self.consequent.call(env)
                } else {
                    self.alternate.call(env)
                }
            }
        }

        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::conditional_if);
        let mut test = ManagedClosure::default();
        let mut consequent = ManagedClosure::default();
        // This decides the default value when there is no alternate
        let mut alternate = Closure::managed(ManagedR7Value::from(R7Value::f()));
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    test = self.analyze(elem)?;
                }
                Rule::consequent => {
                    consequent = self.analyze(elem)?;
                }
                Rule::alternate => {
                    alternate = self.analyze(elem)?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Closure::managed(Analyzed {
            test,
            consequent,
            alternate,
        }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        // TODO: Get rid of that clone
        let mut ast_iter = ast.clone().into_inner();
        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| AnalyzeError::Syntax("lexer can't find a derived expression".into()))?;
        match expr_kind {
            Rule::derived_expr_case_no_else | Rule::derived_expr_case => {
                self.analyze_derived_expr_case(ast)
            }
            Rule::derived_expr_cond | Rule::derived_expr_cond_no_else => {
                self.analyze_derived_expr_cond(ast)
            }
            Rule::derived_expr_and => self.analyze_derived_expr_and(ast),
            Rule::derived_expr_or => self.analyze_derived_expr_or(ast),
            Rule::derived_expr_when => self.analyze_derived_expr_when(ast),
            Rule::derived_expr_unless => self.analyze_derived_expr_unless(ast),
            Rule::binding_let => self.analyze_derived_expr_binding_let(ast, false),
            Rule::binding_let_star => self.analyze_derived_expr_binding_let(ast, true),
            // REVIEW: "star" has NO effect on the letrec analyses. Maybe there's something
            // I didn't get in the semantics that's really important?
            Rule::binding_letrec => self.analyze_derived_expr_binding_letrec(ast, false),
            Rule::binding_letrec_star => self.analyze_derived_expr_binding_letrec(ast, true),
            unhandled_rule => {
                todo!("Unhandled rule: {:#?}", unhandled_rule)
            }
        }
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_case(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedClosure> {
        let mut ast_iter = ast.into_inner().peekable();
        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        debug_assert!(matches!(
            expr_kind,
            Rule::derived_expr_case_no_else | Rule::derived_expr_case
        ));

        #[derive(Trace, Finalize)]
        struct Analyzed {
            case_expr: ManagedClosure,
            case_clauses: Vec<(
                /* test */ ManagedClosure,
                /* consequent */ ManagedClosure,
            )>,
            else_clause: ManagedClosure,
        }

        impl CloseOnEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                for (test, consequent) in self.case_clauses.iter() {
                    if test.call(env.clone())?.borrow().as_bool() {
                        return consequent.call(env);
                    }
                }
                self.else_clause.call(env)
            }
        }

        let mut case_expr = ManagedClosure::default();
        let mut case_clauses = Vec::new();
        // This default value controls the output when there is no else clause.
        let mut else_clause = Closure::managed(ManagedR7Value::from(R7Value::f()));

        while let Some(elem) = ast_iter.next() {
            match elem.as_rule() {
                Rule::expression => case_expr = self.analyze_expression(elem)?,
                Rule::case_clause => {
                    case_clauses.push(self.analyze_case_clause(case_expr.clone(), elem)?);
                }
                Rule::derived_expr_else => {
                    let else_val = ast_iter.next().ok_or_else(|| {
                        AnalyzeError::Syntax("Missing sequence after else clause".into())
                    })?;
                    match else_val.as_rule() {
                        Rule::sequence => {
                            else_clause = self.analyze(else_val)?;
                        }
                        Rule::recipient => {
                            let proc = self.analyze(else_val)?;
                            else_clause = analyze_application(
                                proc,
                                std::iter::once(case_expr.clone()),
                                self.quotation_level,
                            )?;
                        }
                        unhandled_rule => {
                            return Err(AnalyzeError::Syntax(format!(
                                "Unhandled rule: expecting sequence or recipient {:#?}",
                                unhandled_rule
                            )))
                        }
                    }
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Closure::managed(Analyzed {
            case_expr,
            case_clauses,
            else_clause,
        }))
    }

    #[tracing::instrument(skip(self, ast, target))]
    fn analyze_case_clause<'ast>(
        &mut self,
        target: ManagedClosure,
        ast: parser::Pair<'ast, Rule>,
    ) -> AnalyzeResult<(ManagedClosure, ManagedClosure)> {
        let mut test = ManagedClosure::default();
        let mut consequent = ManagedClosure::default();

        let mut clause_value_set: Vec<ManagedClosure> = Vec::new();

        let ast_iter = ast.into_inner();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::datum => {
                    let clause_value = self.analyze_datum(elem)?;
                    clause_value_set.push(clause_value);
                }
                Rule::recipient => {
                    let proc = self.analyze(elem)?;
                    test = Closure::managed(ManagedR7Value::from(R7Value::t()));

                    return Ok((
                        test,
                        analyze_application(proc, std::iter::once(target), self.quotation_level)?,
                    ));
                }
                Rule::sequence => {
                    consequent = self.analyze_sequence(elem)?;

                    #[derive(Trace, Finalize)]
                    struct Analyzed {
                        clause_value_set: Vec<ManagedClosure>,
                        target: ManagedClosure,
                    }

                    impl CloseOnEnv for Analyzed {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            let targ_val = self.target.call(env.clone())?;
                            Ok(ManagedR7Value::from(R7Value::from(
                                self.clause_value_set.iter().any(|test| {
                                    test.call(env.clone()).map_or(false, |val| val == targ_val)
                                }),
                            )))
                        }
                    }

                    return Ok((
                        Closure::managed(Analyzed {
                            clause_value_set,
                            target,
                        }),
                        consequent,
                    ));
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }
        unreachable!("No sequence on that call. Should be an error instead of a panic here.")
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_cond(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedClosure> {
        let mut ast_iter = ast.into_inner().peekable();
        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        debug_assert!(matches!(
            expr_kind,
            Rule::derived_expr_cond_no_else | Rule::derived_expr_cond
        ));

        #[derive(Trace, Finalize)]
        struct Analyzed {
            cond_clauses: Vec<(
                /* test */ ManagedClosure,
                /* consequent */ ManagedClosure,
            )>,
            else_clause: ManagedClosure,
        }

        impl CloseOnEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                for (test, consequent) in self.cond_clauses.iter() {
                    if test.call(env.clone())?.borrow().as_bool() {
                        return consequent.call(env);
                    }
                }
                self.else_clause.call(env)
            }
        }

        let mut cond_clauses = Vec::new();
        // This default value controls the output when there is no else clause.
        let mut else_clause = Closure::managed(ManagedR7Value::from(R7Value::f()));

        while let Some(elem) = ast_iter.next() {
            match elem.as_rule() {
                Rule::cond_clause => {
                    cond_clauses.push(self.analyze_cond_clause(elem)?);
                }
                Rule::derived_expr_else => {
                    let else_val = ast_iter.next().ok_or_else(|| {
                        AnalyzeError::Syntax("Missing sequence after else clause".into())
                    })?;
                    match else_val.as_rule() {
                        Rule::sequence => {
                            else_clause = self.analyze(else_val)?;
                        }
                        unhandled_rule => {
                            return Err(AnalyzeError::Syntax(format!(
                                "Unhandled rule: expecting sequence {:#?}",
                                unhandled_rule
                            )))
                        }
                    }
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Closure::managed(Analyzed {
            cond_clauses,
            else_clause,
        }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_cond_clause<'ast>(
        &mut self,
        ast: parser::Pair<'ast, Rule>,
    ) -> AnalyzeResult<(
        /* test */ ManagedClosure,
        /* consequent */ ManagedClosure,
    )> {
        let mut test = ManagedClosure::default();
        let mut consequent = ManagedClosure::default();

        let mut ast_iter = ast.into_inner();
        let test_ast = ast_iter
            .next()
            .ok_or_else(|| AnalyzeError::Syntax("Expecting a test for the cond".into()))?;
        test = self.analyze(test_ast)?;

        consequent = ast_iter.next().map_or_else(
            || Ok(test.clone()),
            |cons_ast| match cons_ast.as_rule() {
                Rule::sequence => self.analyze(cons_ast),
                Rule::recipient => {
                    let proc = self.analyze(cons_ast)?;
                    let quotation_level = self.quotation_level;
                    let target = test.clone();
                    analyze_application(proc, std::iter::once(target), quotation_level)
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )?;

        Ok((test, consequent))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_and(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedClosure> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_and);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            arguments: Vec<ManagedClosure>,
        }
        impl CloseOnEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let mut args_iter = self.arguments.iter().peekable();
                while let Some(arg) = args_iter.next() {
                    let val = arg.call(env.clone())?;
                    if !val.borrow().as_bool() {
                        return Ok(R7Value::f().into());
                    }
                    if args_iter.peek().is_none() {
                        return Ok(val);
                    }
                }
                Ok(R7Value::t().into())
            }
        }

        let mut arguments = Vec::new();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    arguments.push(self.analyze(elem)?);
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }
        Ok(Closure::managed(Analyzed { arguments }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_or(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedClosure> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_or);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            arguments: Vec<ManagedClosure>,
        }
        impl CloseOnEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                for arg in self.arguments.iter() {
                    let val = arg.call(env.clone())?;
                    if val.borrow().as_bool() {
                        return Ok(val);
                    }
                }
                Ok(R7Value::f().into())
            }
        }

        let mut arguments = Vec::new();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    arguments.push(self.analyze(elem)?);
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Closure::managed(Analyzed { arguments }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_when(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedClosure> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_when);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            test: ManagedClosure,
            seq: ManagedClosure,
        }

        impl CloseOnEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                if self.test.call(env.clone())?.borrow().as_bool() {
                    self.seq.call(env)
                } else {
                    Ok(R7Value::f().into())
                }
            }
        }

        let mut seq = ManagedClosure::default();
        let mut test = ManagedClosure::default();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    test = self.analyze(elem)?;
                }
                Rule::sequence => {
                    seq = self.analyze(elem)?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }
        Ok(Closure::managed(Analyzed { test, seq }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_unless(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedClosure> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_when);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            test: ManagedClosure,
            seq: ManagedClosure,
        }

        impl CloseOnEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                if !self.test.call(env.clone())?.borrow().as_bool() {
                    self.seq.call(env)
                } else {
                    Ok(R7Value::f().into())
                }
            }
        }

        let mut seq = ManagedClosure::default();
        let mut test = ManagedClosure::default();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    test = self.analyze(elem)?;
                }
                Rule::sequence => {
                    seq = self.analyze(elem)?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Closure::managed(Analyzed { test, seq }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_binding_let(
        &mut self,
        ast: parser::Pair<Rule>,
        star: bool,
    ) -> AnalyzeResult<ManagedClosure> {
        let mut ast_iter = ast.into_inner().peekable();

        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        match star {
            true => debug_assert!(matches!(expr_kind, Rule::binding_let_star)),
            false => debug_assert!(matches!(expr_kind, Rule::binding_let)),
        }

        #[derive(Trace, Finalize)]
        struct Analyzed {
            binds: Vec<ManagedClosure>,
            body: ManagedClosure,
        }

        impl CloseOnEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let binds_env: ManagedR7Env = crate::env::R7Env::new((&env).into()).into();

                for binding in self.binds.iter() {
                    binding.call(binds_env.clone())?;
                }

                self.body.call(binds_env)
            }
        }

        let mut binds = Vec::new();
        let mut body = Closure::managed(ManagedR7Value::from(R7Value::null()));

        for elem in ast_iter {
            match elem.as_rule() {
                Rule::binding_spec => {
                    #[derive(Trace, Finalize)]
                    struct AnalyzedBind {
                        symbol: String,
                        val_proc: ManagedClosure,
                        // the difference between let and let*
                        eval_in_parent: bool,
                    }
                    impl CloseOnEnv for AnalyzedBind {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            let val = self.val_proc.call(if self.eval_in_parent {
                                env.borrow().parent().ok_or_else(|| {
                                    R7Error::Unknown(
                                        "No parent environment to evaluate binding in".to_string(),
                                    )
                                })?
                            } else {
                                env.clone()
                            })?;
                            (&mut *env.borrow_mut()).define(&self.symbol, val)
                        }
                    }

                    let mut binding = elem.into_inner();
                    let ident = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(ident.as_rule(), Rule::identifier);
                    let symbol = ident.as_str().to_string();
                    let value = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(value.as_rule(), Rule::expression);
                    let val_proc = self.analyze_expression(value)?;

                    binds.push(Closure::managed(AnalyzedBind {
                        symbol,
                        val_proc,
                        eval_in_parent: !star,
                    }));
                }
                Rule::body => {
                    body = self.analyze_sequence(elem.into_inner().next().unwrap())?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Closure::managed(Analyzed { body, binds }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_binding_letrec(
        &mut self,
        ast: parser::Pair<Rule>,
        star: bool,
    ) -> AnalyzeResult<ManagedClosure> {
        let mut ast_iter = ast.clone().into_inner();

        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        match star {
            true => debug_assert!(matches!(expr_kind, Rule::binding_letrec_star)),
            false => debug_assert!(matches!(expr_kind, Rule::binding_letrec)),
        }

        #[derive(Trace, Finalize)]
        struct Analyzed {
            init_binds: Vec<ManagedClosure>,
            binds: Vec<ManagedClosure>,
            body: ManagedClosure,
        }

        impl CloseOnEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let binds_env: ManagedR7Env = crate::env::R7Env::new((&env).into()).into();

                for binding in self.init_binds.iter() {
                    binding.call(binds_env.clone())?;
                }

                for binding in self.binds.iter() {
                    binding.call(binds_env.clone())?;
                }

                self.body.call(binds_env)
            }
        }

        let mut binds = Vec::new();
        let mut init_binds = Vec::new();
        let mut body = Closure::managed(ManagedR7Value::from(R7Value::null()));

        // First loop to accumulate initial bindings
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::binding_spec => {
                    #[derive(Trace, Finalize)]
                    struct AnalyzedInitBind {
                        symbol: String,
                        eval_in_parent: bool,
                    }
                    impl CloseOnEnv for AnalyzedInitBind {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            (&mut *env.borrow_mut()).define(
                                &self.symbol,
                                R7Value::DynamicBinding(self.symbol.clone()).into(),
                            )
                        }
                    }

                    let mut binding = elem.into_inner();
                    let ident = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(ident.as_rule(), Rule::identifier);
                    let symbol = ident.as_str().to_string();
                    let value = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(value.as_rule(), Rule::expression);

                    init_binds.push(Closure::managed(AnalyzedInitBind {
                        symbol: symbol.clone(),
                        eval_in_parent: !star,
                    }));
                }
                Rule::body => {
                    break;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        // Skipping the letrec keyword
        for elem in ast.into_inner().into_iter().skip(1) {
            match elem.as_rule() {
                Rule::binding_spec => {
                    #[derive(Trace, Finalize)]
                    struct AnalyzedBind {
                        symbol: String,
                        val_proc: ManagedClosure,
                        init_binds: Vec<ManagedClosure>,
                        // the difference between let and let*
                        eval_in_parent: bool,
                    }
                    impl CloseOnEnv for AnalyzedBind {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            let val = self.val_proc.call(env.clone())?;
                            (&mut *env.borrow_mut()).set(&self.symbol, val)
                        }
                    }

                    let mut binding = elem.into_inner();
                    let ident = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(ident.as_rule(), Rule::identifier);
                    let symbol = ident.as_str().to_string();
                    let value = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(value.as_rule(), Rule::expression);
                    let val_proc = self.analyze_expression(value)?;

                    binds.push(Closure::managed(AnalyzedBind {
                        symbol,
                        init_binds: init_binds.clone(),
                        val_proc,
                        eval_in_parent: !star,
                    }));
                }
                Rule::body => {
                    body = self.analyze_sequence(elem.into_inner().next().unwrap())?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Closure::managed(Analyzed {
            body,
            binds,
            init_binds,
        }))
    }

    /// Analyze a parsed tree to return a procedure that can
    /// be use to evaluate the result multiple times according
    /// to the environment.
    #[tracing::instrument(skip(self, ast))]
    pub fn analyze(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedClosure> {
        match ast.as_rule() {
            Rule::EOI => Ok(Closure::managed(ManagedR7Value::from(R7Value::null()))),
            Rule::r7rs => self.analyze_r7rs(ast),
            Rule::number => Ok(Closure::managed(eval_number(ast))),
            Rule::datum => self.analyze_datum(ast),
            Rule::literal => self.analyze_literal(ast),
            Rule::suffix
            | Rule::infnan
            | Rule::exponent_marker
            | Rule::exactness
            | Rule::radix_2
            | Rule::radix_8
            | Rule::radix_10
            | Rule::radix_16
            | Rule::sign
            | Rule::num_2
            | Rule::complex_2
            | Rule::real_2
            | Rule::ureal_2
            | Rule::uinteger_2
            | Rule::prefix_2
            | Rule::num_8
            | Rule::complex_8
            | Rule::real_8
            | Rule::ureal_8
            | Rule::uinteger_8
            | Rule::prefix_8
            | Rule::num_10
            | Rule::complex_10
            | Rule::real_10
            | Rule::ureal_10
            | Rule::uinteger_10
            | Rule::prefix_10
            | Rule::decimal_10
            | Rule::num_16
            | Rule::complex_16
            | Rule::real_16
            | Rule::ureal_16
            | Rule::uinteger_16
            | Rule::prefix_16 => unreachable!(
                "Inner number rule during analysis phase: {:?}",
                ast.as_rule()
            ),
            Rule::sequence => self.analyze_sequence(ast),
            Rule::expression => self.analyze_expression(ast),
            // Basic "{ expression }" aliases
            Rule::test
            | Rule::cond_test
            | Rule::consequent
            | Rule::alternate
            | Rule::operator
            | Rule::operand
            | Rule::recipient
            | Rule::init
            | Rule::step
            | Rule::qq_template_0 => self.analyze(ast.into_inner().next().unwrap()),
            unhandled_rule => {
                todo!("Unhandled rule: {:#?}", unhandled_rule)
            }
        }
    }
}

/// Analyze a sequence of analysis.
///
/// Equivalent to calling all the analyses in order inconditionnally
fn sequence<T>(analyses: T) -> AnalyzeResult<ManagedClosure>
where
    T: Iterator<Item = ManagedClosure>,
{
    #[derive(Trace, Finalize)]
    struct Analyzed {
        parts: Vec<ManagedClosure>,
    }

    impl CloseOnEnv for Analyzed {
        fn call(&self, env: ManagedR7Env) -> R7Result {
            let mut folded: ManagedR7Value = R7Value::null().into();
            for analysed in self.parts.iter() {
                folded = analysed.call(env.clone())?;
            }
            Ok(folded)
        }
    }

    // Force eager collection to root objects and assert static ownership
    Ok(Closure::managed(Analyzed {
        parts: analyses.collect(),
    }))
}

/// Analyze an application ("apply", or procedure call)
fn analyze_application<A>(
    operator: ManagedClosure,
    operands: A,
    quotation_level: usize,
) -> AnalyzeResult<ManagedClosure>
where
    A: Iterator<Item = ManagedClosure>,
{
    #[derive(Trace, Finalize)]
    struct Analyzed {
        operator: ManagedClosure,
        operands: Vec<ManagedClosure>,
        quotation_level: usize,
    }

    impl CloseOnEnv for Analyzed {
        fn call(&self, env: ManagedR7Env) -> R7Result {
            let operator = self.operator.call(env.clone())?;
            let operands = self.operands.iter().try_fold(
                R7Pair::default_with_quotation_level(self.quotation_level),
                |mut acc, operand_proc| -> Result<R7Pair, R7Error> {
                    acc.list_append(operand_proc.call(env.clone())?);
                    Ok(acc)
                },
            )?;

            if matches!(&*operator.borrow(), R7Value::Slot(_)) {
                operator
                    .borrow()
                    .as_proc_ref_and_then(|inner_proc| inner_proc.apply(R7Value::pair(operands)))
                    .map(|tup| tup.0)
            } else if let R7Value::NativeProc(proc) = &*operator.borrow() {
                proc(env, operands).map(|tup| tup.0)
            } else {
                unreachable!("proc is either a Slot holding a procedure or a native procedure, instead got {operator:#?}.")
            }
        }
    }

    Ok(Closure::managed(Analyzed {
        operator,
        operands: operands.collect(),
        quotation_level,
    }))
}

impl CloseOnEnv for ManagedR7Value {
    fn call(&self, env: ManagedR7Env) -> R7Result {
        self.borrow().evaluate(env).map(|tup| tup.0)
    }
}

impl CloseOnEnv for R7Error {
    fn call(&self, _env: ManagedR7Env) -> R7Result {
        Err(self.clone())
    }
}

impl CloseOnEnv for R7Result {
    fn call(&self, _env: ManagedR7Env) -> R7Result {
        self.clone()
    }
}

impl<T> CloseOnEnv for Gc<T>
where
    T: CloseOnEnv,
{
    fn call(&self, env: ManagedR7Env) -> R7Result {
        self.as_ref().call(env)
    }
}

impl<T> CloseOnEnv for GcCell<T>
where
    T: CloseOnEnv,
{
    fn call(&self, env: ManagedR7Env) -> R7Result {
        self.borrow().call(env)
    }
}

A core/src/analyze/no_cps.rs => core/src/analyze/no_cps.rs +1528 -0
@@ 0,0 1,1528 @@
// SPDX-FileCopyrightText: 2022 Gerry Agbobada <git@gagbo.net>
//
// SPDX-License-Identifier: LGPL-3.0-only

use parser::Rule;
use tracing::{debug, warn};

use crate::env::ManagedR7Env;
use crate::eval::literal::eval_number;
use crate::types::{
    Closure, ManagedClosure, ManagedR7Value, R7Error, R7Pair, R7Result, R7SingleResult, R7Value,
};
use gc::{Finalize, Gc, GcCell, Trace};

use super::{AnalyzeError, AnalyzeResult, EvalInEnvWithExplicitContinuation};

/// A trait for objects that can execute runtime statements on a given
/// enviroment.
///
/// This trait is a [Trace] supertrait to allow such objects to be tracked in a
/// garbage collected environment.
pub trait EvalInEnv: Trace {
    fn call(&self, env: ManagedR7Env) -> R7Result;
}

#[derive(Trace, Finalize)]
pub struct Analysis {
    inner: Box<dyn EvalInEnv>,
}
pub type ManagedAnalysis = Gc<Analysis>;

impl EvalInEnv for Analysis {
    fn call(&self, env: ManagedR7Env) -> R7Result {
        self.inner.call(env)
    }
}

impl EvalInEnvWithExplicitContinuation for Analysis {
    fn call_with_continuation(&self, env: ManagedR7Env, cont: ManagedClosure) -> R7Result {
        cont.call_with_values(self.inner.call(env)?)
    }
}

impl Analysis {
    pub fn managed<T: EvalInEnv + 'static>(inner: T) -> ManagedAnalysis {
        Gc::new(Self {
            inner: Box::new(inner),
        })
    }
}

impl std::fmt::Debug for Analysis {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Analysis")
            .field("inner", &"type erased CallInEnv")
            .finish()
    }
}

impl Default for Analysis {
    fn default() -> Self {
        Self {
            inner: Box::new(R7Error::UninitClosureSlot),
        }
    }
}

#[derive(Default)]
pub struct Analyzer {
    quotation_level: usize,
}

impl Analyzer {
    #[tracing::instrument(skip(self, ast))]
    fn analyze_r7rs(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the r7rs".to_string(),
            )),
            |acc, pair| match pair.as_rule() {
                Rule::r7rs => {
                    unreachable!("The r7rs rule is not matched within itself")
                }
                Rule::EOI | Rule::COMMENT | Rule::atmosphere | Rule::WHITESPACE => acc,
                Rule::program => Ok(Analysis::managed(self.analyze_program(pair)?)),
                Rule::library => {
                    todo!("library")
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_program(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        sequence(
            ast.into_inner()
                .map(|pair| match pair.as_rule() {
                    Rule::command_or_definition => self
                        .analyze_command_or_definition(pair)
                        .map(Analysis::managed),
                    unhandled_rule => {
                        todo!("Unhandled rule: {:#?}", unhandled_rule)
                    }
                })
                .collect::<AnalyzeResult<Vec<_>>>()?
                .into_iter(),
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_command_or_definition(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedAnalysis> {
        sequence(
            ast.into_inner()
                .map(|pair| match pair.as_rule() {
                    Rule::expression => self.analyze_expression(pair).map(Analysis::managed),
                    Rule::definition => self.analyze_definition(pair).map(Analysis::managed),
                    Rule::command_or_definition => self
                        .analyze_command_or_definition(pair)
                        .map(Analysis::managed),
                    unhandled_rule => {
                        todo!("Unhandled rule: {:#?}", unhandled_rule)
                    }
                })
                .collect::<AnalyzeResult<Vec<_>>>()?
                .into_iter(),
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_definition(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        let mut ast_iter = ast.into_inner();
        let definition_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| AnalyzeError::Syntax("lexer can't find a definition".into()))?;
        match definition_kind {
            Rule::single_value_definition => {
                #[derive(Trace, Finalize)]
                struct Analyzed {
                    val_proc: ManagedAnalysis,
                    symbol: String,
                    quotation_level: usize,
                }

                impl EvalInEnv for Analyzed {
                    fn call(&self, env: ManagedR7Env) -> R7Result {
                        let value = self.val_proc.call(env.clone())?[0].clone();
                        env.borrow_mut()
                            .define(&self.symbol, value)
                            .map(|val| vec![val])
                    }
                }

                let symbol = ast_iter.next().unwrap().as_str().to_string();
                let val_proc =
                    Analysis::managed(self.analyze_expression(ast_iter.next().ok_or_else(
                        || AnalyzeError::Syntax("expected expression".to_string()),
                    )?)?);
                let quotation_level = self.quotation_level;

                Ok(Analysis::managed(Analyzed {
                    val_proc,
                    symbol,
                    quotation_level,
                }))
            }
            Rule::lambda_definition => {
                #[derive(Trace, Finalize)]
                struct Analyzed {
                    docstring: Option<String>,
                    locals: Vec<String>,
                    name: R7Value,
                    body: ManagedAnalysis,
                    last_arg_is_list: bool,
                }

                impl EvalInEnv for Analyzed {
                    fn call(&self, env: ManagedR7Env) -> R7Result {
                        let proc = R7Value::procedure(Closure::analysed(
                            self.docstring.clone(),
                            self.locals.clone(),
                            self.body.clone(),
                            env.clone(),
                            self.last_arg_is_list,
                        ));
                        env.borrow_mut()
                            .define(&self.name.symbol_name()?, proc.into())
                            .map(|val| vec![val])
                    }
                }

                let docstring: Option<String> = None;
                let mut locals: Vec<String> = Vec::new();
                let mut name = R7Value::null();
                let mut body = ManagedAnalysis::default();
                let mut last_arg_is_list = false;
                for (i, elem) in ast_iter.enumerate() {
                    // The first element is the name of the lambda
                    if i == 0 {
                        debug_assert_eq!(elem.as_rule(), Rule::identifier);
                        debug!("Defining {} lambda", elem.as_str());
                        name = R7Value::symbol(elem.as_str());
                    } else if i == 1 {
                        debug_assert_eq!(elem.as_rule(), Rule::def_formals);
                        elem.into_inner().for_each(|formal| {
                            if formal.as_rule() == Rule::rest_identifier {
                                last_arg_is_list = true;
                                locals.push(formal.as_str().into());
                                return;
                            }
                            debug_assert_eq!(formal.as_rule(), Rule::identifier);
                            debug!("Adding {} to formal argument list", formal.as_str());
                            locals.push(formal.as_str().into());
                        })
                    } else {
                        debug_assert_eq!(elem.as_rule(), Rule::body);
                        body = sequence(
                            elem.into_inner()
                                .map(|part| self.analyze(part).map(Analysis::managed))
                                .collect::<AnalyzeResult<Vec<_>>>()?
                                .into_iter(),
                        )?
                    }
                }

                Ok(Analysis::managed(Analyzed {
                    docstring,
                    locals,
                    name,
                    body,
                    last_arg_is_list,
                }))
            }
            Rule::syntax_definition => {
                todo!("syntax_definition")
            }
            Rule::multiple_values_definition => {
                todo!("multiple_values_definition")
            }
            Rule::record_definition => {
                todo!("record_definition")
            }
            Rule::multiple_definitions => sequence(
                ast_iter
                    .map(|pair| self.analyze_definition(pair).map(Analysis::managed))
                    .collect::<AnalyzeResult<Vec<_>>>()?
                    .into_iter(),
            ),
            _ => Err(AnalyzeError::Syntax("unknown definition pattern".into())),
        }
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_expression(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the expression".into(),
            )),
            |_acc, pair| -> AnalyzeResult<ManagedAnalysis> {
                match pair.as_rule() {
                    Rule::identifier => {
                        let variable_name = pair.as_str().to_string();
                        if self.quotation_level == 0 {
                            #[derive(Trace, Finalize)]
                            struct Analyzed {
                                variable_name: String,
                            }

                            impl EvalInEnv for Analyzed {
                                fn call(&self, env: ManagedR7Env) -> R7Result {
                                    env.borrow().get(&self.variable_name).map(|val| vec![val])
                                }
                            }
                            Ok(Analysis::managed(Analyzed { variable_name }))
                        } else {
                            Ok(Analysis::managed(ManagedR7Value::from(R7Value::symbol(
                                &variable_name,
                            ))))
                        }
                    }
                    Rule::expression => {
                        // Recursive call because eval_lambda calls eval_expression on the body, which usually is a sequence, i.e. a {expression+}
                        self.analyze_expression(pair)
                    }
                    Rule::literal => self.analyze_literal(pair),
                    // assignment and procedure_call cases almost share the same code,
                    // as set! is defined as a native proc in the default environment
                    Rule::assignment => {
                        #[derive(Trace, Finalize)]
                        struct Analyzed {
                            symbol: ManagedR7Value,
                            val_proc: ManagedAnalysis,
                            quot: usize,
                        }

                        impl EvalInEnv for Analyzed {
                            fn call(&self, env: ManagedR7Env) -> R7Result {
                                let mut elements = R7Pair::default_with_quotation_level(self.quot);
                                elements.list_append(self.symbol.clone());
                                elements.list_append(self.val_proc.call(env.clone())?[0].clone());
                                crate::stdlib::base::set(env, elements)
                            }
                        }

                        let mut ast_iter = pair.into_inner();
                        let symbol = ManagedR7Value::from(R7Value::symbol(
                            ast_iter
                                .next()
                                .ok_or_else(|| AnalyzeError::Syntax("expected a symbol".into()))?
                                .as_str(),
                        ));
                        let val_proc = self.analyze_expression(
                            ast_iter
                                .next()
                                .ok_or_else(|| AnalyzeError::Syntax("expected a value".into()))?,
                        )?;
                        let quot = self.quotation_level;

                        Ok(Analysis::managed(Analyzed {
                            symbol,
                            val_proc,
                            quot,
                        }))
                    }
                    Rule::procedure_call => {
                        let mut elements: Vec<ManagedAnalysis> = Vec::new();
                        for elem in pair.into_inner() {
                            elements.push(self.analyze_expression(elem)?);
                        }
                        if self.quotation_level == 0 {
                            let (operator, operands) = elements
                                .split_first()
                                .expect("The parser/lexer found at least one operator.");
                            analyze_application(operator.clone(), operands.iter().cloned(), 0)
                        } else {
                            #[derive(Trace, Finalize)]
                            struct Analyzed {
                                elements: Vec<ManagedAnalysis>,
                            }

                            impl EvalInEnv for Analyzed {
                                fn call(&self, env: ManagedR7Env) -> R7Result {
                                    self.elements
                                        .iter()
                                        .try_fold(R7Pair::default(), |mut acc, operand_proc| {
                                            acc.list_append(
                                                operand_proc.call(env.clone())?[0].clone(),
                                            );
                                            Ok(acc)
                                        })
                                        .map(|pair| vec![ManagedR7Value::from(R7Value::from(pair))])
                                }
                            }

                            Ok(Analysis::managed(Analyzed { elements }))
                        }
                    }
                    Rule::operator => self.analyze_expression(pair),
                    Rule::operand => self.analyze_expression(pair),
                    Rule::lambda_expression => self.analyze_lambda(pair),
                    Rule::conditional => self.analyze_conditional(pair),
                    Rule::derived_expression => self.analyze_derived_expr(pair),
                    unhandled_rule => {
                        todo!("Unhandled rule: {:#?}", unhandled_rule)
                    }
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_literal(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        use crate::eval::literal::*;
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the literal".into(),
            )),
            |_acc, pair| match pair.as_rule() {
                Rule::boolean => {
                    let res = eval_boolean(pair);
                    Ok(Analysis::managed(res))
                }
                Rule::character => {
                    let res = eval_character(pair);
                    Ok(Analysis::managed(res))
                }
                Rule::bytevector => {
                    let res = eval_bytevector(pair);
                    Ok(Analysis::managed(res))
                }
                Rule::number => {
                    let res = eval_number(pair);
                    Ok(Analysis::managed(res))
                }
                Rule::quotation => self.analyze_quotation(pair),
                unhandled_rule => {
                    todo!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_quotation(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax("No evaluable code in the r7rs".into())),
            |_acc, pair| match pair.as_rule() {
                Rule::datum => {
                    self.quotation_level += 1;
                    let res = self.analyze_datum(pair);
                    self.quotation_level -= 1;
                    res
                }
                // As per parser/src/r7rs.pest grammar definition,
                // if we call this function only in case we hit a quotation
                // node, then all other cases are unreachable
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_datum(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        use crate::eval::literal::*;
        ast.into_inner().fold(
            Err(AnalyzeError::Syntax(
                "No evaluable code in the datum".into(),
            )),
            |_acc, pair| match pair.as_rule() {
                Rule::boolean => Ok(Analysis::managed(eval_boolean(pair))),
                Rule::character => Ok(Analysis::managed(eval_character(pair))),
                Rule::number => Ok(Analysis::managed(eval_number(pair))),
                Rule::symbol => Ok(Analysis::managed(ManagedR7Value::from(R7Value::symbol(
                    pair.as_str(),
                )))),
                Rule::list => {
                    #[derive(Trace, Finalize)]
                    struct Analyzed {
                        elems: Vec<ManagedAnalysis>,
                        quot: usize,
                    }

                    impl EvalInEnv for Analyzed {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            let mut res = R7Pair::default_with_quotation_level(self.quot);
                            for elem in self.elems.iter() {
                                res.list_append(elem.call(env.clone())?[0].clone());
                            }
                            // NOTE: The eval is necessary to eat the quote that
                            // was seen during analysis
                            res.eval(env)
                        }
                    }

                    let elems = pair
                        .into_inner()
                        .map(|elem| self.analyze_datum(elem))
                        .collect::<AnalyzeResult<Vec<_>>>()?;
                    let quot = self.quotation_level;

                    Ok(Analysis::managed(Analyzed { elems, quot }))
                }
                unhandled_rule => {
                    todo!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_lambda(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        #[derive(Trace, Finalize)]
        struct Analyzed {
            locals: Vec<String>,
            docstring: Option<String>,
            body: ManagedAnalysis,
            last_arg_is_list: bool,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                Ok(vec![R7Value::procedure(Closure::analysed(
                    self.docstring.clone(),
                    self.locals.clone(),
                    self.body.clone(),
                    env,
                    self.last_arg_is_list,
                ))
                .into()])
            }
        }

        let mut locals: Vec<String> = Vec::new();
        let docstring: Option<String> = None;
        let mut body = ManagedAnalysis::default();
        let mut last_arg_is_list = false;
        for pair in ast.into_inner() {
            match pair.as_rule() {
                Rule::formals => {
                    // If the formals are just "identifier", then it means the only locals should
                    // be bound as a list
                    if !pair.as_str().starts_with('(') {
                        last_arg_is_list = true;
                    }
                    pair.into_inner().for_each(|formal| {
                        if formal.as_rule() == Rule::rest_identifier {
                            last_arg_is_list = true;
                            locals.push(formal.as_str().into());
                            return;
                        }
                        debug_assert_eq!(formal.as_rule(), Rule::identifier);
                        locals.push(formal.as_str().into());
                    })
                }
                Rule::body => {
                    // FIXME: Handle definitions at the beginning of the body

                    // False positive because of the extra Clone trait bound on
                    // sequence argument
                    #[allow(clippy::needless_collect)]
                    let body_parts: Vec<_> = pair
                        .into_inner()
                        .map(|part| self.analyze(part))
                        .collect::<AnalyzeResult<_>>()?;
                    body = sequence(body_parts.into_iter())?;
                }
                _ => {
                    return Err(AnalyzeError::Syntax("unexpected token".into()));
                }
            }
        }

        Ok(Analysis::managed(Analyzed {
            locals,
            docstring,
            body,
            last_arg_is_list,
        }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_sequence(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        let ast_iter = ast.into_inner();
        // False positive because of the extra Clone trait bound on
        // sequence argument
        #[allow(clippy::needless_collect)]
        let body_parts: Vec<_> = ast_iter
            .map(|part| self.analyze(part))
            .collect::<AnalyzeResult<_>>()?;
        sequence(body_parts.into_iter())
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_conditional(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        #[derive(Trace, Finalize)]
        struct Analyzed {
            test: ManagedAnalysis,
            consequent: ManagedAnalysis,
            alternate: ManagedAnalysis,
        }
        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let predicate = self.test.call(env.clone())?[0].clone();
                if predicate.borrow().as_bool() {
                    self.consequent.call(env)
                } else {
                    self.alternate.call(env)
                }
            }
        }

        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::conditional_if);
        let mut test = ManagedAnalysis::default();
        let mut consequent = ManagedAnalysis::default();
        // This decides the default value when there is no alternate
        let mut alternate = Analysis::managed(ManagedR7Value::from(R7Value::f()));
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    test = self.analyze(elem)?;
                }
                Rule::consequent => {
                    consequent = self.analyze(elem)?;
                }
                Rule::alternate => {
                    alternate = self.analyze(elem)?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Analysis::managed(Analyzed {
            test,
            consequent,
            alternate,
        }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        // TODO: Get rid of that clone
        let mut ast_iter = ast.clone().into_inner();
        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| AnalyzeError::Syntax("lexer can't find a derived expression".into()))?;
        match expr_kind {
            Rule::derived_expr_case_no_else | Rule::derived_expr_case => {
                self.analyze_derived_expr_case(ast)
            }
            Rule::derived_expr_cond | Rule::derived_expr_cond_no_else => {
                self.analyze_derived_expr_cond(ast)
            }
            Rule::derived_expr_and => self.analyze_derived_expr_and(ast),
            Rule::derived_expr_or => self.analyze_derived_expr_or(ast),
            Rule::derived_expr_when => self.analyze_derived_expr_when(ast),
            Rule::derived_expr_unless => self.analyze_derived_expr_unless(ast),
            Rule::binding_let => self.analyze_derived_expr_binding_let(ast, false),
            Rule::binding_let_star => self.analyze_derived_expr_binding_let(ast, true),
            // REVIEW: "star" has NO effect on the letrec analyses. Maybe there's something
            // I didn't get in the semantics that's really important?
            Rule::binding_letrec => self.analyze_derived_expr_binding_letrec(ast, false),
            Rule::binding_letrec_star => self.analyze_derived_expr_binding_letrec(ast, true),
            unhandled_rule => {
                todo!("Unhandled rule: {:#?}", unhandled_rule)
            }
        }
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_case(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedAnalysis> {
        let mut ast_iter = ast.into_inner().peekable();
        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        debug_assert!(matches!(
            expr_kind,
            Rule::derived_expr_case_no_else | Rule::derived_expr_case
        ));

        #[derive(Trace, Finalize)]
        struct Analyzed {
            case_expr: ManagedAnalysis,
            case_clauses: Vec<(
                /* test */ ManagedAnalysis,
                /* consequent */ ManagedAnalysis,
            )>,
            else_clause: ManagedAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                for (test, consequent) in self.case_clauses.iter() {
                    if test.call(env.clone())?[0].borrow().as_bool() {
                        return consequent.call(env);
                    }
                }
                self.else_clause.call(env)
            }
        }

        let mut case_expr = ManagedAnalysis::default();
        let mut case_clauses = Vec::new();
        // This default value controls the output when there is no else clause.
        let mut else_clause = Analysis::managed(ManagedR7Value::from(R7Value::f()));

        while let Some(elem) = ast_iter.next() {
            match elem.as_rule() {
                Rule::expression => case_expr = self.analyze_expression(elem)?,
                Rule::case_clause => {
                    case_clauses.push(self.analyze_case_clause(case_expr.clone(), elem)?);
                }
                Rule::derived_expr_else => {
                    let else_val = ast_iter.next().ok_or_else(|| {
                        AnalyzeError::Syntax("Missing sequence after else clause".into())
                    })?;
                    match else_val.as_rule() {
                        Rule::sequence => {
                            else_clause = self.analyze(else_val)?;
                        }
                        Rule::recipient => {
                            let proc = self.analyze(else_val)?;
                            else_clause = analyze_application(
                                proc,
                                std::iter::once(case_expr.clone()),
                                self.quotation_level,
                            )?;
                        }
                        unhandled_rule => {
                            return Err(AnalyzeError::Syntax(format!(
                                "Unhandled rule: expecting sequence or recipient {:#?}",
                                unhandled_rule
                            )))
                        }
                    }
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Analysis::managed(Analyzed {
            case_expr,
            case_clauses,
            else_clause,
        }))
    }

    #[tracing::instrument(skip(self, ast, target))]
    fn analyze_case_clause<'ast>(
        &mut self,
        target: ManagedAnalysis,
        ast: parser::Pair<'ast, Rule>,
    ) -> AnalyzeResult<(ManagedAnalysis, ManagedAnalysis)> {
        let mut clause_value_set: Vec<ManagedAnalysis> = Vec::new();

        let ast_iter = ast.into_inner();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::datum => {
                    let clause_value = self.analyze_datum(elem)?;
                    clause_value_set.push(clause_value);
                }
                Rule::recipient => {
                    let proc = self.analyze(elem)?;
                    let test = Analysis::managed(ManagedR7Value::from(R7Value::t()));

                    return Ok((
                        test,
                        analyze_application(proc, std::iter::once(target), self.quotation_level)?,
                    ));
                }
                Rule::sequence => {
                    let consequent = self.analyze_sequence(elem)?;

                    #[derive(Trace, Finalize)]
                    struct Analyzed {
                        clause_value_set: Vec<ManagedAnalysis>,
                        target: ManagedAnalysis,
                    }

                    impl EvalInEnv for Analyzed {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            let targ_val = self.target.call(env.clone())?;
                            Ok(vec![ManagedR7Value::from(R7Value::from(
                                self.clause_value_set.iter().any(|test| {
                                    test.call(env.clone()).map_or(false, |val| val == targ_val)
                                }),
                            ))])
                        }
                    }

                    return Ok((
                        Analysis::managed(Analyzed {
                            clause_value_set,
                            target,
                        }),
                        consequent,
                    ));
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }
        unreachable!("No sequence on that call. Should be an error instead of a panic here.")
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_cond(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedAnalysis> {
        let mut ast_iter = ast.into_inner().peekable();
        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        debug_assert!(matches!(
            expr_kind,
            Rule::derived_expr_cond_no_else | Rule::derived_expr_cond
        ));

        #[derive(Trace, Finalize)]
        struct Analyzed {
            cond_clauses: Vec<(
                /* test */ ManagedAnalysis,
                /* consequent */ ManagedAnalysis,
            )>,
            else_clause: ManagedAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                for (test, consequent) in self.cond_clauses.iter() {
                    if test.call(env.clone())?[0].borrow().as_bool() {
                        return consequent.call(env);
                    }
                }
                self.else_clause.call(env)
            }
        }

        let mut cond_clauses = Vec::new();
        // This default value controls the output when there is no else clause.
        let mut else_clause = Analysis::managed(ManagedR7Value::from(R7Value::f()));

        while let Some(elem) = ast_iter.next() {
            match elem.as_rule() {
                Rule::cond_clause => {
                    cond_clauses.push(self.analyze_cond_clause(elem)?);
                }
                Rule::derived_expr_else => {
                    let else_val = ast_iter.next().ok_or_else(|| {
                        AnalyzeError::Syntax("Missing sequence after else clause".into())
                    })?;
                    match else_val.as_rule() {
                        Rule::sequence => {
                            else_clause = self.analyze(else_val)?;
                        }
                        unhandled_rule => {
                            return Err(AnalyzeError::Syntax(format!(
                                "Unhandled rule: expecting sequence {:#?}",
                                unhandled_rule
                            )))
                        }
                    }
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Analysis::managed(Analyzed {
            cond_clauses,
            else_clause,
        }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_cond_clause<'ast>(
        &mut self,
        ast: parser::Pair<'ast, Rule>,
    ) -> AnalyzeResult<(
        /* test */ ManagedAnalysis,
        /* consequent */ ManagedAnalysis,
    )> {
        let mut ast_iter = ast.into_inner();
        let test_ast = ast_iter
            .next()
            .ok_or_else(|| AnalyzeError::Syntax("Expecting a test for the cond".into()))?;
        let test = self.analyze(test_ast)?;

        let consequent = ast_iter.next().map_or_else(
            || Ok(test.clone()),
            |cons_ast| match cons_ast.as_rule() {
                Rule::sequence => self.analyze(cons_ast),
                Rule::recipient => {
                    let proc = self.analyze(cons_ast)?;
                    let quotation_level = self.quotation_level;
                    let target = test.clone();
                    analyze_application(proc, std::iter::once(target), quotation_level)
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            },
        )?;

        Ok((test, consequent))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_and(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedAnalysis> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_and);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            arguments: Vec<ManagedAnalysis>,
        }
        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let mut args_iter = self.arguments.iter().peekable();
                while let Some(arg) = args_iter.next() {
                    let val = arg.call(env.clone())?;
                    if !val[0].borrow().as_bool() {
                        return Ok(vec![R7Value::f().into()]);
                    }
                    if args_iter.peek().is_none() {
                        return Ok(val);
                    }
                }
                // This is reached only if there are _no_ arguments
                // so "(and)" => #true
                Ok(vec![R7Value::t().into()])
            }
        }

        let mut arguments = Vec::new();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    arguments.push(self.analyze(elem)?);
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }
        Ok(Analysis::managed(Analyzed { arguments }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_or(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedAnalysis> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_or);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            arguments: Vec<ManagedAnalysis>,
        }
        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let mut args_iter = self.arguments.iter().peekable();
                while let Some(arg) = args_iter.next() {
                    let val = arg.call(env.clone())?;
                    if val[0].borrow().as_bool() {
                        return Ok(vec![val[0].clone()]);
                    }
                    if args_iter.peek().is_none() {
                        return Ok(val);
                    }
                }
                // This is reached only if there are _no_ arguments
                // so "(or)" => #false
                Ok(vec![R7Value::f().into()])
            }
        }

        let mut arguments = Vec::new();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    arguments.push(self.analyze(elem)?);
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Analysis::managed(Analyzed { arguments }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_when(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedAnalysis> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_when);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            test: ManagedAnalysis,
            seq: ManagedAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                if self.test.call(env.clone())?[0].borrow().as_bool() {
                    self.seq.call(env)
                } else {
                    Ok(vec![R7Value::f().into()])
                }
            }
        }

        let mut seq = ManagedAnalysis::default();
        let mut test = ManagedAnalysis::default();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    test = self.analyze(elem)?;
                }
                Rule::sequence => {
                    seq = self.analyze(elem)?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }
        Ok(Analysis::managed(Analyzed { test, seq }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_unless(
        &mut self,
        ast: parser::Pair<Rule>,
    ) -> AnalyzeResult<ManagedAnalysis> {
        let mut ast_iter = ast.into_inner();
        let cond_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a definition".into())
            })?;
        debug_assert_eq!(cond_kind, Rule::derived_expr_when);

        #[derive(Trace, Finalize)]
        struct Analyzed {
            test: ManagedAnalysis,
            seq: ManagedAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                if !self.test.call(env.clone())?[0].borrow().as_bool() {
                    self.seq.call(env)
                } else {
                    Ok(vec![R7Value::f().into()])
                }
            }
        }

        let mut seq = ManagedAnalysis::default();
        let mut test = ManagedAnalysis::default();
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::test => {
                    test = self.analyze(elem)?;
                }
                Rule::sequence => {
                    seq = self.analyze(elem)?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Analysis::managed(Analyzed { test, seq }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_binding_let(
        &mut self,
        ast: parser::Pair<Rule>,
        star: bool,
    ) -> AnalyzeResult<ManagedAnalysis> {
        let mut ast_iter = ast.into_inner().peekable();

        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        match star {
            true => debug_assert!(matches!(expr_kind, Rule::binding_let_star)),
            false => debug_assert!(matches!(expr_kind, Rule::binding_let)),
        }

        #[derive(Trace, Finalize)]
        struct Analyzed {
            binds: Vec<ManagedAnalysis>,
            body: ManagedAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let binds_env: ManagedR7Env = crate::env::R7Env::new((&env).into()).into();

                for binding in self.binds.iter() {
                    binding.call(binds_env.clone())?;
                }

                self.body.call(binds_env)
            }
        }

        let mut binds = Vec::new();
        let mut body = Analysis::managed(ManagedR7Value::from(R7Value::null()));

        for elem in ast_iter {
            match elem.as_rule() {
                Rule::binding_spec => {
                    #[derive(Trace, Finalize)]
                    struct AnalyzedBind {
                        symbol: String,
                        val_proc: ManagedAnalysis,
                        // the difference between let and let*
                        eval_in_parent: bool,
                    }
                    impl EvalInEnv for AnalyzedBind {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            let val = self.val_proc.call(if self.eval_in_parent {
                                env.borrow().parent().ok_or_else(|| {
                                    R7Error::Unknown(
                                        "No parent environment to evaluate binding in".to_string(),
                                    )
                                })?
                            } else {
                                env.clone()
                            })?;
                            debug_assert_eq!(val.len(), 1);
                            (&mut *env.borrow_mut())
                                .define(&self.symbol, val[0].clone())
                                .map(|val| vec![val])
                        }
                    }

                    let mut binding = elem.into_inner();
                    let ident = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(ident.as_rule(), Rule::identifier);
                    let symbol = ident.as_str().to_string();
                    let value = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(value.as_rule(), Rule::expression);
                    let val_proc = self.analyze_expression(value)?;

                    binds.push(Analysis::managed(AnalyzedBind {
                        symbol,
                        val_proc,
                        eval_in_parent: !star,
                    }));
                }
                Rule::body => {
                    body = self.analyze_sequence(elem.into_inner().next().unwrap())?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Analysis::managed(Analyzed { body, binds }))
    }

    #[tracing::instrument(skip(self, ast))]
    fn analyze_derived_expr_binding_letrec(
        &mut self,
        ast: parser::Pair<Rule>,
        star: bool,
    ) -> AnalyzeResult<ManagedAnalysis> {
        let mut ast_iter = ast.clone().into_inner();

        let expr_kind = ast_iter
            .by_ref()
            .next()
            .map(|pair| pair.as_rule())
            .ok_or_else(|| {
                AnalyzeError::Syntax("Syntax error: lexer can't find a derived expression".into())
            })?;
        match star {
            true => debug_assert!(matches!(expr_kind, Rule::binding_letrec_star)),
            false => debug_assert!(matches!(expr_kind, Rule::binding_letrec)),
        }

        #[derive(Trace, Finalize)]
        struct Analyzed {
            init_binds: Vec<ManagedAnalysis>,
            binds: Vec<ManagedAnalysis>,
            body: ManagedAnalysis,
        }

        impl EvalInEnv for Analyzed {
            fn call(&self, env: ManagedR7Env) -> R7Result {
                let binds_env: ManagedR7Env = crate::env::R7Env::new((&env).into()).into();

                for binding in self.init_binds.iter() {
                    binding.call(binds_env.clone())?;
                }

                for binding in self.binds.iter() {
                    binding.call(binds_env.clone())?;
                }

                self.body.call(binds_env)
            }
        }

        let mut binds = Vec::new();
        let mut init_binds = Vec::new();
        let mut body = Analysis::managed(ManagedR7Value::from(R7Value::null()));

        // First loop to accumulate initial bindings
        for elem in ast_iter {
            match elem.as_rule() {
                Rule::binding_spec => {
                    #[derive(Trace, Finalize)]
                    struct AnalyzedInitBind {
                        symbol: String,
                        eval_in_parent: bool,
                    }
                    impl EvalInEnv for AnalyzedInitBind {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            (&mut *env.borrow_mut())
                                .define(
                                    &self.symbol,
                                    R7Value::DynamicBinding(self.symbol.clone()).into(),
                                )
                                .map(|val| vec![val])
                        }
                    }

                    let mut binding = elem.into_inner();
                    let ident = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(ident.as_rule(), Rule::identifier);
                    let symbol = ident.as_str().to_string();
                    let value = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(value.as_rule(), Rule::expression);

                    init_binds.push(Analysis::managed(AnalyzedInitBind {
                        symbol: symbol.clone(),
                        eval_in_parent: !star,
                    }));
                }
                Rule::body => {
                    break;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        // Skipping the letrec keyword
        for elem in ast.into_inner().into_iter().skip(1) {
            match elem.as_rule() {
                Rule::binding_spec => {
                    #[derive(Trace, Finalize)]
                    struct AnalyzedBind {
                        symbol: String,
                        val_proc: ManagedAnalysis,
                        init_binds: Vec<ManagedAnalysis>,
                        // the difference between let and let*
                        eval_in_parent: bool,
                    }
                    impl EvalInEnv for AnalyzedBind {
                        fn call(&self, env: ManagedR7Env) -> R7Result {
                            let val = self.val_proc.call(env.clone())?;
                            debug_assert_eq!(val.len(), 1);
                            (&mut *env.borrow_mut())
                                .set(&self.symbol, val[0].clone())
                                .map(|val| vec![val])
                        }
                    }

                    let mut binding = elem.into_inner();
                    let ident = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(ident.as_rule(), Rule::identifier);
                    let symbol = ident.as_str().to_string();
                    let value = binding.next().expect("Trusting the parser");
                    debug_assert_eq!(value.as_rule(), Rule::expression);
                    let val_proc = self.analyze_expression(value)?;

                    binds.push(Analysis::managed(AnalyzedBind {
                        symbol,
                        init_binds: init_binds.clone(),
                        val_proc,
                        eval_in_parent: !star,
                    }));
                }
                Rule::body => {
                    body = self.analyze_sequence(elem.into_inner().next().unwrap())?;
                }
                unhandled_rule => {
                    unreachable!("Unhandled rule: {:#?}", unhandled_rule)
                }
            }
        }

        Ok(Analysis::managed(Analyzed {
            body,
            binds,
            init_binds,
        }))
    }

    /// Analyze a parsed tree to return a procedure that can
    /// be use to evaluate the result multiple times according
    /// to the environment.
    #[tracing::instrument(skip(self, ast))]
    pub fn analyze(&mut self, ast: parser::Pair<Rule>) -> AnalyzeResult<ManagedAnalysis> {
        match ast.as_rule() {
            Rule::EOI => Ok(Analysis::managed(ManagedR7Value::from(R7Value::null()))),
            Rule::r7rs => self.analyze_r7rs(ast),
            Rule::number => Ok(Analysis::managed(eval_number(ast))),
            Rule::datum => self.analyze_datum(ast),
            Rule::literal => self.analyze_literal(ast),
            Rule::suffix
            | Rule::infnan
            | Rule::exponent_marker
            | Rule::exactness
            | Rule::radix_2
            | Rule::radix_8
            | Rule::radix_10
            | Rule::radix_16
            | Rule::sign
            | Rule::num_2
            | Rule::complex_2
            | Rule::real_2
            | Rule::ureal_2
            | Rule::uinteger_2
            | Rule::prefix_2
            | Rule::num_8
            | Rule::complex_8
            | Rule::real_8
            | Rule::ureal_8
            | Rule::uinteger_8
            | Rule::prefix_8
            | Rule::num_10
            | Rule::complex_10
            | Rule::real_10
            | Rule::ureal_10
            | Rule::uinteger_10
            | Rule::prefix_10
            | Rule::decimal_10
            | Rule::num_16
            | Rule::complex_16
            | Rule::real_16
            | Rule::ureal_16
            | Rule::uinteger_16
            | Rule::prefix_16 => unreachable!(
                "Inner number rule during analysis phase: {:?}",
                ast.as_rule()
            ),
            Rule::sequence => self.analyze_sequence(ast),
            Rule::expression => self.analyze_expression(ast),
            // Basic "{ expression }" aliases
            Rule::test
            | Rule::cond_test
            | Rule::consequent
            | Rule::alternate
            | Rule::operator
            | Rule::operand
            | Rule::recipient
            | Rule::init
            | Rule::step
            | Rule::qq_template_0 => self.analyze(ast.into_inner().next().unwrap()),
            unhandled_rule => {
                todo!("Unhandled rule: {:#?}", unhandled_rule)
            }
        }
    }
}

/// Analyze a sequence of analysis.
///
/// Equivalent to calling all the analyses in order inconditionnally
fn sequence<T>(analyses: T) -> AnalyzeResult<ManagedAnalysis>
where
    T: Iterator<Item = ManagedAnalysis>,
{
    #[derive(Trace, Finalize)]
    struct Analyzed {
        parts: Vec<ManagedAnalysis>,
    }

    impl EvalInEnv for Analyzed {
        fn call(&self, env: ManagedR7Env) -> R7Result {
            use crate::env::R7Env;
            let mut folded = Vec::new();
            let mut new_env = env;
            for analysed in self.parts.iter() {
                folded = analysed.call(new_env.clone())?;
                new_env = R7Env::new(Some(&new_env)).into();
            }
            Ok(folded)
        }
    }

    // Force eager collection to root objects and assert static ownership
    Ok(Analysis::managed(Analyzed {
        parts: analyses.collect(),
    }))
}

/// Analyze an application ("apply",