Skip to content

Commit

Permalink
templater: translate keywords to "self" methods by core template engine
Browse files Browse the repository at this point in the history
This eliminates the separate keywords table. All keywords are resolved through
the pseudo "self" property. Maybe we'll add "self" keyword/variable later.
  • Loading branch information
yuja committed Feb 23, 2024
1 parent 6e5eff5 commit e80b906
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 45 deletions.
21 changes: 4 additions & 17 deletions cli/src/commit_templater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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>>,
Expand All @@ -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,
Expand Down
19 changes: 4 additions & 15 deletions cli/src/operation_templater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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,
Expand Down Expand Up @@ -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>,
Expand All @@ -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,
Expand Down
42 changes: 29 additions & 13 deletions cli/src/template_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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(
Expand All @@ -995,7 +1012,6 @@ mod tests {

enum TestTemplatePropertyKind {
Core(CoreTemplatePropertyKind<'static, ()>),
#[allow(unused)] // TODO
Unit,
}

Expand Down

0 comments on commit e80b906

Please sign in to comment.