knave-expand 0.13.2

The reading, scoping and expansion stages of knave
Documentation
use super::Forms;
use crate::diagnostic::Diagnostic;
use crate::interpret::arguments::Arguments;
use crate::interpret::{CompileTimeHost, Value};
use crate::language::Language;
use crate::reader::{Form, FormKind, Number, NumberValue, Symbol};
use crate::source::Span;

pub struct ProgramOperations<'a> {
    arguments: &'a Arguments,
    call_site: Span,
}

impl<'a> ProgramOperations<'a> {
    pub fn new(arguments: &'a Arguments, call_site: Span) -> Self {
        Self {
            arguments,
            call_site,
        }
    }

    pub fn form_location(&self, host: &mut dyn CompileTimeHost) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(1)?;
        let location = host.form_location(&self.arguments.form(0)?);
        Ok(Value::Form(Form::new(
            FormKind::String(location.into()),
            self.call_site,
        )))
    }

    pub fn project_file_name(&self) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(0)?;
        let name = FormKind::String(Language::project_file_name().into());
        Ok(Value::Form(Form::new(name, self.call_site)))
    }

    pub fn pinned_at(&self) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(2)?;
        let place = self.arguments.form(0)?.span();
        let pinned = Span::new(place.source().pinned(), place.range());
        Ok(Value::Form(self.arguments.form(1)?.located_at(pinned)))
    }

    pub fn in_tasks_directory(&self, host: &mut dyn CompileTimeHost) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(1)?;
        Ok(Value::Bool(
            host.in_tasks_directory(&self.arguments.form(0)?),
        ))
    }

    pub fn read_form(&self, host: &mut dyn CompileTimeHost) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(3)?;
        let context = self.arguments.symbol(0)?;
        let literal = self.arguments.form(1)?.span();
        let value = self.arguments.string(1)?;
        let read = host.read_literal_form(literal, value, self.arguments.index(2)?);
        Forms::list(
            read.map_or_else(Vec::new, |(mut form, end)| {
                form.set_scopes(context.scopes());
                vec![form, self.count_form(end)]
            }),
            self.call_site,
            self.arguments.span(),
        )
    }

    pub fn located(&self) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(2)?;
        let place = self.arguments.form(0)?.span();
        Ok(Value::Form(self.arguments.form(1)?.located_at(place)))
    }

    fn count_form(&self, count: usize) -> Form {
        let number = Number::new(count.to_string(), NumberValue::Integer(count as i128));
        Form::new(FormKind::Number(number), self.call_site)
    }
}

pub struct ModuleOperations<'a> {
    arguments: &'a Arguments,
    call_site: Span,
}

impl<'a> ModuleOperations<'a> {
    pub fn new(arguments: &'a Arguments, call_site: Span) -> Self {
        Self {
            arguments,
            call_site,
        }
    }

    pub fn project_modules(&self, host: &mut dyn CompileTimeHost) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(0)?;
        self.symbols(host.project_modules())
    }

    pub fn program_modules(&self, host: &mut dyn CompileTimeHost) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(0)?;
        self.symbols(host.program_modules())
    }

    pub fn module_exports(&self, host: &mut dyn CompileTimeHost) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(1)?;
        let path = self.arguments.form(0)?;
        let exports = host.module_exports(self.arguments.symbol(0)?, path.span())?;
        self.symbols(exports)
    }

    pub fn module_definitions(&self, host: &mut dyn CompileTimeHost) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(1)?;
        let path = self.arguments.form(0)?;
        let definitions = host.module_definitions(self.arguments.symbol(0)?, path.span())?;
        self.symbols(definitions)
    }

    pub fn current_module(&self, host: &mut dyn CompileTimeHost) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(0)?;
        let module = FormKind::Symbol(host.current_module());
        Ok(Value::Form(Form::new(module, self.call_site)))
    }

    pub fn named(
        &self,
        find: impl FnOnce(&Symbol, Span) -> Result<Symbol, Diagnostic>,
    ) -> Result<Value, Diagnostic> {
        self.arguments.expect_count(1)?;
        let path = self.arguments.form(0)?;
        let module = find(self.arguments.symbol(0)?, path.span())?;
        Ok(Value::Form(Form::new(
            FormKind::Symbol(module),
            self.call_site,
        )))
    }

    fn symbols(&self, symbols: Vec<Symbol>) -> Result<Value, Diagnostic> {
        let forms = symbols
            .into_iter()
            .map(|symbol| Form::new(FormKind::Symbol(symbol), self.call_site))
            .collect();
        Forms::list(forms, self.call_site, self.arguments.span())
    }
}