Skip to main content

aam_core/pipeline/
executor_traits.rs

1//! Executor trait implementations for task-based validation and parsing.
2//!
3//! These executors consume declarative tasks and perform the actual execution,
4//! completely decoupled from AAML struct manipulation.
5
6#![allow(clippy::unused_self)]
7use crate::error::{AamlError, ErrorDiagnostics};
8use crate::pipeline::PipelineHashMap;
9use crate::pipeline::execution_descriptor::ExecutionContext;
10use crate::pipeline::lexer::Lexer;
11use crate::pipeline::new_pipeline_hash_map;
12use crate::pipeline::parser::Parser;
13use crate::pipeline::tasks::{ParseTask, TaskError, TaskExecutionResult, ValidationTask};
14use crate::pipeline::utils::resolve_relative_path;
15use bumpalo::Bump;
16use smol_str::SmolStr;
17
18/// Trait for executing validation tasks.
19///
20/// A `ValidateExecutor` takes a stream of `ValidationTasks` and executes them,
21/// returning aggregated results suitable for LSP integration.
22pub trait ValidateExecutor: Send + Sync {
23    /// Executes a single validation task within a given context.
24    ///
25    /// # Arguments
26    /// - `task`: The validation task to execute
27    /// - `context`: The current execution context
28    ///
29    /// # Returns
30    /// - `Ok(true)` if validation passed
31    /// - `Err(AamlError)` if validation failed
32    fn execute_validation(
33        &self,
34        task: &ValidationTask,
35        context: &ExecutionContext,
36    ) -> Result<bool, AamlError>;
37
38    /// Executes multiple validation tasks and aggregates results.
39    ///
40    /// This method is the main entry point for validation execution.
41    /// It collects errors from multiple failing tasks rather than stopping
42    /// at the first error, which is critical for LSP support.
43    ///
44    /// # Arguments
45    /// - `tasks`: All validation tasks to execute
46    /// - `context`: The execution context
47    ///
48    /// # Returns
49    /// - `TaskExecutionResult` containing success status and error collection
50    fn execute_batch(
51        &self,
52        tasks: &[ValidationTask],
53        context: &ExecutionContext,
54    ) -> TaskExecutionResult {
55        let mut errors = Vec::new();
56
57        for task in tasks {
58            match self.execute_validation(task, context) {
59                Ok(true) => {}
60                Ok(false) => {
61                    // Task executed but validation failed
62                    errors.push(TaskError {
63                        line: task.line(),
64                        message: format!("Validation failed: {}", task.description()),
65                        task_description: task.description(),
66                        aaml_error: None,
67                    });
68                }
69                Err(e) => {
70                    errors.push(TaskError {
71                        line: task.line(),
72                        message: format!("Validation error: {e}"),
73                        task_description: task.description(),
74                        aaml_error: Some(format!("{e:?}")),
75                    });
76                }
77            }
78        }
79
80        TaskExecutionResult {
81            success: errors.is_empty(),
82            errors,
83            stats: ExecutionStats::default(),
84        }
85    }
86}
87
88// Re-export ExecutionStats from tasks module
89pub use crate::pipeline::tasks::ExecutionStats;
90
91/// Trait for executing parsing tasks.
92///
93/// A `ParserExecutor` takes parse tasks and performs parsing operations,
94/// managing scopes, variables, and directive registration.
95pub trait ParserExecutor: Send + Sync {
96    /// Executes a single parsing task.
97    ///
98    /// # Arguments
99    /// - `task`: The parsing task to execute
100    /// - `context`: Mutable execution context (maybe modified)
101    ///
102    /// # Returns
103    /// - `Ok(())` if parsing succeeded
104    /// - `Err(AamlError)` if parsing failed
105    fn execute_parse<'a>(
106        &self,
107        task: &ParseTask<'_>,
108        arena: &'a Bump,
109        context: &mut ExecutionContext<'a>,
110    ) -> Result<(), AamlError>;
111
112    /// Executes multiple parsing tasks in sequence.
113    ///
114    /// # Arguments
115    /// - `tasks`: All parsing tasks to execute
116    /// - `context`: Mutable execution context
117    ///
118    /// # Returns
119    /// - `TaskExecutionResult` with aggregated results
120    fn execute_batch<'a>(
121        &self,
122        tasks: &[ParseTask<'_>],
123        arena: &'a Bump,
124        context: &mut ExecutionContext<'a>,
125    ) -> TaskExecutionResult {
126        let mut errors = Vec::new();
127
128        for task in tasks {
129            match self.execute_parse(task, arena, context) {
130                Ok(()) => {}
131                Err(e) => {
132                    errors.push(TaskError {
133                        line: task.line(),
134                        message: format!("Parse error: {e}"),
135                        task_description: task.description(),
136                        aaml_error: Some(format!("{e:?}")),
137                    });
138                }
139            }
140        }
141
142        TaskExecutionResult {
143            success: errors.is_empty(),
144            errors,
145            stats: ExecutionStats::default(),
146        }
147    }
148}
149
150/// Default implementation of `ValidateExecutor`.
151///
152/// This provides basic validation task execution with type checking and schema verification.
153pub struct DefaultValidateExecutor {
154    // Can hold shared registries or validation strategies
155}
156
157impl DefaultValidateExecutor {
158    #[must_use]
159    pub const fn new() -> Self {
160        Self {}
161    }
162
163    /// Checks if a type exists in the context's type registry.
164    fn type_exists(context: &ExecutionContext, type_name: &str) -> bool {
165        context.types.contains_key(type_name) || Self::is_builtin_type(type_name)
166    }
167
168    /// Checks if a built-in type is recognized.
169    fn is_builtin_type(type_name: &str) -> bool {
170        matches!(type_name, "string" | "i32" | "f64" | "bool" | "color")
171    }
172
173    /// Validates a value against a type (basic implementation).
174    fn validate_type_value(
175        &self,
176        value: &str,
177        type_name: &str,
178        context: &ExecutionContext,
179    ) -> Result<(), AamlError> {
180        crate::pipeline::utils::validate_type_value(value, type_name, context)
181    }
182
183    fn validate_type_match(
184        &self,
185        key: &str,
186        value: &str,
187        type_name: &str,
188        context: &ExecutionContext,
189    ) -> Result<bool, AamlError> {
190        if !Self::type_exists(context, type_name) {
191            return Err(AamlError::InvalidType {
192                type_name: type_name.to_string(),
193                details: format!("Type not found in registry for key '{key}'"),
194                provided: value.to_string(),
195                diagnostics: Some(Box::new(ErrorDiagnostics::new(
196                    "Unknown type",
197                    format!("Type '{type_name}' is not registered"),
198                    "Register the type using @type directive".to_string(),
199                ))),
200            });
201        }
202
203        if let Err(e) = self.validate_type_value(value, type_name, context) {
204            return Err(AamlError::InvalidType {
205                type_name: type_name.to_string(),
206                details: format!("Validation failed for key '{key}'"),
207                provided: value.to_string(),
208                diagnostics: Some(Box::new(ErrorDiagnostics::new(
209                    "Type validation failed",
210                    e.to_string(),
211                    format!("Ensure '{value}' conforms to type '{type_name}'"),
212                ))),
213            });
214        }
215
216        Ok(true)
217    }
218
219    fn verify_schema_exists(
220        schema_name: &str,
221        context: &ExecutionContext,
222    ) -> Result<bool, AamlError> {
223        if context.schemas.contains_key(schema_name) {
224            return Ok(true);
225        }
226
227        Err(AamlError::NotFound {
228            key: schema_name.to_string(),
229            context: "Schema not found in registry".to_string(),
230            diagnostics: Some(Box::new(ErrorDiagnostics::new(
231                "Schema not defined",
232                format!("Schema '{schema_name}' referenced but not defined"),
233                "Define it using @schema directive".to_string(),
234            ))),
235        })
236    }
237
238    fn verify_file_exists(path: &str) -> Result<bool, AamlError> {
239        if std::path::Path::new(path).exists() {
240            return Ok(true);
241        }
242
243        Err(AamlError::IoError {
244            details: format!("Imported file '{path}' not found"),
245            diagnostics: Some(Box::new(ErrorDiagnostics::new(
246                "File missing",
247                format!("The file '{path}' does not exist."),
248                "Check the file path in your import directive.",
249            ))),
250        })
251    }
252
253    fn check_no_circular_reference(
254        &self,
255        key: &str,
256        context: &ExecutionContext,
257    ) -> Result<bool, AamlError> {
258        let mut current_key: &str = key;
259        let mut visited = std::collections::HashSet::new();
260
261        while let Some(next_val) = context.map.get(current_key) {
262            if !visited.insert(current_key) {
263                return Err(AamlError::CircularDependency {
264                    path: format!("{key} -> {next_val}"),
265                    diagnostics: Some(Box::new(ErrorDiagnostics::new(
266                        "Circular reference detected",
267                        format!("Key '{key}' references itself directly or indirectly"),
268                        "Break the reference loop".to_string(),
269                    ))),
270                });
271            }
272
273            if context.map.contains_key(&**next_val) {
274                current_key = next_val;
275            } else {
276                break;
277            }
278        }
279
280        Ok(true)
281    }
282
283    #[inline]
284    fn derive_schema_names(derive_path: &str) -> impl Iterator<Item = &str> {
285        derive_path.split("::").skip(1)
286    }
287
288    #[inline]
289    fn derived_required_key(current_key: &str, field: &str) -> String {
290        if current_key.is_empty() {
291            field.to_string()
292        } else {
293            format!("{current_key}.{field}")
294        }
295    }
296
297    fn ensure_derived_schema_complete(
298        schema_name: &str,
299        current_key: &str,
300        context: &ExecutionContext,
301    ) -> Result<(), AamlError> {
302        let schema = context
303            .schemas
304            .get(schema_name)
305            .ok_or_else(|| AamlError::NotFound {
306                key: schema_name.to_string(),
307                context: "schema derivation".to_string(),
308                diagnostics: Some(Box::new(ErrorDiagnostics::new(
309                    "Schema not defined",
310                    format!("Schema '{schema_name}' referenced in derive chain but not defined"),
311                    "Ensure the file being derived from defines this schema",
312                ))),
313            })?;
314
315        for (field, (type_name, is_optional)) in &schema.fields {
316            if *is_optional {
317                continue;
318            }
319
320            let full_key = Self::derived_required_key(current_key, field);
321            if context.map.contains_key(full_key.as_str()) {
322                continue;
323            }
324
325            return Err(AamlError::SchemaValidationError {
326                schema: schema_name.to_string(),
327                field: field.to_string(),
328                type_name: type_name.to_string(),
329                details: format!(
330                    "Missing required field '{field}' from derived schema '{schema_name}'"
331                ),
332                diagnostics: Some(Box::new(ErrorDiagnostics::new(
333                    "Incomplete derivation",
334                    format!("Derived object missing required field: {field}"),
335                    "Add the field to satisfy the derived schema",
336                ))),
337            });
338        }
339
340        Ok(())
341    }
342
343    fn check_derive_completeness(
344        &self,
345        derive_path: &str,
346        current_key: &str,
347        context: &ExecutionContext,
348    ) -> Result<bool, AamlError> {
349        if !derive_path.contains("::") {
350            return Ok(true);
351        }
352
353        for schema_name in Self::derive_schema_names(derive_path) {
354            Self::ensure_derived_schema_complete(schema_name, current_key, context)?;
355        }
356
357        Ok(true)
358    }
359
360    fn validate_against_schema(
361        &self,
362        schema_name: &str,
363        key: &str,
364        value: &str,
365        context: &ExecutionContext,
366    ) -> Result<bool, AamlError> {
367        let schema_info =
368            context
369                .schemas
370                .get(schema_name)
371                .ok_or_else(|| AamlError::SchemaValidationError {
372                    schema: schema_name.to_string(),
373                    field: key.to_string(),
374                    type_name: "schema".to_string(),
375                    details: format!("Schema '{schema_name}' not found"),
376                    diagnostics: None,
377                })?;
378
379        if let Err(e) = crate::pipeline::utils::validate_inline_object_against_schema(
380            value,
381            schema_info,
382            context,
383        ) {
384            return Err(AamlError::SchemaValidationError {
385                schema: schema_name.to_string(),
386                field: key.to_string(),
387                type_name: "schema".to_string(),
388                details: e.to_string(),
389                diagnostics: None,
390            });
391        }
392
393        Ok(true)
394    }
395
396    fn check_schema_completeness(
397        schema_name: &str,
398        missing_fields: &[std::borrow::Cow<'_, str>],
399    ) -> Result<bool, AamlError> {
400        if missing_fields.is_empty() {
401            return Ok(true);
402        }
403
404        let missing_str = missing_fields
405            .iter()
406            .map(AsRef::as_ref)
407            .collect::<Vec<_>>()
408            .join(", ");
409        Err(AamlError::SchemaValidationError {
410            schema: schema_name.to_string(),
411            field: missing_str.clone(),
412            type_name: "required".to_string(),
413            details: format!("Schema incomplete: missing required fields: {missing_str}"),
414            diagnostics: None,
415        })
416    }
417
418    fn validate_list_elements(
419        key: &str,
420        items: &[crate::pipeline::parser::ValueNode<'_>],
421        element_type: &str,
422        context: &ExecutionContext,
423    ) -> Result<bool, AamlError> {
424        if element_type == "any" || element_type == "list" || element_type == "object" {
425            return Ok(true);
426        }
427
428        for item in items {
429            if let Err(e) = crate::pipeline::utils::validate_type_value(
430                &item.to_string(),
431                element_type,
432                context,
433            ) {
434                return Err(AamlError::InvalidType {
435                    type_name: element_type.to_string(),
436                    details: format!("List element invalid in '{key}'"),
437                    provided: item.to_string(),
438                    diagnostics: Some(Box::new(ErrorDiagnostics::new(
439                        "List element validation failed",
440                        e.to_string(),
441                        format!("All elements in list must be of type '{element_type}'"),
442                    ))),
443                });
444            }
445        }
446
447        Ok(true)
448    }
449
450    fn validate_object_structure(
451        key: &str,
452        pairs: &[(
453            std::borrow::Cow<'_, str>,
454            crate::pipeline::parser::ValueNode<'_>,
455        )],
456    ) -> Result<bool, AamlError> {
457        if pairs.is_empty() {
458            return Err(AamlError::InvalidValue {
459                details: format!("Empty object for key '{key}'"),
460                expected: "non-empty object".to_string(),
461                diagnostics: None,
462            });
463        }
464
465        Ok(true)
466    }
467}
468
469impl Default for DefaultValidateExecutor {
470    fn default() -> Self {
471        Self::new()
472    }
473}
474
475impl ValidateExecutor for DefaultValidateExecutor {
476    fn execute_validation(
477        &self,
478        task: &ValidationTask,
479        context: &ExecutionContext,
480    ) -> Result<bool, AamlError> {
481        match task {
482            ValidationTask::CheckTypeMatch {
483                key,
484                value,
485                type_name,
486                line: _,
487            } => self.validate_type_match(key, value, type_name, context),
488            ValidationTask::VerifySchemaExists {
489                schema_name,
490                line: _,
491            } => Self::verify_schema_exists(schema_name, context),
492            ValidationTask::VerifyFileExists { path, line: _ } => Self::verify_file_exists(path),
493            ValidationTask::CheckNoCircularReference { key, line: _ } => {
494                self.check_no_circular_reference(key, context)
495            }
496            ValidationTask::CheckDeriveCompleteness {
497                derive_path,
498                current_key,
499                line: _,
500            } => self.check_derive_completeness(derive_path, current_key, context),
501            ValidationTask::ValidateAgainstSchema {
502                schema_name,
503                key,
504                value,
505                line: _,
506            } => self.validate_against_schema(schema_name, key, value, context),
507            ValidationTask::CheckSchemaCompleteness {
508                schema_name,
509                missing_fields,
510                line: _,
511            } => Self::check_schema_completeness(schema_name, missing_fields),
512            ValidationTask::ValidateListElements {
513                key,
514                items,
515                element_type,
516                line: _,
517            } => Self::validate_list_elements(key, items, element_type, context),
518            ValidationTask::ValidateObjectStructure {
519                key,
520                pairs,
521                line: _,
522            } => Self::validate_object_structure(key, pairs),
523        }
524    }
525}
526
527/// Default implementation of `ParserExecutor`.
528///
529/// This processes parsing tasks like variable registration, scope management,
530/// and directive execution.
531pub struct DefaultParserExecutor {
532    // Can hold shared registries or command handlers
533}
534
535impl DefaultParserExecutor {
536    #[must_use]
537    pub const fn new() -> Self {
538        Self {}
539    }
540
541    fn process_variable(
542        variable_name: &str,
543        value: &str,
544        line: usize,
545        context: &mut ExecutionContext<'_>,
546    ) {
547        context.set_value(variable_name, value, line);
548    }
549
550    fn manage_scope(scope: &str, is_entry: bool, context: &mut ExecutionContext<'_>) {
551        if is_entry {
552            context.push_scope(scope.to_string());
553        } else {
554            context.pop_scope();
555        }
556    }
557
558    fn execute_directive(
559        directive_name: &str,
560        arguments: &str,
561        line: usize,
562    ) -> Result<(), AamlError> {
563        match directive_name {
564            "import" | "derive" => Ok(()),
565            _ => Err(AamlError::ParseError {
566                line,
567                content: format!("@{directive_name} {arguments}"),
568                details: format!("Unknown directive: @{directive_name}"),
569                diagnostics: Some(Box::new(ErrorDiagnostics::new(
570                    "Unknown directive",
571                    format!("Directive '@{directive_name}' is not recognized"),
572                    "Known directives: @import, @derive, @schema, @type",
573                ))),
574            }),
575        }
576    }
577
578    fn register_type(
579        type_name: &str,
580        type_spec: &str,
581        line: usize,
582        context: &mut ExecutionContext<'_>,
583    ) -> Result<(), AamlError> {
584        let inferred_default = if type_spec.starts_with("list<") {
585            Some("[]".to_string())
586        } else {
587            None
588        };
589
590        context.register_type(crate::pipeline::execution_descriptor::TypeInfo {
591            name: type_name.into(),
592            spec: type_spec.into(),
593            validator: None,
594            default_value: inferred_default.map(Into::into),
595            metadata: new_pipeline_hash_map(),
596            line,
597        })
598    }
599
600    fn parse_schema_fields(fields: &str) -> PipelineHashMap<SmolStr, (SmolStr, bool)> {
601        let mut schema_fields = new_pipeline_hash_map();
602
603        for field_def in fields.split(',') {
604            let parts: Vec<&str> = field_def.trim().split(':').collect();
605            if parts.len() != 2 {
606                continue;
607            }
608
609            let field_name = parts[0].trim().to_string();
610            let type_name = parts[1].trim().to_string();
611            let is_optional = field_name.ends_with('*');
612            let clean_name = if is_optional {
613                field_name.trim_end_matches('*').trim().to_string()
614            } else {
615                field_name
616            };
617
618            schema_fields.insert(clean_name.into(), (type_name.into(), is_optional));
619        }
620
621        schema_fields
622    }
623
624    fn auto_register_list_types(
625        schema_fields: &PipelineHashMap<SmolStr, (SmolStr, bool)>,
626        line: usize,
627        context: &mut ExecutionContext<'_>,
628    ) -> Result<(), AamlError> {
629        let field_type_names: Vec<SmolStr> = schema_fields
630            .values()
631            .map(|(type_name, _)| type_name.clone())
632            .collect();
633
634        for type_name in field_type_names {
635            if !type_name.starts_with("list<") || context.types.contains_key(type_name.as_str()) {
636                continue;
637            }
638
639            context.register_type(crate::pipeline::execution_descriptor::TypeInfo {
640                name: type_name.clone(),
641                spec: type_name,
642                validator: None,
643                default_value: Some("[]".into()),
644                metadata: new_pipeline_hash_map(),
645                line,
646            })?;
647        }
648        Ok(())
649    }
650
651    fn register_schema(
652        schema_name: &str,
653        fields: &str,
654        line: usize,
655        context: &mut ExecutionContext<'_>,
656    ) -> Result<(), AamlError> {
657        let schema_fields = Self::parse_schema_fields(fields);
658        Self::auto_register_list_types(&schema_fields, line, context)?;
659
660        context.register_schema(crate::pipeline::execution_descriptor::SchemaInfo {
661            name: schema_name.into(),
662            fields: schema_fields,
663            line,
664        });
665
666        context.register_type(crate::pipeline::execution_descriptor::TypeInfo {
667            name: schema_name.into(),
668            spec: "schema".into(),
669            validator: None,
670            default_value: Some("{}".into()),
671            metadata: new_pipeline_hash_map(),
672            line,
673        })
674    }
675
676    fn resolve_derive_import<'a>(
677        &self,
678        derive_path: &str,
679        arena: &'a Bump,
680        context: &mut ExecutionContext<'a>,
681    ) -> Result<(), AamlError> {
682        let parts: Vec<&str> = derive_path.split("::").collect();
683        if parts.is_empty() {
684            return Err(AamlError::DirectiveError {
685                directive: "derive".to_string(),
686                message: "Empty derive path".to_string(),
687                diagnostics: None,
688            });
689        }
690
691        let raw_path = parts[0];
692        let resolved =
693            resolve_relative_path(raw_path, crate::pipeline::source_dir::get().as_deref());
694        let file_path = resolved.to_string_lossy().to_string();
695        if !context.is_imported(&file_path) {
696            let content_string =
697                std::fs::read_to_string(&resolved).map_err(|e| AamlError::IoError {
698                    details: format!("Failed to read imported file '{file_path}': {e}"),
699                    diagnostics: Some(Box::new(ErrorDiagnostics::new(
700                        "Import failed",
701                        format!("Could not read file '{file_path}'"),
702                        "Check if the file exists and is readable",
703                    ))),
704                })?;
705
706            let lexer = crate::pipeline::lexer::DefaultLexer::new();
707            let parser = crate::pipeline::parser::DefaultParser::new();
708            let _ctx_guard = crate::error::push_error_render_context(&file_path, &content_string);
709
710            let imported_content = arena.alloc_str(&content_string);
711
712            let tokens = lexer.tokenize(imported_content)?;
713            let parse_output = parser.parse_with_recovery(&tokens);
714            if let Some(first_error) = parse_output.errors.into_iter().next() {
715                return Err(first_error);
716            }
717
718            // Update source_dir to the imported file's directory for nested deriving
719            // RAII guard restores the previous value on drop (including panic)
720            let _nested_guard = crate::pipeline::source_dir::SourceDirGuard::new(
721                resolved.parent().map(std::path::Path::to_path_buf),
722            );
723
724            let sub_tasks = parser.generate_parse_tasks(&parse_output.ast);
725            for sub_task in sub_tasks {
726                if let ParseTask::ProcessVariable { .. } = sub_task {
727                    // Do not import variables during derived - only schemas and types
728                    continue;
729                }
730                self.execute_parse(&sub_task, arena, context)?;
731            }
732            context.record_import(file_path);
733        }
734
735        Ok(())
736    }
737
738    fn resolve_module_reference(
739        module_name: &str,
740        scope: &str,
741        context: &ExecutionContext<'_>,
742    ) -> Result<(), AamlError> {
743        if !context.imported_files.contains(module_name)
744            && !context.schemas.contains_key(module_name)
745        {
746            return Err(AamlError::NotFound {
747                key: module_name.to_string(),
748                context: format!("module reference in scope '{scope}'"),
749                diagnostics: Some(Box::new(ErrorDiagnostics::new(
750                    "Module not found",
751                    format!("The module '{module_name}' has not been imported or defined"),
752                    "Check for a missing @import directive",
753                ))),
754            });
755        }
756
757        Ok(())
758    }
759}
760
761impl Default for DefaultParserExecutor {
762    fn default() -> Self {
763        Self::new()
764    }
765}
766
767impl ParserExecutor for DefaultParserExecutor {
768    fn execute_parse<'a>(
769        &self,
770        task: &ParseTask<'_>,
771        arena: &'a Bump,
772        context: &mut ExecutionContext<'a>,
773    ) -> Result<(), AamlError> {
774        match task {
775            ParseTask::ProcessVariable {
776                variable_name,
777                value,
778                scope: _,
779                line,
780            } => {
781                Self::process_variable(variable_name, value, *line, context);
782                Ok(())
783            }
784
785            ParseTask::ManageScope {
786                scope,
787                is_entry,
788                line: _,
789            } => {
790                Self::manage_scope(scope, *is_entry, context);
791                Ok(())
792            }
793
794            ParseTask::ExecuteDirective {
795                directive_name,
796                arguments,
797                line,
798            } => Self::execute_directive(directive_name, arguments, *line),
799
800            ParseTask::RegisterType {
801                type_name,
802                type_spec,
803                line,
804            } => Self::register_type(type_name, type_spec, *line, context),
805
806            ParseTask::RegisterSchema {
807                schema_name,
808                fields,
809                line,
810            } => Self::register_schema(schema_name, fields, *line, context),
811
812            ParseTask::ResolveDeriveImport {
813                derive_path,
814                line: _,
815            } => self.resolve_derive_import(derive_path, arena, context),
816
817            ParseTask::ResolveModuleReference {
818                module_name,
819                scope,
820                line: _,
821            } => Self::resolve_module_reference(module_name, scope, context),
822        }
823    }
824}