diff --git a/lib/src/revset.rs b/lib/src/revset.rs index 652095f85..5a866dc4e 100644 --- a/lib/src/revset.rs +++ b/lib/src/revset.rs @@ -1105,27 +1105,37 @@ pub fn parse( /// `Some` for rewritten expression, or `None` to reuse the original expression. type TransformedExpression = Option>; +/// Walks `expression` tree and applies `f` recursively from leaf nodes. fn transform_expression_bottom_up( expression: &Rc, mut f: impl FnMut(&Rc) -> TransformedExpression, ) -> TransformedExpression { - try_transform_expression_bottom_up(expression, |expression| Ok(f(expression))).unwrap() + try_transform_expression(expression, |_| Ok(None), |expression| Ok(f(expression))).unwrap() } type TransformResult = Result; -/// Walks `expression` tree and applies `f` recursively from leaf nodes. +/// Walks `expression` tree and applies transformation recursively. /// -/// If `f` returns `None`, the original expression node is reused. If no nodes -/// rewritten, returns `None`. `std::iter::successors()` could be used if -/// the transformation needs to be applied repeatedly until converged. -fn try_transform_expression_bottom_up( +/// `pre` is the callback to rewrite subtree including children. It is +/// invoked before visiting the child nodes. If returned `Some`, children +/// won't be visited. +/// +/// `post` is the callback to rewrite from leaf nodes. If returned `None`, +/// the original expression node will be reused. +/// +/// If no nodes rewritten, this function returns `None`. +/// `std::iter::successors()` could be used if the transformation needs to be +/// applied repeatedly until converged. +fn try_transform_expression( expression: &Rc, - mut f: impl FnMut(&Rc) -> TransformResult, + mut pre: impl FnMut(&Rc) -> TransformResult, + mut post: impl FnMut(&Rc) -> TransformResult, ) -> TransformResult { fn transform_child_rec( expression: &Rc, - f: &mut impl FnMut(&Rc) -> TransformResult, + pre: &mut impl FnMut(&Rc) -> TransformResult, + post: &mut impl FnMut(&Rc) -> TransformResult, ) -> TransformResult { Ok(match expression.as_ref() { RevsetExpression::None => None, @@ -1133,50 +1143,50 @@ fn try_transform_expression_bottom_up( RevsetExpression::Commits(_) => None, RevsetExpression::Symbol(_) => None, RevsetExpression::Children(roots) => { - transform_rec(roots, f)?.map(RevsetExpression::Children) + transform_rec(roots, pre, post)?.map(RevsetExpression::Children) } - RevsetExpression::Ancestors { heads, generation } => { - transform_rec(heads, f)?.map(|heads| RevsetExpression::Ancestors { + RevsetExpression::Ancestors { heads, generation } => transform_rec(heads, pre, post)? + .map(|heads| RevsetExpression::Ancestors { heads, generation: generation.clone(), - }) - } + }), RevsetExpression::Range { roots, heads, generation, - } => transform_rec_pair((roots, heads), f)?.map(|(roots, heads)| { + } => transform_rec_pair((roots, heads), pre, post)?.map(|(roots, heads)| { RevsetExpression::Range { roots, heads, generation: generation.clone(), } }), - RevsetExpression::DagRange { roots, heads } => transform_rec_pair((roots, heads), f)? - .map(|(roots, heads)| RevsetExpression::DagRange { roots, heads }), + RevsetExpression::DagRange { roots, heads } => { + transform_rec_pair((roots, heads), pre, post)? + .map(|(roots, heads)| RevsetExpression::DagRange { roots, heads }) + } RevsetExpression::VisibleHeads => None, RevsetExpression::Heads(candidates) => { - transform_rec(candidates, f)?.map(RevsetExpression::Heads) + transform_rec(candidates, pre, post)?.map(RevsetExpression::Heads) } RevsetExpression::Roots(candidates) => { - transform_rec(candidates, f)?.map(RevsetExpression::Roots) + transform_rec(candidates, pre, post)?.map(RevsetExpression::Roots) } RevsetExpression::Branches(_) => None, RevsetExpression::RemoteBranches { .. } => None, RevsetExpression::Tags => None, RevsetExpression::GitRefs => None, RevsetExpression::GitHead => None, - RevsetExpression::Latest { candidates, count } => { - transform_rec(candidates, f)?.map(|candidates| RevsetExpression::Latest { + RevsetExpression::Latest { candidates, count } => transform_rec(candidates, pre, post)? + .map(|candidates| RevsetExpression::Latest { candidates, count: *count, - }) - } + }), RevsetExpression::Filter(_) => None, RevsetExpression::AsFilter(candidates) => { - transform_rec(candidates, f)?.map(RevsetExpression::AsFilter) + transform_rec(candidates, pre, post)?.map(RevsetExpression::AsFilter) } - RevsetExpression::Present(candidates) => match transform_rec(candidates, f) { + RevsetExpression::Present(candidates) => match transform_rec(candidates, pre, post) { Ok(None) => None, Ok(Some(expression)) => Some(RevsetExpression::Present(expression)), Err(RevsetResolutionError::NoSuchRevision(_)) => Some(RevsetExpression::None), @@ -1188,22 +1198,22 @@ fn try_transform_expression_bottom_up( } }, RevsetExpression::NotIn(complement) => { - transform_rec(complement, f)?.map(RevsetExpression::NotIn) + transform_rec(complement, pre, post)?.map(RevsetExpression::NotIn) } RevsetExpression::Union(expression1, expression2) => { - transform_rec_pair((expression1, expression2), f)?.map( + transform_rec_pair((expression1, expression2), pre, post)?.map( |(expression1, expression2)| RevsetExpression::Union(expression1, expression2), ) } RevsetExpression::Intersection(expression1, expression2) => { - transform_rec_pair((expression1, expression2), f)?.map( + transform_rec_pair((expression1, expression2), pre, post)?.map( |(expression1, expression2)| { RevsetExpression::Intersection(expression1, expression2) }, ) } RevsetExpression::Difference(expression1, expression2) => { - transform_rec_pair((expression1, expression2), f)?.map( + transform_rec_pair((expression1, expression2), pre, post)?.map( |(expression1, expression2)| { RevsetExpression::Difference(expression1, expression2) }, @@ -1216,11 +1226,12 @@ fn try_transform_expression_bottom_up( #[allow(clippy::type_complexity)] fn transform_rec_pair( (expression1, expression2): (&Rc, &Rc), - f: &mut impl FnMut(&Rc) -> TransformResult, + pre: &mut impl FnMut(&Rc) -> TransformResult, + post: &mut impl FnMut(&Rc) -> TransformResult, ) -> Result, Rc)>, RevsetResolutionError> { match ( - transform_rec(expression1, f)?, - transform_rec(expression2, f)?, + transform_rec(expression1, pre, post)?, + transform_rec(expression2, pre, post)?, ) { (Some(new_expression1), Some(new_expression2)) => { Ok(Some((new_expression1, new_expression2))) @@ -1233,17 +1244,21 @@ fn try_transform_expression_bottom_up( fn transform_rec( expression: &Rc, - f: &mut impl FnMut(&Rc) -> TransformResult, + pre: &mut impl FnMut(&Rc) -> TransformResult, + post: &mut impl FnMut(&Rc) -> TransformResult, ) -> TransformResult { - if let Some(new_expression) = transform_child_rec(expression, f)? { + if let Some(new_expression) = pre(expression)? { + return Ok(Some(new_expression)); + } + if let Some(new_expression) = transform_child_rec(expression, pre, post)? { // must propagate new expression tree - Ok(Some(f(&new_expression)?.unwrap_or(new_expression))) + Ok(Some(post(&new_expression)?.unwrap_or(new_expression))) } else { - f(expression) + post(expression) } } - transform_rec(expression, &mut f) + transform_rec(expression, &mut pre, &mut post) } /// Transforms filter expressions, by applying the following rules. @@ -1607,8 +1622,10 @@ pub fn resolve_symbols( expression: Rc, workspace_ctx: Option<&RevsetWorkspaceContext>, ) -> Result, RevsetResolutionError> { - Ok( - try_transform_expression_bottom_up(&expression, |expression| { + Ok(try_transform_expression( + &expression, + |_| Ok(None), + |expression| { Ok(match expression.as_ref() { RevsetExpression::Symbol(symbol) => { let commit_ids = @@ -1667,9 +1684,9 @@ pub fn resolve_symbols( } _ => None, }) - })? - .unwrap_or(expression), - ) + }, + )? + .unwrap_or(expression)) } pub trait Revset<'index>: fmt::Debug {