1use super::super::annotation_context::AnnotationContext;
7use super::super::type_methods::TypeMethodRegistry;
8use super::super::type_schema::TypeSchemaRegistry;
9use shape_ast::ast::{AnnotationDef, AnnotationHandlerType, FunctionDef};
10use shape_ast::error::{Result, ShapeError};
11use std::sync::Arc;
12
13impl super::ExecutionContext {
14 pub fn register_annotation(&mut self, def: AnnotationDef) {
19 self.annotation_registry.register(def);
20 }
21
22 pub fn annotation_context(&self) -> &AnnotationContext {
24 &self.annotation_context
25 }
26
27 pub fn annotation_context_mut(&mut self) -> &mut AnnotationContext {
29 &mut self.annotation_context
30 }
31
32 pub fn register_function(&mut self, function: FunctionDef) {
36 self.dispatch_on_define_hooks(&function);
37 }
38
39 fn dispatch_on_define_hooks(&mut self, func: &FunctionDef) {
45 for annotation in &func.annotations {
46 if let Some(ann_def) = self.annotation_registry.get(&annotation.name).cloned() {
48 for handler in &ann_def.handlers {
50 if handler.handler_type == AnnotationHandlerType::OnDefine {
51 self.execute_on_define_handler(&ann_def, handler, func);
53 }
54 }
55 }
56 }
59 }
60
61 fn execute_on_define_handler(
67 &mut self,
68 _ann_def: &AnnotationDef,
69 _handler: &shape_ast::ast::AnnotationHandler,
70 _func: &FunctionDef,
71 ) {
72 self.sync_pattern_registry_from_annotation_context();
73 }
74
75 fn sync_pattern_registry_from_annotation_context(&mut self) {}
81
82 pub fn lookup_pattern(&self, name: &str) -> Result<&super::super::closure::Closure> {
86 self.pattern_registry
87 .get(name)
88 .ok_or_else(|| ShapeError::RuntimeError {
89 message: format!(
90 "Unknown pattern: '{}'. Did you register it in the pattern registry?",
91 name
92 ),
93 location: None,
94 })
95 }
96
97 pub fn type_method_registry(&self) -> &Arc<TypeMethodRegistry> {
99 &self.type_method_registry
100 }
101
102 pub fn type_schema_registry(&self) -> &Arc<TypeSchemaRegistry> {
104 &self.type_schema_registry
105 }
106
107 pub fn register_enum(&mut self, enum_def: shape_ast::ast::EnumDef) {
116 self.enum_registry.register(enum_def);
117 }
118
119 pub fn lookup_enum(&self, name: &str) -> Option<&shape_ast::ast::EnumDef> {
121 self.enum_registry.get(name)
122 }
123
124 pub fn has_enum(&self, name: &str) -> bool {
126 self.enum_registry.contains(name)
127 }
128
129 pub fn enum_registry(&self) -> &super::EnumRegistry {
131 &self.enum_registry
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::super::ExecutionContext;
138 use shape_ast::ast::{
139 Annotation, AnnotationDef, AnnotationHandler, AnnotationHandlerType, Expr, FunctionDef,
140 Span,
141 };
142
143 #[test]
144 fn test_register_annotation_definition() {
145 let mut ctx = ExecutionContext::new_empty();
146
147 let ann_def = AnnotationDef {
149 name: "test_annotation".to_string(),
150 name_span: Span::DUMMY,
151 doc_comment: None,
152 params: vec![],
153 allowed_targets: None,
154 handlers: vec![],
155 span: Span::DUMMY,
156 };
157
158 ctx.register_annotation(ann_def);
159
160 assert!(ctx.annotation_registry.contains("test_annotation"));
162 }
163
164 #[test]
165 fn test_function_without_annotations_registers_normally() {
166 let mut ctx = ExecutionContext::new_empty();
167
168 let func = FunctionDef {
169 name: "my_func".to_string(),
170 name_span: Span::DUMMY,
171 declaring_module_path: None,
172 doc_comment: None,
173 type_params: None,
174 params: vec![],
175 return_type: None,
176 body: vec![],
177 annotations: vec![],
178 where_clause: None,
179 is_async: false,
180 is_comptime: false,
181 };
182
183 ctx.register_function(func);
184
185 }
189
190 #[test]
191 fn test_function_with_undefined_annotation_no_crash() {
192 let mut ctx = ExecutionContext::new_empty();
193
194 let func = FunctionDef {
196 name: "annotated_func".to_string(),
197 name_span: Span::DUMMY,
198 declaring_module_path: None,
199 doc_comment: None,
200 type_params: None,
201 params: vec![],
202 return_type: None,
203 body: vec![],
204 annotations: vec![Annotation {
205 name: "undefined".to_string(),
206 args: vec![],
207 span: Span::DUMMY,
208 }],
209 where_clause: None,
210 is_async: false,
211 is_comptime: false,
212 };
213
214 ctx.register_function(func);
216
217 }
221
222 #[test]
223 fn test_annotation_with_on_define_handler_is_called() {
224 let mut ctx = ExecutionContext::new_empty();
225
226 let ann_def = AnnotationDef {
230 name: "tracked".to_string(),
231 name_span: Span::DUMMY,
232 doc_comment: None,
233 params: vec![],
234 allowed_targets: None,
235 handlers: vec![AnnotationHandler {
236 handler_type: AnnotationHandlerType::OnDefine,
237 params: vec![shape_ast::ast::AnnotationHandlerParam {
238 name: "fn".to_string(),
239 is_variadic: false,
240 }],
241 return_type: None,
242 body: Expr::Identifier("fn".to_string(), Span::DUMMY),
245 span: Span::DUMMY,
246 }],
247 span: Span::DUMMY,
248 };
249
250 ctx.register_annotation(ann_def);
251
252 let func = FunctionDef {
254 name: "tracked_func".to_string(),
255 name_span: Span::DUMMY,
256 declaring_module_path: None,
257 doc_comment: None,
258 type_params: None,
259 params: vec![],
260 return_type: None,
261 body: vec![],
262 annotations: vec![Annotation {
263 name: "tracked".to_string(),
264 args: vec![],
265 span: Span::DUMMY,
266 }],
267 where_clause: None,
268 is_async: false,
269 is_comptime: false,
270 };
271
272 ctx.register_function(func);
274
275 }
279
280 #[test]
281 fn test_lookup_pattern_not_found() {
282 let ctx = ExecutionContext::new_empty();
283
284 let result = ctx.lookup_pattern("nonexistent");
285 assert!(result.is_err());
286
287 let err = result.unwrap_err();
288 let msg = format!("{}", err);
289 assert!(msg.contains("Unknown pattern"));
290 assert!(msg.contains("nonexistent"));
291 }
292
293 #[test]
294 fn test_annotation_context_registry_access() {
295 let mut ctx = ExecutionContext::new_empty();
296
297 {
299 let registry = ctx.annotation_context_mut().registry("test_registry");
300 registry.set(
301 "key1".to_string(),
302 shape_value::ValueWord::from_string(std::sync::Arc::new("value1".to_string())),
303 );
304 }
305
306 let registry = ctx.annotation_context_mut().registry("test_registry");
308 assert!(registry.get("key1").is_some());
309 }
310}