mago_reflector/
lib.rs

1use mago_ast::Program;
2use mago_interner::ThreadedInterner;
3use mago_names::Names;
4use mago_reflection::CodebaseReflection;
5use mago_source::Source;
6use mago_walker::*;
7
8use crate::internal::context::Context;
9use crate::internal::walker::ReflectionWalker;
10
11mod internal;
12mod populator;
13
14/// Construct a codebase reflection from the given program.
15///
16/// # Arguments
17///
18/// - `interner`: The `ThreadedInterner` instance used for string interning.
19/// - `source`: The `Source` instance containing the source code of the program.
20/// - `program`: The `Program` instance to reflect.
21/// - `names`: The `Names` instance containing the names of the program.
22///
23/// # Returns
24///
25/// A reflection result containing the reflection of the codebase and any issues found during reflection.
26#[inline]
27pub fn reflect(interner: &ThreadedInterner, source: &Source, program: &Program, names: &Names) -> CodebaseReflection {
28    let mut walker = ReflectionWalker::new();
29
30    let mut context = Context::new(interner, source, names);
31
32    walker.walk_program(program, &mut context);
33
34    walker.reflection
35}
36
37/// Merges two `ReflectionResult` instances.
38///
39/// This method combines the codebase reflections and issues from two `ReflectionResult` instances
40/// into a single `ReflectionResult`. If duplicates are found during merging (such as functions,
41/// classes, or constants with identical names), they are recorded as issues within the resulting
42/// `ReflectionResult`.
43///
44/// # Parameters
45///
46/// - `left`: The first `ReflectionResult` to merge.
47/// - `right`: The second `ReflectionResult` to merge.
48///
49/// # Returns
50///
51/// A new `ReflectionResult` containing the combined reflections and issues from both inputs.
52/// If any conflicts are found (e.g., duplicate functions, classes, or constants), they are recorded
53/// as issues in the returned result.
54#[inline]
55pub fn merge(
56    interner: &ThreadedInterner,
57    mut reflection: CodebaseReflection,
58    other_reflection: CodebaseReflection,
59) -> CodebaseReflection {
60    for (_, function_like) in other_reflection.function_like_reflections.into_iter() {
61        reflection.register_function_like(interner, function_like);
62    }
63
64    for (_, class_like) in other_reflection.class_like_reflections.into_iter() {
65        reflection.register_class_like(interner, class_like);
66    }
67
68    for (_, constant) in other_reflection.constant_reflections.into_iter() {
69        reflection.register_constant(interner, constant);
70    }
71
72    reflection.populated = false;
73    reflection
74}
75
76/// Populates additional data into an existing `ReflectionResult`.
77///
78/// This method updates an existing `ReflectionResult` by adding any additional details
79/// to the `reflection` field based on further analysis. It may also add new issues
80/// encountered during this process.
81///
82/// # Parameters
83///
84/// - `interner`: The `ThreadedInterner` instance used for string interning.
85/// - `result`: The mutable `ReflectionResult` to populate with additional data.
86///
87/// This function is useful for supplementing a `ReflectionResult` with more comprehensive
88/// information after initial reflection or to populate unresolved details.
89#[inline]
90pub fn populate(interner: &ThreadedInterner, reflection: &mut CodebaseReflection) {
91    populator::populate(interner, reflection);
92}