knave 0.13.1

A Lisp programming language for humans and agents that infers types and ownership and compiles to readable Rust
Documentation
use std::rc::Rc;

use rustc_hash::FxHashMap;

use super::ty::{GenericId, GenericParam, Type};
use crate::core::BindingId;
use crate::source::Span;

#[derive(Clone)]
pub struct StructDefinition {
    pub lifetimes: Vec<BindingId>,
    pub params: Vec<GenericParam>,
    pub fields: Vec<(Rc<str>, Type)>,
    pub field_spans: Vec<Span>,
    pub function_spans: Vec<Span>,
    pub derives: Vec<&'static str>,
    pub derived_traits: Vec<BindingId>,
    pub blocked: Vec<(BindingId, Rc<str>, Type)>,
    pub written_derive: Option<Span>,
}

impl StructDefinition {
    pub fn field(&self, name: &str) -> Option<&Type> {
        self.fields
            .iter()
            .find(|(field, _)| field.as_ref() == name)
            .map(|(_, field_type)| field_type)
    }

    pub fn instantiated_field_depth(&self, name: &str, arguments: &[Type]) -> Option<usize> {
        let declared = self.field(name)?;
        let argument_depth = match declared.innermost_referent() {
            Type::Generic(generic) => self
                .params
                .iter()
                .position(|param| param.id == *generic)
                .and_then(|position| arguments.get(position))
                .map_or(0, Type::reference_depth),
            _ => 0,
        };
        Some(declared.reference_depth() + argument_depth)
    }

    pub fn instantiated_field(&self, name: &str, arguments: &[Type]) -> Option<Type> {
        let replacements = self.replacements(arguments);
        self.field(name).map(|field_type| {
            field_type
                .without_written_lifetimes()
                .substitute(&replacements)
        })
    }

    pub fn instantiated_fields(&self, arguments: &[Type]) -> Vec<(Rc<str>, Type)> {
        let replacements = self.replacements(arguments);
        self.fields
            .iter()
            .map(|(name, field_type)| {
                (
                    name.clone(),
                    field_type
                        .without_written_lifetimes()
                        .substitute(&replacements),
                )
            })
            .collect()
    }

    fn replacements(&self, arguments: &[Type]) -> FxHashMap<GenericId, Type> {
        self.params
            .iter()
            .map(|param| param.id)
            .zip(arguments.iter().cloned())
            .collect()
    }
}

#[derive(Clone, Default)]
pub struct StructTable {
    structs: FxHashMap<BindingId, StructDefinition>,
}

impl StructTable {
    pub fn add(&mut self, binding: BindingId, definition: StructDefinition) {
        self.structs.insert(binding, definition);
    }

    pub fn get(&self, binding: BindingId) -> Option<&StructDefinition> {
        self.structs.get(&binding)
    }

    pub fn get_mut(&mut self, binding: BindingId) -> Option<&mut StructDefinition> {
        self.structs.get_mut(&binding)
    }

    pub fn iter(&self) -> impl Iterator<Item = (BindingId, &StructDefinition)> {
        self.structs
            .iter()
            .map(|(binding, definition)| (*binding, definition))
    }

    pub fn with_field(&self, name: &str) -> Vec<BindingId> {
        self.structs
            .iter()
            .filter(|(_, definition)| definition.field(name).is_some())
            .map(|(binding, _)| *binding)
            .collect()
    }
}