Skip to content

Commit

Permalink
Move complexity of path operations into path module.
Browse files Browse the repository at this point in the history
  • Loading branch information
01mf02 committed Jan 18, 2024
1 parent 482c876 commit 84214cb
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 43 deletions.
42 changes: 7 additions & 35 deletions jaq-interpret/src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,24 +278,13 @@ impl<'a> FilterT<'a> for Ref<'a> {
w(if v.as_bool() { then_ } else { else_ }).run(cv)
}),
Ast::Path(f, path) => {
// TODO: a great part of the following code is duplicated in `update()`
// it would be great to factor out this part, but I find this quite difficult ...
use crate::path::{self, Path};
let run = |i| {
let path = path.map_ref(|i| {
let cv = cv.clone();
crate::into_iter::collect_if_once(move || w(i).run(cv))
};
let path = path.0.iter();
let path = path.map(move |(part, opt)| (part.as_ref().map(run), *opt));
let path: Vec<_> = path.collect();
});
flat_map_with(w(f).run(cv), path, |y, path| {
let paths = Path(Vec::new()).combinations(path.into_iter());
let paths = paths.map(|path| path.transpose());

then(y, |y| {
flat_map_with(paths, y, |path, y| {
then(path, |path| (path::run(path.0.into_iter(), y)))
})
flat_map_with(path.explode(), y, |path, y| then(path, |path| path.run(y)))
})
})
}
Expand Down Expand Up @@ -385,31 +374,14 @@ impl<'a> FilterT<'a> for Ref<'a> {
Ast::Id => f(cv.1),

Ast::Path(l, path) => {
use crate::path::{self, Path};
let run = |i| {
let path = path.map_ref(|i| {
let cv = cv.clone();
crate::into_iter::collect_if_once(move || w(i).run(cv))
};
let path = path.0.iter();
let path = path.map(move |(part, opt)| (part.as_ref().map(run), *opt));
let path: Vec<_> = path.collect();

});
let f = move |v| {
let path = path.clone();
let paths = Path(Vec::new()).combinations(path.into_iter());
let mut paths = paths.map(|path| path.transpose());

box_once(paths.try_fold(v, |acc, path| {
let mut path = path?;
if let Some(last) = path.0.pop() {
path::update(path.0.into_iter(), last, acc, &f)
} else {
// should be unreachable
Ok(acc)
}
}))
let mut paths = path.clone().explode();
box_once(paths.try_fold(v, |acc, path| path?.update(acc, &f)))
};

w(l).update(cv, Box::new(f))
}
Ast::Pipe(l, false, r) => w(l).update(
Expand Down
47 changes: 39 additions & 8 deletions jaq-interpret/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,16 @@ pub enum Part<I> {
Range(Option<I>, Option<I>),
}

impl<'a, U: Clone + 'a, E: Clone + 'a, T: Clone + IntoIterator<Item = Result<U, E>> + 'a> Path<T> {
pub fn explode(self) -> impl Iterator<Item = Result<Path<U>, E>> + 'a {
Path(Vec::new())
.combinations(self.0.into_iter())
.map(|path| path.transpose())
}
}

impl<'a, U: Clone + 'a> Path<U> {
pub fn combinations<I, F>(self, mut iter: I) -> BoxIter<'a, Self>
fn combinations<I, F>(self, mut iter: I) -> BoxIter<'a, Self>
where
I: Iterator<Item = (Part<F>, Opt)> + Clone + 'a,
F: IntoIterator<Item = U> + Clone + 'a,
Expand All @@ -33,7 +41,22 @@ impl<'a, U: Clone + 'a> Path<U> {
}
}

pub fn run<'a, I>(mut iter: I, val: Val) -> ValRs<'a>
impl Path<Val> {
pub fn run<'a>(self, v: Val) -> ValRs<'a> {
run(self.0.into_iter(), v)
}

pub fn update<'a, F: Fn(Val) -> ValRs<'a>>(mut self, v: Val, f: F) -> ValR {
if let Some(last) = self.0.pop() {
update(self.0.into_iter(), last, v, &f)
} else {
// should be unreachable
Ok(v)
}
}
}

fn run<'a, I>(mut iter: I, val: Val) -> ValRs<'a>
where
I: Iterator<Item = (Part<Val>, Opt)> + Clone + 'a,
{
Expand All @@ -46,10 +69,10 @@ where
}
}

pub fn update<'f, P, F>(mut iter: P, last: (Part<Val>, Opt), v: Val, f: F) -> ValR
fn update<'f, P, F>(mut iter: P, last: (Part<Val>, Opt), v: Val, f: &F) -> ValR
where
P: Iterator<Item = (Part<Val>, Opt)> + Clone,
F: Fn(Val) -> ValRs<'f> + Copy,
F: Fn(Val) -> ValRs<'f>,
{
if let Some((part, opt)) = iter.next() {
use core::iter::once;
Expand Down Expand Up @@ -201,8 +224,16 @@ impl<'a, U: Clone + 'a, F: IntoIterator<Item = U> + Clone + 'a> Part<F> {
}
}

impl<T> Path<T> {
pub fn map_ref<'a, U>(&'a self, mut f: impl FnMut(&'a T) -> U) -> Path<U> {
let path = self.0.iter();
let path = path.map(move |(part, opt)| (part.as_ref().map(&mut f), *opt));
Path(path.collect())
}
}

impl<T> Part<T> {
pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> Part<U> {
fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> Part<U> {
use Part::{Index, Range};
match self {
Index(i) => Index(f(i)),
Expand All @@ -212,7 +243,7 @@ impl<T> Part<T> {
}

impl<T, E> Path<Result<T, E>> {
pub fn transpose(self) -> Result<Path<T>, E> {
fn transpose(self) -> Result<Path<T>, E> {
self.0
.into_iter()
.map(|(part, opt)| Ok((part.transpose()?, opt)))
Expand All @@ -222,7 +253,7 @@ impl<T, E> Path<Result<T, E>> {
}

impl<T, E> Part<Result<T, E>> {
pub fn transpose(self) -> Result<Part<T>, E> {
fn transpose(self) -> Result<Part<T>, E> {
match self {
Self::Index(i) => Ok(Part::Index(i?)),
Self::Range(from, upto) => Ok(Part::Range(from.transpose()?, upto.transpose()?)),
Expand All @@ -231,7 +262,7 @@ impl<T, E> Part<Result<T, E>> {
}

impl<F> Part<F> {
pub fn as_ref(&self) -> Part<&F> {
fn as_ref(&self) -> Part<&F> {
match self {
Self::Index(i) => Part::Index(i),
Self::Range(from, upto) => Part::Range(from.as_ref(), upto.as_ref()),
Expand Down

0 comments on commit 84214cb

Please sign in to comment.