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
43#[derive(Debug, PartialEq, Clone)]
44pub struct ExprDef {
45    pub value: Box<Expr>,
46
47    pub constant: bool,
48    pub ty: Option<Ty>,
49}
50
51#[derive(Debug, PartialEq, Clone)]
52pub struct TyDef {
53    pub ty: Ty,
54    pub is_framed: bool,
55    pub framed_label: Option<String>,
56}
57
58#[derive(Debug, PartialEq, Clone)]
59pub struct ImportDef {
60    pub kind: ImportKind,
61    pub span: Span,
62}
63
64#[derive(Debug, PartialEq, Clone)]
65pub enum ImportKind {
66    /// Represents `std::sql::from as read_table`
67    Single(Path, Option<String>),
68
69    /// Represents `std::sql::{...}`
70    Many(Path, Vec<ImportDef>),
71}
72
73impl ImportDef {
74    pub fn new_simple(path: Path, span: Span) -> Self {
75        Self {
76            kind: ImportKind::Single(path, None),
77            span,
78        }
79    }
80
81    pub fn as_simple(&self) -> Option<&Path> {
82        let ImportKind::Single(path, _) = &self.kind else {
83            return None;
84        };
85        Some(path)
86    }
87
88    pub fn path(&self) -> &Path {
89        match &self.kind {
90            ImportKind::Single(path, _) => path,
91            ImportKind::Many(path, _) => path,
92        }
93    }
94}
95
96#[derive(Debug, Clone, PartialEq)]
97pub struct Annotation {
98    pub expr: Box<Expr>,
99}
100
101#[derive(Debug, Clone, PartialEq)]
102pub struct DocComment {
103    pub content: String,
104    pub span: Span,
105}
106
107impl Def {
108    pub fn new<K: Into<DefKind>>(kind: K) -> Def {
109        Def {
110            kind: kind.into(),
111            annotations: Vec::new(),
112            doc_comment: None,
113
114            span: None,
115            span_name: None,
116        }
117    }
118}
119
120impl From<ModuleDef> for DefKind {
121    fn from(value: ModuleDef) -> Self {
122        DefKind::Module(value)
123    }
124}
125impl From<Expr> for DefKind {
126    fn from(expr: Expr) -> Self {
127        DefKind::Expr(ExprDef {
128            value: Box::new(expr),
129            ty: None,
130            constant: false,
131        })
132    }
133}
134
135impl std::fmt::Debug for ModuleDef {
136    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137        let mut ds = f.debug_struct("ModuleDef");
138
139        if self.defs.len() < 15 {
140            ds.field("defs", &DebugNames(&self.defs));
141        } else {
142            ds.field("defs", &format!("... {} entries ...", self.defs.len()));
143        }
144        ds.finish()
145    }
146}
147
148struct DebugNames<'a>(&'a IndexMap<String, Def>);
149
150impl<'a> std::fmt::Debug for DebugNames<'a> {
151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152        let mut dm = f.debug_map();
153        for (n, def) in self.0.iter().sorted_by_key(|x| x.0) {
154            dm.entry(n, def);
155        }
156        dm.finish()
157    }
158}