jj_cli/
generic_templater.rsuse std::collections::HashMap;
use crate::template_builder;
use crate::template_builder::BuildContext;
use crate::template_builder::CoreTemplateBuildFnTable;
use crate::template_builder::CoreTemplatePropertyKind;
use crate::template_builder::IntoTemplateProperty;
use crate::template_builder::TemplateLanguage;
use crate::template_parser;
use crate::template_parser::FunctionCallNode;
use crate::template_parser::TemplateDiagnostics;
use crate::template_parser::TemplateParseResult;
use crate::templater::Template;
use crate::templater::TemplateProperty;
pub struct GenericTemplateLanguage<'a, C> {
build_fn_table: GenericTemplateBuildFnTable<'a, C>,
}
impl<'a, C> GenericTemplateLanguage<'a, C> {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self::with_keywords(HashMap::new())
}
pub fn with_keywords(keywords: GenericTemplateBuildKeywordFnMap<'a, C>) -> Self {
GenericTemplateLanguage {
build_fn_table: GenericTemplateBuildFnTable {
core: CoreTemplateBuildFnTable::builtin(),
keywords,
},
}
}
pub fn add_keyword<F>(&mut self, name: &'static str, build: F)
where
F: Fn(
Box<dyn TemplateProperty<Output = C> + 'a>,
) -> TemplateParseResult<GenericTemplatePropertyKind<'a, C>>
+ 'a,
{
self.build_fn_table.keywords.insert(name, Box::new(build));
}
}
impl<'a, C: 'a> TemplateLanguage<'a> for GenericTemplateLanguage<'a, C> {
type Property = GenericTemplatePropertyKind<'a, C>;
template_builder::impl_core_wrap_property_fns!('a, GenericTemplatePropertyKind::Core);
fn build_function(
&self,
diagnostics: &mut TemplateDiagnostics,
build_ctx: &BuildContext<Self::Property>,
function: &FunctionCallNode,
) -> TemplateParseResult<Self::Property> {
let table = &self.build_fn_table.core;
table.build_function(self, diagnostics, build_ctx, function)
}
fn build_method(
&self,
diagnostics: &mut TemplateDiagnostics,
build_ctx: &BuildContext<Self::Property>,
property: Self::Property,
function: &FunctionCallNode,
) -> TemplateParseResult<Self::Property> {
let type_name = property.type_name();
match property {
GenericTemplatePropertyKind::Core(property) => {
let table = &self.build_fn_table.core;
table.build_method(self, diagnostics, build_ctx, property, function)
}
GenericTemplatePropertyKind::Self_(property) => {
let table = &self.build_fn_table.keywords;
let build = template_parser::lookup_method(type_name, table, function)?;
function.expect_no_arguments()?;
build(property)
}
}
}
}
impl<'a, C> GenericTemplateLanguage<'a, C> {
pub fn wrap_self(
property: impl TemplateProperty<Output = C> + 'a,
) -> GenericTemplatePropertyKind<'a, C> {
GenericTemplatePropertyKind::Self_(Box::new(property))
}
}
pub enum GenericTemplatePropertyKind<'a, C> {
Core(CoreTemplatePropertyKind<'a>),
Self_(Box<dyn TemplateProperty<Output = C> + 'a>),
}
impl<'a, C: 'a> IntoTemplateProperty<'a> for GenericTemplatePropertyKind<'a, C> {
fn type_name(&self) -> &'static str {
match self {
GenericTemplatePropertyKind::Core(property) => property.type_name(),
GenericTemplatePropertyKind::Self_(_) => "Self",
}
}
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<Output = bool> + 'a>> {
match self {
GenericTemplatePropertyKind::Core(property) => property.try_into_boolean(),
GenericTemplatePropertyKind::Self_(_) => None,
}
}
fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<Output = i64> + 'a>> {
match self {
GenericTemplatePropertyKind::Core(property) => property.try_into_integer(),
GenericTemplatePropertyKind::Self_(_) => None,
}
}
fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<Output = String> + 'a>> {
match self {
GenericTemplatePropertyKind::Core(property) => property.try_into_plain_text(),
GenericTemplatePropertyKind::Self_(_) => None,
}
}
fn try_into_template(self) -> Option<Box<dyn Template + 'a>> {
match self {
GenericTemplatePropertyKind::Core(property) => property.try_into_template(),
GenericTemplatePropertyKind::Self_(_) => None,
}
}
}
pub type GenericTemplateBuildKeywordFn<'a, C> = Box<
dyn Fn(
Box<dyn TemplateProperty<Output = C> + 'a>,
) -> TemplateParseResult<GenericTemplatePropertyKind<'a, C>>
+ 'a,
>;
pub type GenericTemplateBuildKeywordFnMap<'a, C> =
HashMap<&'static str, GenericTemplateBuildKeywordFn<'a, C>>;
struct GenericTemplateBuildFnTable<'a, C: 'a> {
core: CoreTemplateBuildFnTable<'a, GenericTemplateLanguage<'a, C>>,
keywords: GenericTemplateBuildKeywordFnMap<'a, C>,
}