Skip to main content

lutra_compiler/project/
mod.rs

1mod analysis;
2mod source_tree;
3
4pub use analysis::{SymbolInfo, TargetMap, TargetSpan};
5pub(crate) use source_tree::SourceProvider;
6pub use source_tree::{SourceOverlay, SourceTree};
7
8use std::sync::Arc;
9
10use crate::pr;
11
12/// Project, checked.
13#[derive(Debug)]
14pub struct Project {
15    /// Discovered sources
16    pub source: SourceTree,
17
18    /// Resolved definitions
19    pub root_module: pr::ModuleDef,
20
21    /// Resolution ordering of definitions
22    // TODO: make a more efficient "a ordered vec of unordered groups" data structure
23    pub ordering: Vec<Vec<pr::Path>>,
24
25    pub dependencies: Vec<Dependency>,
26
27    /// Index of all resolved identifier references, keyed by source location.
28    /// Built once after name resolution; used for go-to-definition and similar queries.
29    pub target_map: analysis::TargetMap,
30}
31
32#[derive(Debug, Clone)]
33pub struct Dependency {
34    pub name: String,
35
36    pub inner: Arc<Project>,
37}
38
39impl Project {
40    /// Returns name defined with `@!package(name = "...")`.
41    ///
42    /// Represents the default name of this project when included as a dependency.
43    pub fn get_name(&self) -> Option<&str> {
44        self.root_module
45            .get_anno_at(&pr::Path::empty(), pr::Anno::as_std_metadata)
46    }
47
48    /// Returns the default runner URL defined with `@!runner("...")`.
49    pub fn get_runner(&self) -> Option<&str> {
50        self.root_module
51            .get_anno_at(&pr::Path::empty(), pr::Anno::as_std_runner)
52    }
53
54    /// Search the resolved module tree recursively for definitions that carry
55    /// the annotation `@<annotation_name>`.
56    ///
57    /// Returns a vec of fully-qualified paths of matching defs.
58    pub fn find_by_anno<'a, R: 'a>(
59        &'a self,
60        matcher: impl Fn(&'a pr::Anno) -> Option<R> + Copy,
61    ) -> Vec<(pr::Path, R)> {
62        let mut result = Vec::new();
63        let empty = pr::Path::empty();
64        if let Some(r) = self.root_module.get_anno_at(&empty, matcher) {
65            result.push((empty.clone(), r));
66        }
67        find_by_anno_re(&self.root_module, matcher, empty, &mut result);
68        result
69    }
70}
71
72fn find_by_anno_re<'a, R: 'a>(
73    module: &'a pr::ModuleDef,
74    matcher: impl Fn(&'a pr::Anno) -> Option<R> + Copy,
75    mut path: pr::Path,
76    result: &mut Vec<(pr::Path, R)>,
77) {
78    for (name, def) in &module.defs {
79        path.push(name.clone());
80
81        if let Some(r) = def.get_anno(matcher) {
82            result.push((path.clone(), r));
83        }
84
85        if let pr::DefKind::Module(inner) = &def.kind {
86            find_by_anno_re(inner, matcher, path.clone(), result);
87        }
88
89        path.pop();
90    }
91}