airlang 0.23.0

Air is a minimalist and universal programming language.
Documentation
use const_format::concatcp;
use num_traits::ToPrimitive;

use crate::bug;
use crate::semantics::cfg::Cfg;
use crate::semantics::core::PREFIX_ID;
use crate::semantics::ctx::DynCtx;
use crate::semantics::val::CallVal;
use crate::semantics::val::CellVal;
use crate::semantics::val::IntVal;
use crate::semantics::val::ListVal;
use crate::semantics::val::MapVal;
use crate::semantics::val::PairVal;
use crate::semantics::val::Val;
use crate::type_::Key;

pub(crate) const VALUE: &str = concatcp!(PREFIX_ID, "value");

impl DynCtx<Key, Val> for CellVal {
    fn ref_(&self, cfg: &mut Cfg, key: Key) -> Option<&Val> {
        if &*key == VALUE {
            return Some(&self.value);
        }
        bug!(cfg, "context cell: expected key to be {VALUE}, but got {key}");
        None
    }

    fn ref_mut(&mut self, cfg: &mut Cfg, key: Key) -> Option<&mut Val> {
        if &*key == VALUE {
            return Some(&mut self.value);
        }
        bug!(cfg, "context cell: expected key to be {VALUE}, but got {key}");
        None
    }

    fn set(&mut self, cfg: &mut Cfg, key: Key, value: Val) -> Option<()> {
        if &*key == VALUE {
            self.value = value;
            return Some(());
        }
        bug!(cfg, "context cell: expected key to be {VALUE}, but got {key}");
        None
    }
}

pub(crate) const LEFT: &str = concatcp!(PREFIX_ID, "left");
pub(crate) const RIGHT: &str = concatcp!(PREFIX_ID, "right");

impl DynCtx<Key, Val> for PairVal {
    fn ref_(&self, cfg: &mut Cfg, key: Key) -> Option<&Val> {
        match &*key {
            LEFT => return Some(&self.left),
            RIGHT => return Some(&self.right),
            _ => {}
        }
        bug!(cfg, "context pair: expected key to be {LEFT} or {RIGHT}, but got {key}");
        None
    }

    fn ref_mut(&mut self, cfg: &mut Cfg, key: Key) -> Option<&mut Val> {
        match &*key {
            LEFT => return Some(&mut self.left),
            RIGHT => return Some(&mut self.right),
            _ => {}
        }
        bug!(cfg, "context pair: expected key to be {LEFT} or {RIGHT}, but got {key}");
        None
    }

    fn set(&mut self, cfg: &mut Cfg, key: Key, value: Val) -> Option<()> {
        match &*key {
            LEFT => {
                self.left = value;
                return Some(());
            }
            RIGHT => {
                self.right = value;
                return Some(());
            }
            _ => {}
        }
        bug!(cfg, "context pair: expected key to be {LEFT} or {RIGHT}, but got {key}");
        None
    }
}

pub(crate) const FUNCTION: &str = concatcp!(PREFIX_ID, "function");
pub(crate) const INPUT: &str = concatcp!(PREFIX_ID, "input");

impl DynCtx<Key, Val> for CallVal {
    fn ref_(&self, cfg: &mut Cfg, key: Key) -> Option<&Val> {
        match &*key {
            FUNCTION => return Some(&self.func),
            INPUT => return Some(&self.input),
            _ => {}
        }
        bug!(cfg, "context call: expected key to be {FUNCTION} or {INPUT}, but got {key}");
        None
    }

    fn ref_mut(&mut self, cfg: &mut Cfg, key: Key) -> Option<&mut Val> {
        match &*key {
            FUNCTION => return Some(&mut self.func),
            INPUT => return Some(&mut self.input),
            _ => {}
        }
        bug!(cfg, "context call: expected key to be {FUNCTION} or {INPUT}, but got {key}");
        None
    }

    fn set(&mut self, cfg: &mut Cfg, key: Key, value: Val) -> Option<()> {
        match &*key {
            FUNCTION => {
                self.func = value;
                return Some(());
            }
            INPUT => {
                self.input = value;
                return Some(());
            }
            _ => {}
        }
        bug!(cfg, "context call: expected key to be {FUNCTION} or {INPUT}, but got {key}");
        None
    }
}

pub(crate) const FIRST: &str = concatcp!(PREFIX_ID, "first");
pub(crate) const LAST: &str = concatcp!(PREFIX_ID, "last");

impl DynCtx<Key, Val> for ListVal {
    fn ref_(&self, cfg: &mut Cfg, key: Key) -> Option<&Val> {
        match &*key {
            FIRST => {
                if let Some(first) = self.first() {
                    return Some(first);
                }
                bug!(cfg, "context list: get first item on an empty list");
            }
            LAST => {
                if let Some(last) = self.last() {
                    return Some(last);
                }
                bug!(cfg, "context list: get last item on an empty list");
            }
            s => {
                bug!(cfg, "context list: expected key to be {FIRST} or {LAST}, but got {s}");
            }
        }
        None
    }

    fn ref_mut(&mut self, cfg: &mut Cfg, key: Key) -> Option<&mut Val> {
        match &*key {
            FIRST => {
                if let Some(first) = self.first_mut() {
                    return Some(first);
                }
                bug!(cfg, "context list: get first item on an empty list");
            }
            LAST => {
                if let Some(last) = self.last_mut() {
                    return Some(last);
                }
                bug!(cfg, "context list: get last item on an empty list");
            }
            s => {
                bug!(cfg, "context list: expected key to be {FIRST} or {LAST}, but got {s}");
            }
        }
        None
    }

    fn set(&mut self, cfg: &mut Cfg, key: Key, value: Val) -> Option<()> {
        match &*key {
            FIRST => {
                if let Some(first) = self.first_mut() {
                    *first = value;
                    return Some(());
                }
                bug!(cfg, "context list: get first item on an empty list");
            }
            LAST => {
                if let Some(last) = self.last_mut() {
                    *last = value;
                    return Some(());
                }
                bug!(cfg, "context list: get last item on an empty list");
            }
            s => {
                bug!(cfg, "context list: expected key to be {FIRST} or {LAST}, but got {s}");
            }
        }
        None
    }
}

impl DynCtx<Key, Val> for MapVal {
    fn ref_(&self, cfg: &mut Cfg, key: Key) -> Option<&Val> {
        if let Some(val) = self.get(&key) {
            return Some(val);
        }
        bug!(cfg, "context map: value not found for key {key}");
        None
    }

    fn ref_mut(&mut self, cfg: &mut Cfg, key: Key) -> Option<&mut Val> {
        if let Some(val) = self.get_mut(&key) {
            return Some(val);
        }
        bug!(cfg, "context map: value not found for key {key}");
        None
    }

    fn set(&mut self, _cfg: &mut Cfg, key: Key, value: Val) -> Option<()> {
        self.insert(key, value);
        Some(())
    }
}

impl DynCtx<Key, Val> for Val {
    fn ref_(&self, cfg: &mut Cfg, key: Key) -> Option<&Val> {
        match self {
            Val::Cell(cell) => cell.ref_(cfg, key),
            Val::Pair(pair) => pair.ref_(cfg, key),
            Val::Call(call) => call.ref_(cfg, key),
            Val::List(list) => list.ref_(cfg, key),
            Val::Map(map) => map.ref_(cfg, key),
            Val::Dyn(val) => val.ref_(cfg, Val::Key(key)),
            v => {
                bug!(cfg, "context: value not found for key {key} in {v}");
                None
            }
        }
    }

    fn ref_mut(&mut self, cfg: &mut Cfg, key: Key) -> Option<&mut Val> {
        match self {
            Val::Cell(cell) => cell.ref_mut(cfg, key),
            Val::Pair(pair) => pair.ref_mut(cfg, key),
            Val::Call(call) => call.ref_mut(cfg, key),
            Val::List(list) => list.ref_mut(cfg, key),
            Val::Map(map) => map.ref_mut(cfg, key),
            Val::Dyn(val) => val.ref_mut(cfg, Val::Key(key)),
            v => {
                bug!(cfg, "context: value not found for key {key} in {v}");
                None
            }
        }
    }

    fn set(&mut self, cfg: &mut Cfg, key: Key, value: Val) -> Option<()> {
        match self {
            Val::Cell(cell) => cell.set(cfg, key, value),
            Val::Pair(pair) => pair.set(cfg, key, value),
            Val::Call(call) => call.set(cfg, key, value),
            Val::List(list) => list.set(cfg, key, value),
            Val::Map(map) => map.set(cfg, key, value),
            Val::Dyn(val) => val.set(cfg, Val::Key(key), value),
            v => {
                bug!(cfg, "context: value not found for key {key} in {v}");
                None
            }
        }
    }
}

impl DynCtx<IntVal, Val> for ListVal {
    fn ref_(&self, cfg: &mut Cfg, key: IntVal) -> Option<&Val> {
        let len = self.len();
        let Some(index) = key.to_usize() else {
            bug!(cfg, "context list: key {key} should >= 0 and < list.length {len}");
            return None;
        };
        let Some(val) = self.get(index) else {
            bug!(cfg, "context list: key {index} should < list.length {len}");
            return None;
        };
        Some(val)
    }

    fn ref_mut(&mut self, cfg: &mut Cfg, key: IntVal) -> Option<&mut Val> {
        let len = self.len();
        let Some(index) = key.to_usize() else {
            bug!(cfg, "context list: key {key} should >= 0 and < list.length {len}");
            return None;
        };
        let Some(val) = self.get_mut(index) else {
            bug!(cfg, "context list: key {index} should < list.length {len}");
            return None;
        };
        Some(val)
    }

    fn set(&mut self, cfg: &mut Cfg, key: IntVal, value: Val) -> Option<()> {
        let len = self.len();
        let Some(index) = key.to_usize() else {
            bug!(cfg, "context list: key {key} should >= 0 and < list.length {len}");
            return None;
        };
        let Some(val) = self.get_mut(index) else {
            bug!(cfg, "context list: key {index} should < list.length {len}");
            return None;
        };
        *val = value;
        Some(())
    }
}

impl DynCtx<Val, Val> for Val {
    fn ref_(&self, cfg: &mut Cfg, key: Val) -> Option<&Val> {
        if let Val::Key(name) = &key {
            return self.ref_(cfg, name.clone());
        }
        match self {
            Val::List(list) => {
                let Val::Int(index) = key else {
                    bug!(cfg, "context list: key {key} should be an integer");
                    return None;
                };
                list.ref_(cfg, index)
            }
            Val::Dyn(val) => val.ref_(cfg, key),
            _ => {
                bug!(cfg, "context: value not found for key {key} in {self}");
                None
            }
        }
    }

    fn ref_mut(&mut self, cfg: &mut Cfg, key: Val) -> Option<&mut Val> {
        if let Val::Key(name) = &key {
            return self.ref_mut(cfg, name.clone());
        }
        match self {
            Val::List(list) => {
                let Val::Int(index) = key else {
                    bug!(cfg, "context list: key {key} should be an integer");
                    return None;
                };
                list.ref_mut(cfg, index)
            }
            Val::Dyn(val) => val.ref_mut(cfg, key),
            _ => {
                bug!(cfg, "context: value not found for key {key} in {self}");
                None
            }
        }
    }

    fn set(&mut self, cfg: &mut Cfg, key: Val, value: Val) -> Option<()> {
        if let Val::Key(name) = &key {
            return self.set(cfg, name.clone(), value);
        }
        match self {
            Val::List(list) => {
                let Val::Int(index) = key else {
                    bug!(cfg, "context list: key {key} should be an integer");
                    return None;
                };
                list.set(cfg, index, value)
            }
            Val::Dyn(val) => val.set(cfg, key, value),
            _ => {
                bug!(cfg, "context: value not found for key {key} in {self}");
                None
            }
        }
    }
}