forked from mirrors/jj
templater: translate keywords to "self" methods by core template engine
This eliminates the separate keywords table. All keywords are resolved through the pseudo "self" property. Maybe we'll add "self" keyword/variable later.
This commit is contained in:
parent
6e5eff5423
commit
e80b906188
3 changed files with 37 additions and 45 deletions
|
@ -54,8 +54,9 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo, '_> {
|
|||
|
||||
template_builder::impl_core_wrap_property_fns!('repo, CommitTemplatePropertyKind::Core);
|
||||
|
||||
fn build_keyword(&self, name: &str, span: pest::Span) -> TemplateParseResult<Self::Property> {
|
||||
build_commit_keyword(self, name, span)
|
||||
fn build_self(&self) -> Self::Property {
|
||||
// Commit object is lightweight (a few Arc + CommitId)
|
||||
self.wrap_commit(TemplatePropertyFn(|commit: &Commit| commit.clone()))
|
||||
}
|
||||
|
||||
fn build_method(
|
||||
|
@ -236,21 +237,6 @@ impl CommitKeywordCache {
|
|||
}
|
||||
}
|
||||
|
||||
fn build_commit_keyword<'repo>(
|
||||
language: &CommitTemplateLanguage<'repo, '_>,
|
||||
name: &str,
|
||||
span: pest::Span,
|
||||
) -> TemplateParseResult<CommitTemplatePropertyKind<'repo>> {
|
||||
// Commit object is lightweight (a few Arc + CommitId), so just clone it
|
||||
// to turn into a property type. Abstraction over "for<'a> (&'a T) -> &'a T"
|
||||
// and "(&T) -> T" wouldn't be simple. If we want to remove Clone/Rc/Arc,
|
||||
// maybe we can add an abstraction that takes "Fn(&Commit) -> O" and returns
|
||||
// "TemplateProperty<Commit, Output = O>".
|
||||
let property = TemplatePropertyFn(|commit: &Commit| commit.clone());
|
||||
build_commit_keyword_opt(language, property, name)
|
||||
.ok_or_else(|| TemplateParseError::no_such_keyword(name, span))
|
||||
}
|
||||
|
||||
fn build_commit_method<'repo>(
|
||||
language: &CommitTemplateLanguage<'repo, '_>,
|
||||
_build_ctx: &BuildContext<CommitTemplatePropertyKind<'repo>>,
|
||||
|
@ -265,6 +251,7 @@ fn build_commit_method<'repo>(
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: merge into build_commit_method()
|
||||
fn build_commit_keyword_opt<'repo>(
|
||||
language: &CommitTemplateLanguage<'repo, '_>,
|
||||
property: impl TemplateProperty<Commit, Output = Commit> + 'repo,
|
||||
|
|
|
@ -42,8 +42,9 @@ impl TemplateLanguage<'static> for OperationTemplateLanguage<'_> {
|
|||
|
||||
template_builder::impl_core_wrap_property_fns!('static, OperationTemplatePropertyKind::Core);
|
||||
|
||||
fn build_keyword(&self, name: &str, span: pest::Span) -> TemplateParseResult<Self::Property> {
|
||||
build_operation_keyword(self, name, span)
|
||||
fn build_self(&self) -> Self::Property {
|
||||
// Operation object is lightweight (a few Arc + OperationId)
|
||||
self.wrap_operation(TemplatePropertyFn(|op: &Operation| op.clone()))
|
||||
}
|
||||
|
||||
fn build_method(
|
||||
|
@ -67,7 +68,6 @@ impl TemplateLanguage<'static> for OperationTemplateLanguage<'_> {
|
|||
}
|
||||
|
||||
impl OperationTemplateLanguage<'_> {
|
||||
#[allow(unused)] // TODO
|
||||
fn wrap_operation(
|
||||
&self,
|
||||
property: impl TemplateProperty<Operation, Output = Operation> + 'static,
|
||||
|
@ -124,18 +124,6 @@ impl IntoTemplateProperty<'static, Operation> for OperationTemplatePropertyKind
|
|||
}
|
||||
}
|
||||
|
||||
fn build_operation_keyword(
|
||||
language: &OperationTemplateLanguage,
|
||||
name: &str,
|
||||
span: pest::Span,
|
||||
) -> TemplateParseResult<OperationTemplatePropertyKind> {
|
||||
// Operation object is lightweight (a few Arc + OperationId), so just clone
|
||||
// it to turn into a property type.
|
||||
let property = TemplatePropertyFn(|op: &Operation| op.clone());
|
||||
build_operation_keyword_opt(language, property, name)
|
||||
.ok_or_else(|| TemplateParseError::no_such_keyword(name, span))
|
||||
}
|
||||
|
||||
fn build_operation_method(
|
||||
language: &OperationTemplateLanguage,
|
||||
_build_ctx: &BuildContext<OperationTemplatePropertyKind>,
|
||||
|
@ -150,6 +138,7 @@ fn build_operation_method(
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: merge into build_operation_method()
|
||||
fn build_operation_keyword_opt(
|
||||
language: &OperationTemplateLanguage,
|
||||
property: impl TemplateProperty<Operation, Output = Operation> + 'static,
|
||||
|
|
|
@ -68,7 +68,10 @@ pub trait TemplateLanguage<'a> {
|
|||
template: Box<dyn ListTemplate<Self::Context> + 'a>,
|
||||
) -> Self::Property;
|
||||
|
||||
fn build_keyword(&self, name: &str, span: pest::Span) -> TemplateParseResult<Self::Property>;
|
||||
/// Creates the `self` template property, which is usually a function that
|
||||
/// clones the `Context` object.
|
||||
fn build_self(&self) -> Self::Property;
|
||||
|
||||
fn build_method(
|
||||
&self,
|
||||
build_ctx: &BuildContext<Self::Property>,
|
||||
|
@ -272,6 +275,28 @@ pub struct BuildContext<'i, P> {
|
|||
local_variables: HashMap<&'i str, &'i (dyn Fn() -> P)>,
|
||||
}
|
||||
|
||||
fn build_keyword<'a, L: TemplateLanguage<'a>>(
|
||||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
name: &str,
|
||||
name_span: pest::Span<'_>,
|
||||
) -> TemplateParseResult<Expression<L::Property>> {
|
||||
// Keyword is a 0-ary method on the "self" property
|
||||
let self_property = language.build_self();
|
||||
let function = FunctionCallNode {
|
||||
name,
|
||||
name_span,
|
||||
args: vec![],
|
||||
args_span: name_span.end_pos().span(&name_span.end_pos()),
|
||||
};
|
||||
let property = language
|
||||
.build_method(build_ctx, self_property, &function)
|
||||
// Since keyword is a 0-ary method, any argument-related errors mean
|
||||
// there's no such keyword.
|
||||
.map_err(|_| TemplateParseError::no_such_keyword(name, name_span))?;
|
||||
Ok(Expression::with_label(property, name))
|
||||
}
|
||||
|
||||
fn build_unary_operation<'a, L: TemplateLanguage<'a>>(
|
||||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
|
@ -842,8 +867,7 @@ pub fn build_expression<'a, L: TemplateLanguage<'a>>(
|
|||
// Don't label a local variable with its name
|
||||
Ok(Expression::unlabeled(make()))
|
||||
} else {
|
||||
let property = language.build_keyword(name, node.span)?;
|
||||
Ok(Expression::with_label(property, *name))
|
||||
build_keyword(language, build_ctx, name, node.span)
|
||||
}
|
||||
}
|
||||
ExpressionKind::Boolean(value) => {
|
||||
|
@ -960,15 +984,8 @@ mod tests {
|
|||
|
||||
impl_core_wrap_property_fns!('static, TestTemplatePropertyKind::Core);
|
||||
|
||||
fn build_keyword(
|
||||
&self,
|
||||
name: &str,
|
||||
span: pest::Span,
|
||||
) -> TemplateParseResult<Self::Property> {
|
||||
self.keywords
|
||||
.get(name)
|
||||
.map(|f| f(self))
|
||||
.ok_or_else(|| TemplateParseError::no_such_keyword(name, span))
|
||||
fn build_self(&self) -> Self::Property {
|
||||
TestTemplatePropertyKind::Unit
|
||||
}
|
||||
|
||||
fn build_method(
|
||||
|
@ -995,7 +1012,6 @@ mod tests {
|
|||
|
||||
enum TestTemplatePropertyKind {
|
||||
Core(CoreTemplatePropertyKind<'static, ()>),
|
||||
#[allow(unused)] // TODO
|
||||
Unit,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue