use std::collections::HashMap;
use anathema_store::slab::{Slab, SlabIndex};
use crate::expressions::Expression;
#[derive(Debug, Default, Clone)]
pub struct Globals(HashMap<String, Variable>);
impl Globals {
pub fn empty() -> Self {
Self(HashMap::new())
}
pub fn new(hm: HashMap<String, Variable>) -> Self {
Self(hm)
}
pub fn get(&self, ident: &str) -> Option<&Expression> {
match self.0.get(ident) {
Some(Variable::Global(expr)) => Some(expr),
_ => None,
}
}
pub fn take(&mut self) -> Self {
std::mem::take(self)
}
}
impl From<Variables> for Globals {
fn from(value: Variables) -> Self {
Self(value.into())
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct VarId(usize);
impl SlabIndex for VarId {
const MAX: usize = usize::MAX;
fn as_usize(&self) -> usize {
self.0
}
fn from_usize(index: usize) -> Self
where
Self: Sized,
{
Self(index)
}
}
#[derive(Debug, Clone)]
pub enum Variable {
LocalIdent,
Global(Expression),
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct ScopeId(Box<[u16]>);
impl ScopeId {
#[cfg(test)]
fn next(&self, index: u16) -> Self {
let mut scope_id = Vec::with_capacity(self.0.len() + 1);
scope_id.extend_from_slice(&self.0);
scope_id.push(index);
Self(scope_id.into())
}
#[cfg(test)]
fn parent(&self) -> &[u16] {
debug_assert!(self.0.len() > 1);
let to = self.0.len() - 1;
&self.0[..to]
}
#[cfg(test)]
fn sub_path_len(&self, id: impl AsRef<[u16]>) -> Option<usize> {
let id = id.as_ref();
let len = id.len().min(self.0.len());
let lhs = &self.0[..len];
let rhs = &id[..len];
(lhs == rhs).then_some(len)
}
#[cfg(test)]
fn as_slice(&self) -> &[u16] {
&self.0
}
#[cfg(test)]
fn contains(&self, other: impl AsRef<[u16]>) -> Option<&ScopeId> {
let other = other.as_ref();
let len = self.0.len();
match other.len() >= len {
true => (*self.0 == other[..len]).then_some(self),
false => None,
}
}
}
impl AsRef<[u16]> for ScopeId {
fn as_ref(&self) -> &[u16] {
&self.0
}
}
impl From<&[u16]> for ScopeId {
fn from(value: &[u16]) -> Self {
Self(value.into())
}
}
impl<const N: usize> From<[u16; N]> for ScopeId {
fn from(value: [u16; N]) -> Self {
Self(value.into())
}
}
#[derive(Debug)]
struct RootScope(Scope);
impl Default for RootScope {
fn default() -> Self {
Self(Scope::new(ScopeId(vec![0].into())))
}
}
impl RootScope {
fn get_scope_mut(&mut self, id: impl AsRef<[u16]>) -> &mut Scope {
let mut scope = &mut self.0;
let mut id = &id.as_ref()[1..];
while !id.is_empty() {
scope = &mut scope.children[id[0] as usize];
id = &id[1..];
}
scope
}
fn get_var_id(&self, id: impl AsRef<[u16]>, ident: &str) -> Option<VarId> {
let mut scope = &self.0;
let mut id = &id.as_ref()[1..];
let mut var = self.0.variables.get(ident).and_then(|values| values.last()).copied();
while !id.is_empty() {
scope = &scope.children[id[0] as usize];
id = &id[1..];
if let val @ Some(_) = scope.variables.get(ident).and_then(|values| values.last()).copied() {
var = val;
}
}
var
}
#[cfg(test)]
fn id(&self) -> &ScopeId {
&self.0.id
}
#[cfg(test)]
fn insert(&mut self, ident: impl Into<String>, var: VarId) {
self.0.insert(ident.into(), var)
}
#[cfg(test)]
fn create_child(&mut self) -> ScopeId {
self.0.create_child()
}
}
#[derive(Debug)]
pub struct Scope {
variables: HashMap<String, Vec<VarId>>,
id: ScopeId,
children: Vec<Scope>,
}
impl Scope {
fn new(id: ScopeId) -> Self {
Self {
id,
variables: Default::default(),
children: vec![],
}
}
#[cfg(test)]
fn create_child(&mut self) -> ScopeId {
let index = self.children.len();
let id = self.id.next(index as u16);
self.children.push(Scope::new(id.clone()));
id
}
fn insert(&mut self, ident: impl Into<String>, value: VarId) {
let entry = self.variables.entry(ident.into()).or_default();
entry.push(value);
}
}
#[derive(Debug)]
struct Declarations(HashMap<String, Vec<(ScopeId, VarId)>>);
impl Declarations {
fn new() -> Self {
Self(HashMap::new())
}
fn add(&mut self, ident: impl Into<String>, id: impl Into<ScopeId>, value_id: impl Into<VarId>) {
let value_id = value_id.into();
let ids = self.0.entry(ident.into()).or_default();
ids.push((id.into(), value_id));
}
#[cfg(test)]
fn get(&self, ident: &str, id: impl AsRef<[u16]>) -> Option<(&ScopeId, VarId)> {
self.0
.get(ident)
.unwrap()
.iter()
.rev()
.filter_map(|(scope, value)| scope.contains(&id).map(|s| (s, *value)))
.next()
}
#[cfg(test)]
fn get_ref(&self, ident: &str, id: impl AsRef<[u16]>) -> &[u16] {
self.get(ident, id).unwrap().0.as_ref()
}
}
#[derive(Debug)]
pub struct Variables {
root: RootScope,
current: ScopeId,
store: Slab<VarId, Variable>,
declarations: Declarations,
}
impl Default for Variables {
fn default() -> Self {
let root = RootScope::default();
Self {
current: root.0.id.clone(),
root,
store: Slab::empty(),
declarations: Declarations::new(),
}
}
}
impl Variables {
pub fn new() -> Self {
Self::default()
}
pub fn take(&mut self) -> Self {
std::mem::take(self)
}
fn declare_at(&mut self, ident: impl Into<String>, var_id: VarId, id: ScopeId) -> VarId {
let ident = ident.into();
let scope = self.root.get_scope_mut(id);
scope.insert(ident.clone(), var_id);
self.declarations.add(ident, scope.id.clone(), var_id);
var_id
}
pub fn declare(&mut self, ident: impl Into<String>, value: impl Into<Expression>) -> VarId {
let value = value.into();
let var_id = self.store.insert(Variable::Global(value));
let scope_id = self.current.clone();
self.declare_at(ident, var_id, scope_id)
}
pub fn declare_local(&mut self, ident: impl Into<String>) -> VarId {
let value = Variable::LocalIdent;
let var_id = self.store.insert(value);
let scope_id = self.current.clone();
self.declare_at(ident, var_id, scope_id)
}
pub fn fetch(&self, ident: &str) -> Option<Expression> {
self.root
.get_var_id(&self.current, ident)
.and_then(|id| self.store.get(id).cloned())
.and_then(|val| match val {
Variable::Global(expression) => Some(expression),
Variable::LocalIdent => None,
})
}
#[cfg(test)]
pub(crate) fn push(&mut self) {
let parent = self.root.get_scope_mut(&self.current);
self.current = parent.create_child();
}
#[cfg(test)]
pub(crate) fn pop(&mut self) {
self.current = self.current.parent().into();
}
#[cfg(test)]
fn by_value_ref(&self, var: VarId) -> Expression {
self.store
.get(var)
.cloned()
.map(|val| match val {
Variable::LocalIdent => unreachable!("this is a test function"),
Variable::Global(expression) => expression,
})
.expect("it would be an Anathema compilation error if this failed")
}
}
impl From<Variables> for HashMap<String, Variable> {
fn from(mut vars: Variables) -> Self {
let mut hm = HashMap::new();
for (key, mut ids) in vars.declarations.0.into_iter() {
let (_, var_id) = ids
.pop()
.expect("there is always at least one var id associated with a key");
let val = vars.store.remove(var_id);
hm.insert(key, val);
}
hm
}
}
#[cfg(test)]
mod test {
use super::*;
impl From<usize> for VarId {
fn from(value: usize) -> Self {
VarId(value)
}
}
#[test]
fn scope_id_next() {
let id = ScopeId::from([0]);
assert_eq!(id.next(0).as_slice(), &[0, 0]);
}
#[test]
fn scope_id_parent() {
let id = ScopeId::from([1, 0]);
assert_eq!(id.parent(), &[1]);
}
#[test]
fn scope_min() {
let a = ScopeId::from([1, 0]);
let b = ScopeId::from([1, 0, 0, 1]);
let expected = [1, 0].len();
let actual = a.sub_path_len(b).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn create_child() {
let mut root = RootScope::default();
let child_id = root.create_child();
assert_eq!(root.0.children.len(), 1);
assert_eq!(child_id.as_ref(), &[0, 0]);
}
#[test]
fn get_value() {
let expected: VarId = 123.into();
let mut root = RootScope::default();
root.insert("var", expected);
let actual = root.get_var_id(root.id(), "var").unwrap();
assert_eq!(expected, actual);
}
#[test]
fn child_get_value() {
let expected: VarId = 1.into();
let ident = "var";
let mut root = RootScope::default();
let child_id = root.create_child();
let child = root.get_scope_mut(&child_id);
child.insert(ident, expected);
let actual = root.get_var_id(&child_id, ident).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn variable_declaration() {
let mut vars = Variables::new();
let expected = Expression::from(123i64);
vars.declare("var", expected.clone());
let value = vars.fetch("var").unwrap();
assert_eq!(expected, value);
}
#[test]
fn shadow_value() {
let ident = "var";
let mut vars = Variables::new();
let value_a = Expression::from("1");
let value_b = Expression::from("2");
let first_value_ref = vars.declare(ident, value_a.clone());
let second_value_ref = vars.declare(ident, value_b.clone());
assert_eq!(value_a, vars.by_value_ref(first_value_ref));
assert_eq!(value_b, vars.by_value_ref(second_value_ref));
}
#[test]
fn scoping_variables_inaccessible_sibling() {
let mut vars = Variables::new();
let ident = "var";
vars.push();
vars.declare(ident, "inaccessible");
assert!(vars.fetch(ident).is_some());
vars.pop();
assert!(vars.fetch(ident).is_none());
vars.push();
assert!(vars.fetch(ident).is_none());
}
#[test]
fn declaration_lookup() {
let mut dec = Declarations::new();
dec.add("var", [0], 0);
let root = dec.get_ref("var", [0, 0]);
assert_eq!(root, &[0]);
}
#[test]
fn declaration_failed_lookup() {
let mut dec = Declarations::new();
dec.add("var", [0], 0);
let root = dec.get("var", [1, 0]);
assert!(root.is_none());
}
#[test]
fn multi_level_declarations() {
let mut dec = Declarations::new();
let ident = "var";
dec.add(ident, [0], 0);
dec.add(ident, [0, 0], 0);
dec.add(ident, [0, 0, 0], 0);
assert_eq!(dec.get_ref(ident, [0, 0]), &[0, 0]);
assert_eq!(dec.get_ref(ident, [0, 0, 0, 1, 1]), &[0, 0, 0]);
}
#[test]
fn unreachable_declaration() {
let mut dec = Declarations::new();
dec.add("var", [0, 1], 0);
assert!(dec.get("var", [0, 0, 1]).is_none());
}
}