Skip to content

Commit

Permalink
Simplify object construction.
Browse files Browse the repository at this point in the history
  • Loading branch information
01mf02 committed Mar 4, 2024
1 parent b5e022e commit be30608
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 78 deletions.
36 changes: 7 additions & 29 deletions jaq-interpret/src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ pub(crate) enum Ast {
Float(f64),
Str(String),
Array(Id),
Object(Box<[(Id, Id)]>),
ObjEmpty,
ObjSingle(Id, Id),

Try(Id, Id),
Neg(Id),
Expand Down Expand Up @@ -142,25 +143,6 @@ fn run_cvs<'a>(f: Ref<'a>, cvs: Results<'a, Cv<'a>, Error>) -> impl Iterator<Ite
cvs.flat_map(move |cv| then(cv, |cv| f.run(cv)))
}

type ObjVec = Vec<(ValR, ValR)>;
fn obj_cart<'a, I>(mut args: I, cv: Cv<'a>, prev: ObjVec) -> BoxIter<'a, ObjVec>
where
I: Iterator<Item = (Ref<'a>, Ref<'a>)> + Clone + 'a,
{
if let Some((l, r)) = args.next() {
let iter = l.run(cv.clone());
flat_map_with(iter, (args, cv, prev), move |l, (args, cv, prev)| {
let iter = r.run(cv.clone());
flat_map_with(iter, (l, args, cv, prev), |r, (l, args, cv, mut prev)| {
prev.push((l, r));
obj_cart(args, cv, prev)
})
})
} else {
box_once(prev)
}
}

fn reduce<'a, T: Clone + 'a, F>(xs: Results<'a, T, Error>, init: Val, f: F) -> ValRs
where
F: Fn(T, Val) -> ValRs<'a> + 'a,
Expand Down Expand Up @@ -240,14 +222,10 @@ impl<'a> FilterT<'a> for Ref<'a> {
Ast::Array(f) => Box::new(once_with(move || {
w(f).run(cv).collect::<Result<_, _>>().map(Val::arr)
})),
Ast::Object(o) if o.is_empty() => box_once(Ok(Val::Obj(Default::default()))),
Ast::Object(o) => Box::new(
obj_cart(o.iter().map(move |(k, v)| (w(k), w(v))), cv, Vec::new()).map(|kvs| {
kvs.into_iter()
.map(|(k, v)| Ok((k?.to_str()?, v?)))
.collect::<Result<_, _>>()
.map(Val::obj)
}),
Ast::ObjEmpty => box_once(Ok(Val::Obj(Default::default()))),
Ast::ObjSingle(k, v) => Box::new(
Self::cartesian(w(k), w(v), cv)
.map(|(k, v)| Ok(Val::obj([(k?.to_str()?, v?)].into_iter().collect()))),
),
Ast::Try(f, c) => Box::new(w(f).run((cv.0.clone(), cv.1)).flat_map(move |y| {
y.map_or_else(
Expand Down Expand Up @@ -364,7 +342,7 @@ impl<'a> FilterT<'a> for Ref<'a> {
match &self.1[self.0 .0] {
Ast::ToString => err,
Ast::Int(_) | Ast::Float(_) | Ast::Str(_) => err,
Ast::Array(_) | Ast::Object(_) => err,
Ast::Array(_) | Ast::ObjEmpty | Ast::ObjSingle(..) => err,
Ast::Neg(_) | Ast::Logic(..) | Ast::Math(..) | Ast::Ord(..) => err,
Ast::Update(..) | Ast::UpdateMath(..) | Ast::Assign(..) => err,

Expand Down
105 changes: 56 additions & 49 deletions jaq-interpret/src/lir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,9 @@ fn recurse(typ: CallTyp) -> Filter {
impl Ctx {
/// `{}[]` returns zero values.
fn empty(&mut self) -> Filter {
// `{}`
let obj = Filter::Object(Default::default());
// `[]`
let path = (path::Part::Range(None, None), path::Opt::Essential);
Filter::Path(self.id_of_ast(obj), Path(Vec::from([path])))
Filter::Path(self.id_of_ast(Filter::ObjEmpty), Path(Vec::from([path])))
}

/// `..`, also known as `recurse/0`, is defined as `., (.[]? | ..)`
Expand Down Expand Up @@ -128,31 +126,52 @@ impl Ctx {
AbsId(len)
}

fn get(&mut self, f: Spanned<mir::Filter>) -> AbsId {
let f = self.filter(f);
self.id_of_ast(f)
}

fn add(&mut self, l: Filter, r: Filter) -> Filter {
Filter::Math(self.id_of_ast(l), MathOp::Add, self.id_of_ast(r))
}

fn of_str(&mut self, s: Str<Spanned<mir::Filter>>) -> Filter {
let fmt = s.fmt.map_or(TOSTRING, |fmt| self.get(*fmt));
use jaq_syn::string::Part;
let iter = s.parts.into_iter().map(|part| match part {
Part::Str(s) => Filter::Str(s),
Part::Fun(f) => Filter::Pipe(self.get(f), false, fmt),
});
let mut iter = iter.collect::<Vec<_>>().into_iter().rev();
let last = iter.next().unwrap_or_else(|| Filter::Str("".into()));
iter.fold(last, |acc, x| self.add(x, acc))
}

fn of_key_val(&mut self, kv: KeyVal<Spanned<mir::Filter>>) -> Filter {
match kv {
KeyVal::Filter(k, v) => Filter::ObjSingle(self.get(k), self.get(v)),
KeyVal::Str(k, v) => {
let k = self.of_str(k);
let k = self.id_of_ast(k);
let v = match v {
None => {
self.id_of_ast(Filter::Path(IDENTITY, Path::from(path::Part::Index(k))))
}
Some(v) => self.get(v),
};
Filter::ObjSingle(k, v)
}
}
}

/// Convert a MIR filter to a LIR filter.
fn filter(&mut self, f: Spanned<mir::Filter>) -> Filter {
let get = |f, ctx: &mut Self| {
let f = ctx.filter(f);
ctx.id_of_ast(f)
};
let of_str = |s: Str<_>, ctx: &mut Self| {
let fmt = s.fmt.map_or(TOSTRING, |fmt| get(*fmt, ctx));
use jaq_syn::string::Part;
let iter = s.parts.into_iter().map(|part| match part {
Part::Str(s) => Filter::Str(s),
Part::Fun(f) => Filter::Pipe(get(f, ctx), false, fmt),
});
let mut iter = iter.collect::<Vec<_>>().into_iter().rev();
let last = iter.next();
iter.fold(last.unwrap_or_else(|| Filter::Str("".into())), |acc, x| {
Filter::Math(ctx.id_of_ast(x), MathOp::Add, ctx.id_of_ast(acc))
})
};
use mir::Filter as Expr;

match f.0 {
Expr::Var(v) => Filter::Var(v),
Expr::Call(call, args) => {
let args: Vec<_> = args.into_iter().map(|a| get(a, self)).collect();
let args: Vec<_> = args.into_iter().map(|a| self.get(a)).collect();
match call {
mir::Call::Arg(a) if args.is_empty() => Filter::Var(a),
mir::Call::Arg(_) => panic!("higher-order argument encountered"),
Expand Down Expand Up @@ -180,38 +199,26 @@ impl Ctx {
}

Expr::Fold(typ, Fold { xs, init, f, .. }) => {
Filter::Fold(typ, get(*xs, self), get(*init, self), get(*f, self))
Filter::Fold(typ, self.get(*xs), self.get(*init), self.get(*f))
}

Expr::Id => Filter::Id,
Expr::Num(hir::Num::Float(f)) => Filter::Float(f),
Expr::Num(hir::Num::Int(i)) => Filter::Int(i),
Expr::Str(s) => of_str(*s, self),
Expr::Array(a) => Filter::Array(a.map_or(EMPTY, |a| get(*a, self))),
Expr::Str(s) => self.of_str(*s),
Expr::Array(a) => Filter::Array(a.map_or(EMPTY, |a| self.get(*a))),
Expr::Object(o) => {
let kvs = o.into_iter().map(|kv| match kv {
KeyVal::Filter(k, v) => (get(k, self), get(v, self)),
KeyVal::Str(k, v) => {
let k = of_str(k, self);
let k = self.id_of_ast(k);
let v = match v {
None => self.id_of_ast(Filter::Path(
IDENTITY,
Path::from(path::Part::Index(k)),
)),
Some(v) => get(v, self),
};
(k, v)
}
});
Filter::Object(kvs.collect())
let kvs = o.into_iter().map(|kv| self.of_key_val(kv));
let mut kvs = kvs.collect::<Vec<_>>().into_iter().rev();
let last = kvs.next().unwrap_or(Filter::ObjEmpty);
kvs.fold(last, |acc, x| self.add(x, acc))
}
Expr::Try(f) => Filter::Try(get(*f, self), EMPTY),
Expr::Neg(f) => Filter::Neg(get(*f, self)),
Expr::Try(f) => Filter::Try(self.get(*f), EMPTY),
Expr::Neg(f) => Filter::Neg(self.get(*f)),
Expr::Recurse => recurse(CallTyp::Catch),

Expr::Binary(l, op, r) => {
let (l, r) = (get(*l, self), get(*r, self));
let (l, r) = (self.get(*l), self.get(*r));
match op {
BinaryOp::Pipe(bind) => Filter::Pipe(l, bind.is_some(), r),
BinaryOp::Comma => Filter::Comma(l, r),
Expand All @@ -229,20 +236,20 @@ impl Ctx {
Expr::Ite(if_thens, else_) => {
let else_ = else_.map_or(Filter::Id, |else_| self.filter(*else_));
if_thens.into_iter().rev().fold(else_, |acc, (if_, then_)| {
Filter::Ite(get(if_, self), get(then_, self), self.id_of_ast(acc))
Filter::Ite(self.get(if_), self.get(then_), self.id_of_ast(acc))
})
}
Expr::TryCatch(try_, catch_) => {
Filter::Try(get(*try_, self), catch_.map_or(EMPTY, |c| get(*c, self)))
Filter::Try(self.get(*try_), catch_.map_or(EMPTY, |c| self.get(*c)))
}
Expr::Path(f, path) => {
let f = get(*f, self);
let f = self.get(*f);
use jaq_syn::path::Part;
let path = path.into_iter().map(|(p, opt)| match p {
Part::Index(i) => (path::Part::Index(get(i, self)), opt),
Part::Index(i) => (path::Part::Index(self.get(i)), opt),
Part::Range(lower, upper) => {
let lower = lower.map(|f| get(f, self));
let upper = upper.map(|f| get(f, self));
let lower = lower.map(|f| self.get(f));
let upper = upper.map(|f| self.get(f));
(path::Part::Range(lower, upper), opt)
}
});
Expand Down

0 comments on commit be30608

Please sign in to comment.