Skip to content

Commit

Permalink
add nice iterator for hierarchical structures
Browse files Browse the repository at this point in the history
  • Loading branch information
vincenthz committed Feb 19, 2024
1 parent 710b90f commit e738734
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 9 deletions.
31 changes: 28 additions & 3 deletions werbolg-compile/src/bindings.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::hier::Hier;
use alloc::{vec, vec::Vec};
use hashbrown::HashMap;
use werbolg_core::{AbsPath, Ident};
use hashbrown::{hash_map, HashMap};
use werbolg_core::{AbsPath, Ident, Namespace};

#[derive(Clone)]
pub struct Bindings<T>(HashMap<Ident, T>);
Expand All @@ -18,6 +18,16 @@ impl<T> Default for Bindings<T> {
}
}

pub struct BindingsIterator<'a, T>(hash_map::Iter<'a, Ident, T>);

impl<'a, T> Iterator for BindingsIterator<'a, T> {
type Item = (&'a Ident, &'a T);

fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}

pub struct BindingInsertError {
pub name: Ident,
}
Expand Down Expand Up @@ -50,11 +60,15 @@ impl<T> Bindings<T> {
}

pub fn dump<W: core::fmt::Write>(&self, writer: &mut W) -> Result<(), core::fmt::Error> {
for (ident, _) in self.0.iter() {
for (ident, _) in self.iter() {
writeln!(writer, "{:?}", ident)?
}
Ok(())
}

pub fn iter<'a>(&'a self) -> BindingsIterator<'a, T> {
BindingsIterator(self.0.iter())
}
}

impl<T: Clone> GlobalBindings<T> {
Expand Down Expand Up @@ -82,6 +96,17 @@ impl<T: Clone> GlobalBindings<T> {
let bindings = self.0.get(&namespace).unwrap();
bindings.get(&ident)
}

#[allow(unused)]
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (AbsPath, &'a T)>
where
T: 'a,
{
self.0.iterator(
Namespace::root(),
alloc::rc::Rc::new(|x: &'a Bindings<T>| alloc::boxed::Box::new(x.iter())),
)
}
}

impl<T> BindingsStack<T> {
Expand Down
1 change: 1 addition & 0 deletions werbolg-compile/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ fn generate_expression_code<'a, L: Clone + Eq + core::hash::Hash>(
struct_ident.inner,
));
} else if result.len() > 1 {
// duplicated structs
/*
return Err(CompilationError::DuplicateSymbol(
struct_ident.span,
Expand Down
87 changes: 85 additions & 2 deletions werbolg-compile/src/hier.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use alloc::boxed::Box;
use alloc::vec::Vec;
use hashbrown::HashMap;
use werbolg_core::{Ident, Namespace};
use hashbrown::{hash_map, HashMap};
use werbolg_core::{AbsPath, Ident, Namespace};

/// A hierarchical T with recursives namespaces as Ident
pub struct Hier<T> {
Expand Down Expand Up @@ -130,3 +131,85 @@ impl<T: Default> Hier<T> {
}
}
}

impl<T> Hier<T> {
pub fn iterator<'a, I, J, F>(
&'a self,
namespace: Namespace,
f: alloc::rc::Rc<F>,
) -> HierIterator<'a, I, J, T, F>
where
F: Fn(&'a T) -> J,
J: Iterator<Item = (&'a Ident, &'a I)>,
{
HierIterator::<'a> {
namespace,
current_consumed: false,
current: CurrentOrSub::Current(f(&self.current)),
ns: self.ns.iter(),
f: f,
}
}
}

/// Hierarchy iterator for Hier<T>
///
/// 'a is the lifetime of the initial Hier<T>
/// I is the item inside the second element of the Iterator of the T
/// J is the iterator object created from T which return a Tuple of elements, (Ident, I)
/// T is the object embedded inside Hier
/// F is the closure to create the iterator associated with T
pub struct HierIterator<'a, I: 'a, J, T, F: Fn(&'a T) -> J>
where
J: Iterator<Item = (&'a Ident, &'a I)>,
{
namespace: Namespace,
current_consumed: bool,
current: CurrentOrSub<J, Box<HierIterator<'a, I, J, T, F>>>,
ns: hash_map::Iter<'a, Ident, Hier<T>>,
f: alloc::rc::Rc<F>,
}

pub enum CurrentOrSub<A, B> {
Current(A),
Sub(B),
}

impl<'a, I, J, T, F: Fn(&'a T) -> J> Iterator for HierIterator<'a, I, J, T, F>
where
J: Iterator<Item = (&'a Ident, &'a I)>,
{
type Item = (AbsPath, &'a I);

fn next(&mut self) -> Option<Self::Item> {
let next = match &mut self.current {
CurrentOrSub::Current(c_iter) => {
if let Some(x) = c_iter.next() {
let path = AbsPath::new(&self.namespace, x.0);
Some((path, x.1))
} else {
None
}
}
CurrentOrSub::Sub(e) => e.next(),
};
if let Some(x) = next {
Some(x)
} else {
if self.current_consumed {
self.namespace = self.namespace.parent();
} else {
self.current_consumed = true;
}
match self.ns.next() {
None => None,
Some((ns, hier)) => {
self.namespace = self.namespace.clone().append(ns.clone());
let x = hier.iterator(self.namespace.clone(), self.f.clone());
self.current = CurrentOrSub::Sub(Box::new(x));
self.next()
}
}
}
}
}
31 changes: 27 additions & 4 deletions werbolg-compile/src/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::hier::{Hier, HierError};
use alloc::vec::Vec;
use core::hash::Hash;
use core::marker::PhantomData;
use hashbrown::HashMap;
use hashbrown::{hash_map, HashMap};
use werbolg_core::id::IdF;
pub use werbolg_core::idvec::{IdVec, IdVecAfter};
use werbolg_core::{AbsPath, Ident, Namespace};
Expand Down Expand Up @@ -43,8 +43,18 @@ impl<ID: Copy> SymbolsTableFlat<ID> {
self.tbl.get(ident).map(|i| *i)
}

pub fn iter(&self) -> impl Iterator<Item = (&Ident, ID)> {
self.tbl.iter().map(|(ident, id)| (ident, *id))
pub fn iter<'a>(&'a self) -> SymbolsTableFlatIterator<'a, ID> {
SymbolsTableFlatIterator(self.tbl.iter())
}
}

pub struct SymbolsTableFlatIterator<'a, ID>(hash_map::Iter<'a, Ident, ID>);

impl<'a, ID> Iterator for SymbolsTableFlatIterator<'a, ID> {
type Item = (&'a Ident, &'a ID);

fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}

Expand Down Expand Up @@ -127,7 +137,7 @@ impl<ID: Copy> SymbolsTable<ID> {
for (n, t) in ts.iter() {
for (ident, id) in t.iter() {
let path = AbsPath::new(n, ident);
vec.push((path, id))
vec.push((path, *id))
}
}
}
Expand All @@ -137,6 +147,15 @@ impl<ID: Copy> SymbolsTable<ID> {
self.dump_path(current, &mut v);
v
}

pub fn iter<'a>(&'a self) -> impl Iterator<Item = (AbsPath, ID)> + 'a {
self.0
.iterator(
Namespace::root(),
alloc::rc::Rc::new(|s: &'a SymbolsTableFlat<ID>| s.iter()),
)
.map(|(x, y)| (x, *y))
}
}

/// Symbol Table Data maps Ident to ID and store the ID to T
Expand Down Expand Up @@ -183,6 +202,10 @@ impl<ID: IdF, T> SymbolsTableData<ID, T> {
pub fn to_vec(&self, current: Namespace) -> Vec<(AbsPath, ID)> {
self.table.to_vec(current)
}

pub fn iter_symbols<'a>(&'a self) -> impl Iterator<Item = (AbsPath, ID)> + 'a {
self.table.iter()
}
}

pub struct UniqueTableBuilder<ID: IdF, T: Eq + Hash> {
Expand Down
11 changes: 11 additions & 0 deletions werbolg-core/src/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,17 @@ impl Namespace {
Self(out)
}

/// Parent namespace
pub fn parent(&self) -> Self {
if self.is_root() {
Namespace::root()
} else {
let mut vec = self.0.clone();
vec.pop().unwrap();
Namespace(vec)
}
}

/// Drop the first element of the namespace
pub fn drop_first(mut self) -> (Ident, Self) {
if self.is_root() {
Expand Down

0 comments on commit e738734

Please sign in to comment.