mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-20 03:20:08 +00:00
templater: add support for keyword arguments
This commit is contained in:
parent
2413fffcf9
commit
6e06a79cfd
2 changed files with 30 additions and 25 deletions
|
@ -46,8 +46,10 @@ prefix_ops = _{ logical_not_op | negate_op }
|
|||
infix_ops = _{ logical_or_op | logical_and_op }
|
||||
|
||||
function = { identifier ~ "(" ~ whitespace* ~ function_arguments ~ whitespace* ~ ")" }
|
||||
keyword_argument = { identifier ~ whitespace* ~ "=" ~ whitespace* ~ template }
|
||||
argument = _{ keyword_argument | template }
|
||||
function_arguments = {
|
||||
template ~ (whitespace* ~ "," ~ whitespace* ~ template)* ~ (whitespace* ~ ",")?
|
||||
argument ~ (whitespace* ~ "," ~ whitespace* ~ argument)* ~ (whitespace* ~ ",")?
|
||||
| ""
|
||||
}
|
||||
lambda = {
|
||||
|
|
|
@ -29,6 +29,7 @@ use jj_lib::dsl_util::AliasesMap;
|
|||
use jj_lib::dsl_util::Diagnostics;
|
||||
use jj_lib::dsl_util::ExpressionFolder;
|
||||
use jj_lib::dsl_util::FoldableExpression;
|
||||
use jj_lib::dsl_util::FunctionCallParser;
|
||||
use jj_lib::dsl_util::InvalidArguments;
|
||||
use jj_lib::dsl_util::StringLiteralParser;
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -49,6 +50,13 @@ const STRING_LITERAL_PARSER: StringLiteralParser<Rule> = StringLiteralParser {
|
|||
content_rule: Rule::string_content,
|
||||
escape_rule: Rule::string_escape,
|
||||
};
|
||||
const FUNCTION_CALL_PARSER: FunctionCallParser<Rule> = FunctionCallParser {
|
||||
function_name_rule: Rule::identifier,
|
||||
function_arguments_rule: Rule::function_arguments,
|
||||
keyword_argument_rule: Rule::keyword_argument,
|
||||
argument_name_rule: Rule::identifier,
|
||||
argument_value_rule: Rule::template,
|
||||
};
|
||||
|
||||
impl Rule {
|
||||
fn to_symbol(self) -> Option<&'static str> {
|
||||
|
@ -71,6 +79,8 @@ impl Rule {
|
|||
Rule::prefix_ops => None,
|
||||
Rule::infix_ops => None,
|
||||
Rule::function => None,
|
||||
Rule::keyword_argument => None,
|
||||
Rule::argument => None,
|
||||
Rule::function_arguments => None,
|
||||
Rule::lambda => None,
|
||||
Rule::formal_parameters => None,
|
||||
|
@ -417,28 +427,6 @@ fn parse_formal_parameters(params_pair: Pair<Rule>) -> TemplateParseResult<Vec<&
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_function_call_node(pair: Pair<Rule>) -> TemplateParseResult<FunctionCallNode> {
|
||||
assert_eq!(pair.as_rule(), Rule::function);
|
||||
let mut inner = pair.into_inner();
|
||||
let name_pair = inner.next().unwrap();
|
||||
let name_span = name_pair.as_span();
|
||||
let args_pair = inner.next().unwrap();
|
||||
let args_span = args_pair.as_span();
|
||||
assert_eq!(args_pair.as_rule(), Rule::function_arguments);
|
||||
let name = parse_identifier_name(name_pair)?;
|
||||
let args = args_pair
|
||||
.into_inner()
|
||||
.map(parse_template_node)
|
||||
.try_collect()?;
|
||||
Ok(FunctionCallNode {
|
||||
name,
|
||||
name_span,
|
||||
args,
|
||||
keyword_args: vec![], // unsupported
|
||||
args_span,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_lambda_node(pair: Pair<Rule>) -> TemplateParseResult<LambdaNode> {
|
||||
assert_eq!(pair.as_rule(), Rule::lambda);
|
||||
let mut inner = pair.into_inner();
|
||||
|
@ -478,7 +466,11 @@ fn parse_term_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
|
|||
}
|
||||
Rule::identifier => ExpressionNode::new(parse_identifier_or_literal(expr), span),
|
||||
Rule::function => {
|
||||
let function = Box::new(parse_function_call_node(expr)?);
|
||||
let function = Box::new(FUNCTION_CALL_PARSER.parse(
|
||||
expr,
|
||||
parse_identifier_name,
|
||||
parse_template_node,
|
||||
)?);
|
||||
ExpressionNode::new(ExpressionKind::FunctionCall(function), span)
|
||||
}
|
||||
Rule::lambda => {
|
||||
|
@ -493,7 +485,11 @@ fn parse_term_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
|
|||
let span = object.span.start_pos().span(&chain.as_span().end_pos());
|
||||
let method = Box::new(MethodCallNode {
|
||||
object,
|
||||
function: parse_function_call_node(chain)?,
|
||||
function: FUNCTION_CALL_PARSER.parse(
|
||||
chain,
|
||||
parse_identifier_name,
|
||||
parse_template_node,
|
||||
)?,
|
||||
});
|
||||
Ok(ExpressionNode::new(
|
||||
ExpressionKind::MethodCall(method),
|
||||
|
@ -896,8 +892,15 @@ mod tests {
|
|||
assert!(parse_template(r#" label("","",) "#).is_ok());
|
||||
assert!(parse_template(r#" label("",,"") "#).is_err());
|
||||
|
||||
// Keyword arguments
|
||||
assert!(parse_template("f(foo = bar)").is_ok());
|
||||
assert!(parse_template("f( foo=bar )").is_ok());
|
||||
assert!(parse_template("x.f(foo, bar=0, baz=1)").is_ok());
|
||||
|
||||
// Boolean literal cannot be used as a function name
|
||||
assert!(parse_template("false()").is_err());
|
||||
// Boolean literal cannot be used as a parameter name
|
||||
assert!(parse_template("f(false=0)").is_err());
|
||||
// Function arguments can be any expression
|
||||
assert!(parse_template("f(false)").is_ok());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue