airlang 0.26.0

Air is a minimalist and universal programming language.
Documentation
use std::collections::hash_map::Entry;

use derive_more::Deref;
use derive_more::DerefMut;

use crate::semantics::cfg::fact::Facts;
use crate::semantics::cfg::fact::ValId;
use crate::semantics::func::DynFunc;
use crate::semantics::val::FuncVal;
use crate::semantics::val::Val;
use crate::type_::Key;
use crate::type_::Map;
use crate::utils::hint::cold_path;

#[derive(Default, Clone, PartialEq, Eq, Hash, Deref, DerefMut)]
pub struct Cfg {
    aborted: bool,
    #[deref]
    #[deref_mut]
    map: Map<Key, Val>,
    facts: Facts,
}

impl Cfg {
    pub fn import(&self, key: Key) -> Option<&Val> {
        self.map.get(&key)
    }

    pub fn export(&mut self, key: Key, val: Val) -> Option<()> {
        if self.map.contains_key(&key) {
            return None;
        }
        self.map.insert(key, val);
        Some(())
    }

    pub fn extend(&mut self, key: Key, val: Val) {
        match self.map.entry(key.clone()) {
            Entry::Occupied(_) => panic!("expect a unique key, but {key} is already used"),
            Entry::Vacant(entry) => {
                entry.insert(val);
            },
        }
    }

    #[inline(always)]
    pub fn step(&mut self) -> bool {
        if self.aborted {
            cold_path();
            return false;
        }
        true
    }

    #[cold]
    pub fn abort(&mut self) {
        self.aborted = true;
    }

    pub fn recover(&mut self) {
        self.aborted = false;
    }

    #[inline(always)]
    pub fn is_aborted(&self) -> bool {
        if self.aborted {
            cold_path();
            true
        } else {
            false
        }
    }

    pub(crate) fn facts(&self) -> &Facts {
        &self.facts
    }

    pub fn fact_put(&mut self, ctx: &mut Val, func: FuncVal, input: Val) {
        let output = func.call(self, ctx, input.clone());
        let input = ValId::from(input);
        let output = ValId::from(output);
        self.facts.put(func, input, output);
    }

    pub fn fact_call(&self, func: FuncVal, input: Val) -> Option<Val> {
        let outputs = self.facts.call(func, ValId::from(input))?;
        if outputs.is_empty() {
            return None;
        }
        Some(Val::clone(&outputs[0]))
    }

    pub fn fact_solve(&self, func: FuncVal, output: Val) -> Option<Val> {
        let inputs = self.facts.solve(func, ValId::from(output))?;
        if inputs.is_empty() {
            return None;
        }
        Some(Val::clone(&inputs[0]))
    }

    pub fn fact_exist(&self, func: FuncVal, input: Val, output: Val) -> bool {
        let input = ValId::from(input);
        let output = ValId::from(output);
        self.facts.exist(func, input, output)
    }
}

impl From<Map<Key, Val>> for Cfg {
    fn from(map: Map<Key, Val>) -> Self {
        Self { map, ..Cfg::default() }
    }
}

impl From<Cfg> for Map<Key, Val> {
    fn from(cfg: Cfg) -> Self {
        cfg.map
    }
}

pub(crate) mod fact;