Skip to main content

codama_plugin_core/
resolve_directives_visitor.rs

1use crate::DirectiveResolver;
2use codama_attributes::{Attribute, CodamaDirective, Resolvable, SeedDirectiveType};
3use codama_errors::CodamaResult;
4use codama_korok_visitors::KorokVisitor;
5use codama_koroks::*;
6use codama_nodes::{InstructionInputValueNode, ValueNode};
7
8/// A visitor that resolves all `Resolvable::Unresolved` entries in the korok tree
9/// by delegating to the `DirectiveResolver`.
10///
11/// This visitor runs automatically as the first step in `resolve_plugins()`,
12/// before any lifecycle hooks fire.
13pub struct ResolveDirectivesVisitor<'a> {
14    resolver: &'a dyn DirectiveResolver,
15}
16
17impl<'a> ResolveDirectivesVisitor<'a> {
18    pub fn new(resolver: &'a dyn DirectiveResolver) -> Self {
19        Self { resolver }
20    }
21
22    fn resolve_attributes(
23        &self,
24        attributes: &mut codama_attributes::Attributes,
25    ) -> CodamaResult<()> {
26        for attr in attributes.iter_mut() {
27            let Attribute::Codama(codama_attr) = attr else {
28                continue;
29            };
30            self.resolve_directive(codama_attr.directive.as_mut())?;
31        }
32        Ok(())
33    }
34
35    fn resolve_directive(&self, directive: &mut CodamaDirective) -> CodamaResult<()> {
36        match directive {
37            CodamaDirective::Type(d) => {
38                self.resolve_type(&mut d.node)?;
39            }
40            CodamaDirective::DefaultValue(d) => {
41                self.resolve_instruction_input_value(&mut d.node)?;
42            }
43            CodamaDirective::Account(d) => {
44                if let Some(ref mut dv) = d.default_value {
45                    self.resolve_instruction_input_value(dv)?;
46                }
47            }
48            CodamaDirective::Field(d) => {
49                self.resolve_type_node(&mut d.r#type)?;
50                if let Some(ref mut dv) = d.default_value {
51                    self.resolve_value_node(dv)?;
52                }
53            }
54            CodamaDirective::Argument(d) => {
55                self.resolve_type_node(&mut d.r#type)?;
56                if let Some(ref mut dv) = d.default_value {
57                    self.resolve_instruction_input_value(dv)?;
58                }
59            }
60            CodamaDirective::Seed(d) => match &mut d.seed {
61                SeedDirectiveType::Variable { r#type, .. } => {
62                    self.resolve_type_node(r#type)?;
63                }
64                SeedDirectiveType::Constant { r#type, value } => {
65                    self.resolve_type_node(r#type)?;
66                    self.resolve_value_node(value)?;
67                }
68                SeedDirectiveType::Linked(_) => {}
69            },
70            // Other directives don't contain resolvable slots.
71            _ => {}
72        }
73        Ok(())
74    }
75
76    fn resolve_type(
77        &self,
78        resolvable: &mut Resolvable<codama_nodes::RegisteredTypeNode>,
79    ) -> CodamaResult<()> {
80        if let Resolvable::Unresolved(directive) = resolvable {
81            let resolved = self.resolver.resolve_type_directive(directive)?;
82            *resolvable = Resolvable::Resolved(resolved);
83        }
84        Ok(())
85    }
86
87    fn resolve_type_node(
88        &self,
89        resolvable: &mut Resolvable<codama_nodes::TypeNode>,
90    ) -> CodamaResult<()> {
91        if let Resolvable::Unresolved(directive) = resolvable {
92            let registered = self.resolver.resolve_type_directive(directive)?;
93            let type_node = codama_nodes::TypeNode::try_from(registered)?;
94            *resolvable = Resolvable::Resolved(type_node);
95        }
96        Ok(())
97    }
98
99    fn resolve_instruction_input_value(
100        &self,
101        resolvable: &mut Resolvable<InstructionInputValueNode>,
102    ) -> CodamaResult<()> {
103        if let Resolvable::Unresolved(directive) = resolvable {
104            let resolved = self.resolver.resolve_value_directive(directive)?;
105            *resolvable = Resolvable::Resolved(resolved);
106        }
107        Ok(())
108    }
109
110    fn resolve_value_node(&self, resolvable: &mut Resolvable<ValueNode>) -> CodamaResult<()> {
111        if let Resolvable::Unresolved(directive) = resolvable {
112            let instruction_input = self.resolver.resolve_value_directive(directive)?;
113            let value_node = ValueNode::try_from(instruction_input)?;
114            *resolvable = Resolvable::Resolved(value_node);
115        }
116        Ok(())
117    }
118}
119
120impl KorokVisitor for ResolveDirectivesVisitor<'_> {
121    fn visit_root(&mut self, korok: &mut RootKorok) -> CodamaResult<()> {
122        self.visit_children(korok)
123    }
124
125    fn visit_crate(&mut self, korok: &mut CrateKorok) -> CodamaResult<()> {
126        self.resolve_attributes(&mut korok.attributes)?;
127        self.visit_children(korok)
128    }
129
130    fn visit_file_module(&mut self, korok: &mut FileModuleKorok) -> CodamaResult<()> {
131        self.resolve_attributes(&mut korok.attributes)?;
132        self.visit_children(korok)
133    }
134
135    fn visit_module(&mut self, korok: &mut ModuleKorok) -> CodamaResult<()> {
136        self.resolve_attributes(&mut korok.attributes)?;
137        self.visit_children(korok)
138    }
139
140    fn visit_struct(&mut self, korok: &mut StructKorok) -> CodamaResult<()> {
141        self.resolve_attributes(&mut korok.attributes)?;
142        self.visit_children(korok)
143    }
144
145    fn visit_enum(&mut self, korok: &mut EnumKorok) -> CodamaResult<()> {
146        self.resolve_attributes(&mut korok.attributes)?;
147        self.visit_children(korok)
148    }
149
150    fn visit_enum_variant(&mut self, korok: &mut EnumVariantKorok) -> CodamaResult<()> {
151        self.resolve_attributes(&mut korok.attributes)?;
152        self.visit_children(korok)
153    }
154
155    fn visit_field(&mut self, korok: &mut FieldKorok) -> CodamaResult<()> {
156        self.resolve_attributes(&mut korok.attributes)
157    }
158
159    fn visit_unsupported_item(&mut self, korok: &mut UnsupportedItemKorok) -> CodamaResult<()> {
160        self.resolve_attributes(&mut korok.attributes)
161    }
162
163    fn visit_impl(&mut self, korok: &mut ImplKorok) -> CodamaResult<()> {
164        self.resolve_attributes(&mut korok.attributes)?;
165        self.visit_children(korok)
166    }
167
168    fn visit_const(&mut self, korok: &mut ConstKorok) -> CodamaResult<()> {
169        self.resolve_attributes(&mut korok.attributes)
170    }
171
172    fn visit_unsupported_impl_item(
173        &mut self,
174        korok: &mut UnsupportedImplItemKorok,
175    ) -> CodamaResult<()> {
176        self.resolve_attributes(&mut korok.attributes)
177    }
178}