mirror of
https://github.com/martinvonz/jj.git
synced 2024-11-28 17:41:14 +00:00
revset: insert pre-order callback that can terminate transformation early
This will be a hook for resolve_symbols() to transform Present(_) subtree.
This commit is contained in:
parent
feaad6b5fa
commit
aeb93c7591
1 changed files with 58 additions and 41 deletions
|
@ -1105,27 +1105,37 @@ pub fn parse(
|
|||
/// `Some` for rewritten expression, or `None` to reuse the original expression.
|
||||
type TransformedExpression = Option<Rc<RevsetExpression>>;
|
||||
|
||||
/// Walks `expression` tree and applies `f` recursively from leaf nodes.
|
||||
fn transform_expression_bottom_up(
|
||||
expression: &Rc<RevsetExpression>,
|
||||
mut f: impl FnMut(&Rc<RevsetExpression>) -> 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<TransformedExpression, RevsetResolutionError>;
|
||||
|
||||
/// 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<RevsetExpression>,
|
||||
mut f: impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
|
||||
mut pre: impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
|
||||
mut post: impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
|
||||
) -> TransformResult {
|
||||
fn transform_child_rec(
|
||||
expression: &Rc<RevsetExpression>,
|
||||
f: &mut impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
|
||||
pre: &mut impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
|
||||
post: &mut impl FnMut(&Rc<RevsetExpression>) -> 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<RevsetExpression>, &Rc<RevsetExpression>),
|
||||
f: &mut impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
|
||||
pre: &mut impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
|
||||
post: &mut impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
|
||||
) -> Result<Option<(Rc<RevsetExpression>, Rc<RevsetExpression>)>, 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<RevsetExpression>,
|
||||
f: &mut impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
|
||||
pre: &mut impl FnMut(&Rc<RevsetExpression>) -> TransformResult,
|
||||
post: &mut impl FnMut(&Rc<RevsetExpression>) -> 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<RevsetExpression>,
|
||||
workspace_ctx: Option<&RevsetWorkspaceContext>,
|
||||
) -> Result<Rc<RevsetExpression>, 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 {
|
||||
|
|
Loading…
Reference in a new issue