mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-25 05:29:39 +00:00
revset: rewrite match table of builtin functions as HashMap
So that we can build a list of function names.
This commit is contained in:
parent
9ed537b3e8
commit
d3d8afc77b
1 changed files with 173 additions and 172 deletions
|
@ -711,187 +711,188 @@ fn parse_function_expression(
|
|||
state.with_alias_expanding(id, &locals, primary_span, |state| {
|
||||
parse_program(defn, state)
|
||||
})
|
||||
} else if let Some(func) = BUILTIN_FUNCTION_MAP.get(name) {
|
||||
func(name, arguments_pair, state)
|
||||
} else {
|
||||
parse_builtin_function(name_pair, arguments_pair, state)
|
||||
Err(RevsetParseError::with_span(
|
||||
RevsetParseErrorKind::NoSuchFunction(name.to_owned()),
|
||||
name_pair.as_span(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_builtin_function(
|
||||
name_pair: Pair<Rule>,
|
||||
arguments_pair: Pair<Rule>,
|
||||
state: ParseState,
|
||||
) -> Result<Rc<RevsetExpression>, RevsetParseError> {
|
||||
let name = name_pair.as_str();
|
||||
match name {
|
||||
"parents" => {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let expression = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(expression.parents())
|
||||
}
|
||||
"children" => {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let expression = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(expression.children())
|
||||
}
|
||||
"ancestors" => {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let expression = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(expression.ancestors())
|
||||
}
|
||||
"descendants" => {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let expression = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(expression.descendants())
|
||||
}
|
||||
"connected" => {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
type RevsetFunction =
|
||||
fn(&str, Pair<Rule>, ParseState) -> Result<Rc<RevsetExpression>, RevsetParseError>;
|
||||
|
||||
static BUILTIN_FUNCTION_MAP: Lazy<HashMap<&'static str, RevsetFunction>> = Lazy::new(|| {
|
||||
// Not using maplit::hashmap!{} or custom declarative macro here because
|
||||
// code completion inside macro is quite restricted.
|
||||
let mut map: HashMap<&'static str, RevsetFunction> = HashMap::new();
|
||||
map.insert("parents", |name, arguments_pair, state| {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let expression = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(expression.parents())
|
||||
});
|
||||
map.insert("children", |name, arguments_pair, state| {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let expression = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(expression.children())
|
||||
});
|
||||
map.insert("ancestors", |name, arguments_pair, state| {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let expression = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(expression.ancestors())
|
||||
});
|
||||
map.insert("descendants", |name, arguments_pair, state| {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let expression = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(expression.descendants())
|
||||
});
|
||||
map.insert("connected", |name, arguments_pair, state| {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let candidates = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(candidates.connected())
|
||||
});
|
||||
map.insert("none", |name, arguments_pair, _state| {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::none())
|
||||
});
|
||||
map.insert("all", |name, arguments_pair, _state| {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::all())
|
||||
});
|
||||
map.insert("heads", |name, arguments_pair, state| {
|
||||
let ([], [opt_arg]) = expect_arguments(name, arguments_pair)?;
|
||||
if let Some(arg) = opt_arg {
|
||||
let candidates = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(candidates.connected())
|
||||
Ok(candidates.heads())
|
||||
} else {
|
||||
Ok(RevsetExpression::visible_heads())
|
||||
}
|
||||
"none" => {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::none())
|
||||
}
|
||||
"all" => {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::all())
|
||||
}
|
||||
"heads" => {
|
||||
let ([], [opt_arg]) = expect_arguments(name, arguments_pair)?;
|
||||
if let Some(arg) = opt_arg {
|
||||
let candidates = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(candidates.heads())
|
||||
} else {
|
||||
Ok(RevsetExpression::visible_heads())
|
||||
}
|
||||
}
|
||||
"roots" => {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let candidates = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(candidates.roots())
|
||||
}
|
||||
"public_heads" => {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::public_heads())
|
||||
}
|
||||
"branches" => {
|
||||
let ([], [opt_arg]) = expect_arguments(name, arguments_pair)?;
|
||||
let needle = if let Some(arg) = opt_arg {
|
||||
parse_function_argument_to_string(name, arg, state)?
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
Ok(RevsetExpression::branches(needle))
|
||||
}
|
||||
"remote_branches" => {
|
||||
let ([], [branch_opt_arg, remote_opt_arg]) =
|
||||
expect_named_arguments(name, &["", "remote"], arguments_pair)?;
|
||||
let branch_needle = if let Some(branch_arg) = branch_opt_arg {
|
||||
parse_function_argument_to_string(name, branch_arg, state)?
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
let remote_needle = if let Some(remote_arg) = remote_opt_arg {
|
||||
parse_function_argument_to_string(name, remote_arg, state)?
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
Ok(RevsetExpression::remote_branches(
|
||||
branch_needle,
|
||||
remote_needle,
|
||||
))
|
||||
}
|
||||
"tags" => {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::tags())
|
||||
}
|
||||
"git_refs" => {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::git_refs())
|
||||
}
|
||||
"git_head" => {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::git_head())
|
||||
}
|
||||
"merges" => {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::filter(
|
||||
RevsetFilterPredicate::ParentCount(2..u32::MAX),
|
||||
))
|
||||
}
|
||||
"description" => {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let needle = parse_function_argument_to_string(name, arg, state)?;
|
||||
Ok(RevsetExpression::filter(
|
||||
RevsetFilterPredicate::Description(needle),
|
||||
))
|
||||
}
|
||||
"author" => {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let needle = parse_function_argument_to_string(name, arg, state)?;
|
||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::Author(
|
||||
needle,
|
||||
)))
|
||||
}
|
||||
"committer" => {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let needle = parse_function_argument_to_string(name, arg, state)?;
|
||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::Committer(
|
||||
needle,
|
||||
)))
|
||||
}
|
||||
"empty" => {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::File(None)).negated())
|
||||
}
|
||||
"file" => {
|
||||
if let Some(ctx) = state.workspace_ctx {
|
||||
let arguments_span = arguments_pair.as_span();
|
||||
let paths: Vec<_> = arguments_pair
|
||||
.into_inner()
|
||||
.map(|arg| -> Result<_, RevsetParseError> {
|
||||
let span = arg.as_span();
|
||||
let needle = parse_function_argument_to_string(name, arg, state)?;
|
||||
let path = RepoPath::parse_fs_path(ctx.cwd, ctx.workspace_root, &needle)
|
||||
.map_err(|e| {
|
||||
RevsetParseError::with_span(
|
||||
RevsetParseErrorKind::FsPathParseError(e),
|
||||
span,
|
||||
)
|
||||
})?;
|
||||
Ok(path)
|
||||
})
|
||||
.try_collect()?;
|
||||
if paths.is_empty() {
|
||||
Err(RevsetParseError::with_span(
|
||||
RevsetParseErrorKind::InvalidFunctionArguments {
|
||||
name: name.to_owned(),
|
||||
message: "Expected at least 1 argument".to_string(),
|
||||
},
|
||||
arguments_span,
|
||||
))
|
||||
} else {
|
||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::File(Some(
|
||||
paths,
|
||||
))))
|
||||
}
|
||||
} else {
|
||||
Err(RevsetParseError::new(
|
||||
RevsetParseErrorKind::FsPathWithoutWorkspace,
|
||||
});
|
||||
map.insert("roots", |name, arguments_pair, state| {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let candidates = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(candidates.roots())
|
||||
});
|
||||
map.insert("public_heads", |name, arguments_pair, _state| {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::public_heads())
|
||||
});
|
||||
map.insert("branches", |name, arguments_pair, state| {
|
||||
let ([], [opt_arg]) = expect_arguments(name, arguments_pair)?;
|
||||
let needle = if let Some(arg) = opt_arg {
|
||||
parse_function_argument_to_string(name, arg, state)?
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
Ok(RevsetExpression::branches(needle))
|
||||
});
|
||||
map.insert("remote_branches", |name, arguments_pair, state| {
|
||||
let ([], [branch_opt_arg, remote_opt_arg]) =
|
||||
expect_named_arguments(name, &["", "remote"], arguments_pair)?;
|
||||
let branch_needle = if let Some(branch_arg) = branch_opt_arg {
|
||||
parse_function_argument_to_string(name, branch_arg, state)?
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
let remote_needle = if let Some(remote_arg) = remote_opt_arg {
|
||||
parse_function_argument_to_string(name, remote_arg, state)?
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
Ok(RevsetExpression::remote_branches(
|
||||
branch_needle,
|
||||
remote_needle,
|
||||
))
|
||||
});
|
||||
map.insert("tags", |name, arguments_pair, _state| {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::tags())
|
||||
});
|
||||
map.insert("git_refs", |name, arguments_pair, _state| {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::git_refs())
|
||||
});
|
||||
map.insert("git_head", |name, arguments_pair, _state| {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::git_head())
|
||||
});
|
||||
map.insert("merges", |name, arguments_pair, _state| {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::filter(
|
||||
RevsetFilterPredicate::ParentCount(2..u32::MAX),
|
||||
))
|
||||
});
|
||||
map.insert("description", |name, arguments_pair, state| {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let needle = parse_function_argument_to_string(name, arg, state)?;
|
||||
Ok(RevsetExpression::filter(
|
||||
RevsetFilterPredicate::Description(needle),
|
||||
))
|
||||
});
|
||||
map.insert("author", |name, arguments_pair, state| {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let needle = parse_function_argument_to_string(name, arg, state)?;
|
||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::Author(
|
||||
needle,
|
||||
)))
|
||||
});
|
||||
map.insert("committer", |name, arguments_pair, state| {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let needle = parse_function_argument_to_string(name, arg, state)?;
|
||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::Committer(
|
||||
needle,
|
||||
)))
|
||||
});
|
||||
map.insert("empty", |name, arguments_pair, _state| {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::File(None)).negated())
|
||||
});
|
||||
map.insert("file", |name, arguments_pair, state| {
|
||||
if let Some(ctx) = state.workspace_ctx {
|
||||
let arguments_span = arguments_pair.as_span();
|
||||
let paths: Vec<_> = arguments_pair
|
||||
.into_inner()
|
||||
.map(|arg| -> Result<_, RevsetParseError> {
|
||||
let span = arg.as_span();
|
||||
let needle = parse_function_argument_to_string(name, arg, state)?;
|
||||
let path = RepoPath::parse_fs_path(ctx.cwd, ctx.workspace_root, &needle)
|
||||
.map_err(|e| {
|
||||
RevsetParseError::with_span(
|
||||
RevsetParseErrorKind::FsPathParseError(e),
|
||||
span,
|
||||
)
|
||||
})?;
|
||||
Ok(path)
|
||||
})
|
||||
.try_collect()?;
|
||||
if paths.is_empty() {
|
||||
Err(RevsetParseError::with_span(
|
||||
RevsetParseErrorKind::InvalidFunctionArguments {
|
||||
name: name.to_owned(),
|
||||
message: "Expected at least 1 argument".to_string(),
|
||||
},
|
||||
arguments_span,
|
||||
))
|
||||
} else {
|
||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::File(Some(
|
||||
paths,
|
||||
))))
|
||||
}
|
||||
} else {
|
||||
Err(RevsetParseError::new(
|
||||
RevsetParseErrorKind::FsPathWithoutWorkspace,
|
||||
))
|
||||
}
|
||||
"present" => {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let expression = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(Rc::new(RevsetExpression::Present(expression)))
|
||||
}
|
||||
_ => Err(RevsetParseError::with_span(
|
||||
RevsetParseErrorKind::NoSuchFunction(name.to_owned()),
|
||||
name_pair.as_span(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
});
|
||||
map.insert("present", |name, arguments_pair, state| {
|
||||
let arg = expect_one_argument(name, arguments_pair)?;
|
||||
let expression = parse_expression_rule(arg.into_inner(), state)?;
|
||||
Ok(Rc::new(RevsetExpression::Present(expression)))
|
||||
});
|
||||
map
|
||||
});
|
||||
|
||||
type OptionalArg<'i> = Option<Pair<'i, Rule>>;
|
||||
|
||||
|
|
Loading…
Reference in a new issue