fluent_static_codegen/
function.rs

1use std::collections::HashMap;
2
3use fluent_static_function::FluentFunctionDescriptor;
4use proc_macro2::TokenStream;
5use quote::{format_ident, quote};
6use syn::{parse_str, Ident, Path, PathArguments};
7
8pub trait FunctionCallGenerator {
9    fn generate(
10        &self,
11        function_name: &str,
12        positional_args: &Ident,
13        named_args: &Ident,
14    ) -> Option<TokenStream>;
15}
16
17pub struct FunctionRegistry {
18    fns: HashMap<String, TokenStream>,
19}
20
21impl FunctionRegistry {
22    pub fn register(
23        &mut self,
24        function_id: &str,
25        function_descriptor: impl FluentFunctionDescriptor,
26    ) -> &Self {
27        self.fns
28            .insert(function_id.to_string(), Self::fqn(function_descriptor));
29        self
30    }
31
32    fn fqn(function_descriptor: impl FluentFunctionDescriptor) -> TokenStream {
33        let path = function_descriptor.type_name();
34
35        // HACK fluent_static reexports fluent_static_function,
36        // need to patch function name
37        // to avoid fluent_static_function dependency
38        let path = if path.starts_with("fluent_static_function::builtins") {
39            path.replace("fluent_static_function", "fluent_static::function")
40        } else {
41            path.to_string()
42        };
43
44        let mut path: Path = parse_str(&path).expect("vaild function type name");
45        if let Some(name) = path.segments.last_mut() {
46            name.arguments = PathArguments::None
47        }
48
49        quote! { #path }
50    }
51}
52
53impl Default for FunctionRegistry {
54    fn default() -> Self {
55        let fns = HashMap::new();
56        let mut result = Self { fns };
57
58        result.register("NUMBER", fluent_static_function::builtins::number);
59
60        result
61    }
62}
63
64impl FunctionCallGenerator for FunctionRegistry {
65    fn generate(
66        &self,
67        function_name: &str,
68        positional_args: &Ident,
69        named_args: &Ident,
70    ) -> Option<TokenStream> {
71        if let Some(fn_ident) = self.fns.get(function_name) {
72            Some(quote! {
73                #fn_ident(&#positional_args, &#named_args)
74            })
75        } else {
76            None
77        }
78    }
79}