ok/jj
1
0
Fork 0
forked from mirrors/jj

revset: add a Result version of transform_expression_bottom_up()

I'd like to add a stage after optimization for resolving most symbols
to commit IDs, and that needs to be able to fail.
This commit is contained in:
Martin von Zweigbergk 2023-03-16 11:05:16 -07:00 committed by Martin von Zweigbergk
parent 998727266c
commit 1711cb61fb

View file

@ -1047,29 +1047,37 @@ pub fn parse(
parse_program(revset_str, state) parse_program(revset_str, state)
} }
fn transform_expression_bottom_up(
expression: &Rc<RevsetExpression>,
mut f: impl FnMut(&Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>>,
) -> Option<Rc<RevsetExpression>> {
try_transform_expression_bottom_up(expression, |expression| Ok(f(expression))).unwrap()
}
type TransformResult = Result<Option<Rc<RevsetExpression>>, RevsetError>;
/// Walks `expression` tree and applies `f` recursively from leaf nodes. /// Walks `expression` tree and applies `f` recursively from leaf nodes.
/// ///
/// If `f` returns `None`, the original expression node is reused. If no nodes /// If `f` returns `None`, the original expression node is reused. If no nodes
/// rewritten, returns `None`. `std::iter::successors()` could be used if /// rewritten, returns `None`. `std::iter::successors()` could be used if
/// the transformation needs to be applied repeatedly until converged. /// the transformation needs to be applied repeatedly until converged.
fn transform_expression_bottom_up( fn try_transform_expression_bottom_up(
expression: &Rc<RevsetExpression>, expression: &Rc<RevsetExpression>,
mut f: impl FnMut(&Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>>, mut f: impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
) -> Option<Rc<RevsetExpression>> { ) -> TransformResult {
fn transform_child_rec( fn transform_child_rec(
expression: &Rc<RevsetExpression>, expression: &Rc<RevsetExpression>,
f: &mut impl FnMut(&Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>>, f: &mut impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
) -> Option<Rc<RevsetExpression>> { ) -> TransformResult {
match expression.as_ref() { Ok(match expression.as_ref() {
RevsetExpression::None => None, RevsetExpression::None => None,
RevsetExpression::All => None, RevsetExpression::All => None,
RevsetExpression::Commits(_) => None, RevsetExpression::Commits(_) => None,
RevsetExpression::Symbol(_) => None, RevsetExpression::Symbol(_) => None,
RevsetExpression::Children(roots) => { RevsetExpression::Children(roots) => {
transform_rec(roots, f).map(RevsetExpression::Children) transform_rec(roots, f)?.map(RevsetExpression::Children)
} }
RevsetExpression::Ancestors { heads, generation } => { RevsetExpression::Ancestors { heads, generation } => {
transform_rec(heads, f).map(|heads| RevsetExpression::Ancestors { transform_rec(heads, f)?.map(|heads| RevsetExpression::Ancestors {
heads, heads,
generation: generation.clone(), generation: generation.clone(),
}) })
@ -1078,21 +1086,21 @@ fn transform_expression_bottom_up(
roots, roots,
heads, heads,
generation, generation,
} => transform_rec_pair((roots, heads), f).map(|(roots, heads)| { } => transform_rec_pair((roots, heads), f)?.map(|(roots, heads)| {
RevsetExpression::Range { RevsetExpression::Range {
roots, roots,
heads, heads,
generation: generation.clone(), generation: generation.clone(),
} }
}), }),
RevsetExpression::DagRange { roots, heads } => transform_rec_pair((roots, heads), f) RevsetExpression::DagRange { roots, heads } => transform_rec_pair((roots, heads), f)?
.map(|(roots, heads)| RevsetExpression::DagRange { roots, heads }), .map(|(roots, heads)| RevsetExpression::DagRange { roots, heads }),
RevsetExpression::VisibleHeads => None, RevsetExpression::VisibleHeads => None,
RevsetExpression::Heads(candidates) => { RevsetExpression::Heads(candidates) => {
transform_rec(candidates, f).map(RevsetExpression::Heads) transform_rec(candidates, f)?.map(RevsetExpression::Heads)
} }
RevsetExpression::Roots(candidates) => { RevsetExpression::Roots(candidates) => {
transform_rec(candidates, f).map(RevsetExpression::Roots) transform_rec(candidates, f)?.map(RevsetExpression::Roots)
} }
RevsetExpression::PublicHeads => None, RevsetExpression::PublicHeads => None,
RevsetExpression::Branches(_) => None, RevsetExpression::Branches(_) => None,
@ -1102,58 +1110,62 @@ fn transform_expression_bottom_up(
RevsetExpression::GitHead => None, RevsetExpression::GitHead => None,
RevsetExpression::Filter(_) => None, RevsetExpression::Filter(_) => None,
RevsetExpression::AsFilter(candidates) => { RevsetExpression::AsFilter(candidates) => {
transform_rec(candidates, f).map(RevsetExpression::AsFilter) transform_rec(candidates, f)?.map(RevsetExpression::AsFilter)
} }
RevsetExpression::Present(candidates) => { RevsetExpression::Present(candidates) => {
transform_rec(candidates, f).map(RevsetExpression::Present) transform_rec(candidates, f)?.map(RevsetExpression::Present)
} }
RevsetExpression::NotIn(complement) => { RevsetExpression::NotIn(complement) => {
transform_rec(complement, f).map(RevsetExpression::NotIn) transform_rec(complement, f)?.map(RevsetExpression::NotIn)
} }
RevsetExpression::Union(expression1, expression2) => { RevsetExpression::Union(expression1, expression2) => {
transform_rec_pair((expression1, expression2), f).map( transform_rec_pair((expression1, expression2), f)?.map(
|(expression1, expression2)| RevsetExpression::Union(expression1, expression2), |(expression1, expression2)| RevsetExpression::Union(expression1, expression2),
) )
} }
RevsetExpression::Intersection(expression1, expression2) => { RevsetExpression::Intersection(expression1, expression2) => {
transform_rec_pair((expression1, expression2), f).map( transform_rec_pair((expression1, expression2), f)?.map(
|(expression1, expression2)| { |(expression1, expression2)| {
RevsetExpression::Intersection(expression1, expression2) RevsetExpression::Intersection(expression1, expression2)
}, },
) )
} }
RevsetExpression::Difference(expression1, expression2) => { RevsetExpression::Difference(expression1, expression2) => {
transform_rec_pair((expression1, expression2), f).map( transform_rec_pair((expression1, expression2), f)?.map(
|(expression1, expression2)| { |(expression1, expression2)| {
RevsetExpression::Difference(expression1, expression2) RevsetExpression::Difference(expression1, expression2)
}, },
) )
} }
} }
.map(Rc::new) .map(Rc::new))
} }
#[allow(clippy::type_complexity)]
fn transform_rec_pair( fn transform_rec_pair(
(expression1, expression2): (&Rc<RevsetExpression>, &Rc<RevsetExpression>), (expression1, expression2): (&Rc<RevsetExpression>, &Rc<RevsetExpression>),
f: &mut impl FnMut(&Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>>, f: &mut impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
) -> Option<(Rc<RevsetExpression>, Rc<RevsetExpression>)> { ) -> Result<Option<(Rc<RevsetExpression>, Rc<RevsetExpression>)>, RevsetError> {
match (transform_rec(expression1, f), transform_rec(expression2, f)) { match (
transform_rec(expression1, f)?,
transform_rec(expression2, f)?,
) {
(Some(new_expression1), Some(new_expression2)) => { (Some(new_expression1), Some(new_expression2)) => {
Some((new_expression1, new_expression2)) Ok(Some((new_expression1, new_expression2)))
} }
(Some(new_expression1), None) => Some((new_expression1, expression2.clone())), (Some(new_expression1), None) => Ok(Some((new_expression1, expression2.clone()))),
(None, Some(new_expression2)) => Some((expression1.clone(), new_expression2)), (None, Some(new_expression2)) => Ok(Some((expression1.clone(), new_expression2))),
(None, None) => None, (None, None) => Ok(None),
} }
} }
fn transform_rec( fn transform_rec(
expression: &Rc<RevsetExpression>, expression: &Rc<RevsetExpression>,
f: &mut impl FnMut(&Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>>, f: &mut impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
) -> Option<Rc<RevsetExpression>> { ) -> TransformResult {
if let Some(new_expression) = transform_child_rec(expression, f) { if let Some(new_expression) = transform_child_rec(expression, f)? {
// must propagate new expression tree // must propagate new expression tree
Some(f(&new_expression).unwrap_or(new_expression)) Ok(Some(f(&new_expression)?.unwrap_or(new_expression)))
} else { } else {
f(expression) f(expression)
} }