knave 0.14.7

A Lisp programming language for humans and agents that infers types and ownership and compiles to readable Rust
Documentation
use rustc_hash::{FxHashMap, FxHashSet};

use crate::core::BindingId;

#[derive(Clone, Default, PartialEq)]
pub(super) struct CalleeParameters {
    sharing: Vec<bool>,
    higher_ranked: Vec<bool>,
}

impl CalleeParameters {
    pub(super) fn new(sharing: Vec<bool>, higher_ranked: Vec<bool>) -> Self {
        Self {
            sharing,
            higher_ranked,
        }
    }

    pub(super) fn shares(&self, position: usize) -> bool {
        Self::marks(&self.sharing, position)
    }

    pub(super) fn is_higher_ranked(&self, position: usize) -> bool {
        Self::marks(&self.higher_ranked, position)
    }

    fn joined(&self, other: &Self) -> Self {
        Self::new(
            Self::either(&self.sharing, &other.sharing),
            Self::either(&self.higher_ranked, &other.higher_ranked),
        )
    }

    fn either(left: &[bool], right: &[bool]) -> Vec<bool> {
        (0..left.len().max(right.len()))
            .map(|position| Self::marks(left, position) || Self::marks(right, position))
            .collect()
    }

    fn marks(marked: &[bool], position: usize) -> bool {
        marked.get(position).is_some_and(|marks| *marks)
    }
}

#[derive(Default)]
pub(super) struct OpenCallees {
    orders: FxHashMap<BindingId, usize>,
    stack: Vec<BindingId>,
    provisional: FxHashMap<BindingId, CalleeParameters>,
    assumed: FxHashSet<BindingId>,
}

impl OpenCallees {
    pub(super) fn open(&mut self, callee: BindingId) -> usize {
        let order = self.orders.len();
        self.orders.insert(callee, order);
        self.stack.push(callee);
        order
    }

    pub(super) fn order(&self, callee: BindingId) -> Option<usize> {
        self.orders.get(&callee).copied()
    }

    pub(super) fn assume(&mut self, callee: BindingId) -> CalleeParameters {
        self.assumed.insert(callee);
        self.provisional.get(&callee).cloned().unwrap_or_default()
    }

    pub(super) fn propose(&mut self, callee: BindingId, parameters: CalleeParameters) {
        self.provisional.insert(callee, parameters);
    }

    pub(super) fn widen(&mut self, callee: BindingId, parameters: &CalleeParameters) -> bool {
        let current = self.provisional.get(&callee).cloned().unwrap_or_default();
        let widened = current.joined(parameters);
        let grew = widened != current;
        self.provisional.insert(callee, widened);
        grew
    }

    pub(super) fn group_from(&self, order: usize) -> Vec<BindingId> {
        self.stack
            .iter()
            .copied()
            .filter(|callee| self.orders[callee] >= order)
            .collect()
    }

    pub(super) fn any_assumed(&self, group: &[BindingId]) -> bool {
        group.iter().any(|callee| self.assumed.contains(callee))
    }

    pub(super) fn close(&mut self, group: &[BindingId]) -> Vec<(BindingId, CalleeParameters)> {
        self.stack.truncate(self.stack.len() - group.len());
        group
            .iter()
            .map(|callee| (*callee, self.closed(*callee)))
            .collect()
    }

    fn closed(&mut self, callee: BindingId) -> CalleeParameters {
        self.orders.remove(&callee);
        self.assumed.remove(&callee);
        self.provisional.remove(&callee).unwrap_or_default()
    }
}