Skip to main content

lutra_compiler/pr/
def.rs

1use enum_as_inner::EnumAsInner;
2use indexmap::IndexMap;
3use itertools::Itertools;
4
5use crate::Span;
6use crate::pr::path::Path;
7use crate::pr::{Expr, Ty};
8
9/// Definition.
10#[derive(Debug, Clone, PartialEq)]
11pub struct Def {
12    pub kind: DefKind,
13
14    pub annotations: Vec<Annotation>,
15
16    pub doc_comment: Option<DocComment>,
17
18    /// Code span of the whole definition (including doc comments and annotations)
19    pub span: Option<Span>,
20
21    /// Code span of definition name
22    pub span_name: Option<Span>,
23}
24
25#[derive(Debug, EnumAsInner, PartialEq, Clone)]
26pub enum DefKind {
27    Module(ModuleDef),
28    Expr(ExprDef),
29    Ty(TyDef),
30    Import(ImportDef),
31
32    /// A definition that has not yet been resolved.
33    /// Created during the first pass of the AST, must not be present in
34    /// a fully resolved module structure.
35    Unresolved(Option<Box<DefKind>>),
36}
37
38#[derive(PartialEq, Clone, Default)]
39pub struct ModuleDef {
40    pub defs: IndexMap<String, Def>,
41
42    // Self-annotations, defined within the module
43    pub annotations: Vec<Annotation>,
44
45    /// Span covering the content of this module, i.e. the region inside the
46    /// braces for inline modules, or the whole file body for file-based
47    /// submodules. This excludes inner doc comments or annotations.
48    pub span_content: Option<Span>,
49}
50
51#[derive(Debug, PartialEq, Clone)]
52pub struct ExprDef {
53    pub value: Box<Expr>,
54
55    pub constant: bool,
56    pub ty: Option<Ty>,
57}
58
59#[derive(Debug, PartialEq, Clone)]
60pub struct TyDef {
61    pub ty: Ty,
62    pub is_framed: bool,
63    pub framed_label: Option<String>,
64}
65
66#[derive(Debug, PartialEq, Clone)]
67pub struct ImportDef {
68    pub kind: ImportKind,
69    pub span: Span,
70}
71
72#[derive(Debug, PartialEq, Clone)]
73pub enum ImportKind {
74    /// Represents `std::sql::from as read_table`
75    Single(Path, Option<String>),
76
77    /// Represents `std::sql::{...}`
78    Many(Path, Vec<ImportDef>),
79}
80
81impl ImportDef {
82    pub fn new_simple(path: Path, span: Span) -> Self {
83        Self {
84            kind: ImportKind::Single(path, None),
85            span,
86        }
87    }
88
89    pub fn as_simple(&self) -> Option<&Path> {
90        let ImportKind::Single(path, _) = &self.kind else {
91            return None;
92        };
93        Some(path)
94    }
95
96    pub fn path(&self) -> &Path {
97        match &self.kind {
98            ImportKind::Single(path, _) => path,
99            ImportKind::Many(path, _) => path,
100        }
101    }
102}
103
104#[derive(Debug, Clone, PartialEq)]
105pub struct Annotation {
106    pub expr: Box<Expr>,
107}
108
109#[derive(Debug, Clone, PartialEq)]
110pub struct DocComment {
111    pub content: String,
112    pub span: Span,
113}
114
115impl Def {
116    pub fn new<K: Into<DefKind>>(kind: K) -> Def {
117        Def {
118            kind: kind.into(),
119            annotations: Vec::new(),
120            doc_comment: None,
121
122            span: None,
123            span_name: None,
124        }
125    }
126}
127
128impl From<ModuleDef> for DefKind {
129    fn from(value: ModuleDef) -> Self {
130        DefKind::Module(value)
131    }
132}
133impl From<Expr> for DefKind {
134    fn from(expr: Expr) -> Self {
135        DefKind::Expr(ExprDef {
136            value: Box::new(expr),
137            ty: None,
138            constant: false,
139        })
140    }
141}
142
143impl std::fmt::Debug for ModuleDef {
144    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145        let mut ds = f.debug_struct("ModuleDef");
146
147        if !self.annotations.is_empty() {
148            ds.field("annotations", &self.annotations);
149        }
150
151        if self.defs.len() < 15 {
152            ds.field("defs", &DebugNames(&self.defs));
153        } else {
154            ds.field("defs", &format!("... {} entries ...", self.defs.len()));
155        }
156        ds.finish()
157    }
158}
159
160struct DebugNames<'a>(&'a IndexMap<String, Def>);
161
162impl<'a> std::fmt::Debug for DebugNames<'a> {
163    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164        let mut dm = f.debug_map();
165        for (n, def) in self.0.iter().sorted_by_key(|x| x.0) {
166            dm.entry(n, def);
167        }
168        dm.finish()
169    }
170}