Skip to main content

dada_ir_ast/
ast.rs

1#![allow(clippy::unused_unit)] // FIXME: derive(Update) triggers these
2
3use dada_util::FromImpls;
4use dada_util::SalsaSerialize;
5use salsa::Update;
6use serde::Serialize;
7
8use crate::{
9    inputs::SourceFile,
10    span::{Span, Spanned},
11};
12
13mod use_item;
14pub use use_item::*;
15mod class_item;
16pub use class_item::*;
17mod member;
18pub use member::*;
19mod function;
20pub use function::*;
21mod types;
22pub use types::*;
23mod util;
24pub use util::*;
25mod expr;
26pub use expr::*;
27
28#[derive(SalsaSerialize)]
29#[salsa::interned(debug)]
30pub struct Identifier<'db> {
31    #[return_ref]
32    pub text: String,
33}
34
35impl<'db> Identifier<'db> {
36    pub fn prelude(db: &'db dyn crate::Db) -> Identifier<'db> {
37        Identifier::new(db, "prelude")
38    }
39
40    pub fn dada(db: &'db dyn crate::Db) -> Identifier<'db> {
41        Identifier::new(db, "dada")
42    }
43
44    pub fn main(db: &'db dyn crate::Db) -> Identifier<'db> {
45        Identifier::new(db, "main")
46    }
47
48    pub fn new_ident(db: &'db dyn crate::Db) -> Identifier<'db> {
49        Identifier::new(db, "new")
50    }
51
52    /// Create interned "self" identifier
53    pub fn self_ident(db: &'db dyn crate::Db) -> Identifier<'db> {
54        Identifier::new(db, "self")
55    }
56
57    /// Create interned "Self" identifier
58    pub fn self_ty_ident(db: &'db dyn crate::Db) -> Identifier<'db> {
59        Identifier::new(db, "Self")
60    }
61}
62
63impl std::fmt::Display for Identifier<'_> {
64    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65        salsa::with_attached_database(|db| write!(f, "{}", self.text(db)))
66            .unwrap_or_else(|| std::fmt::Debug::fmt(self, f))
67    }
68}
69
70#[derive(SalsaSerialize)]
71#[salsa::tracked(debug)]
72pub struct AstModule<'db> {
73    pub name: Identifier<'db>,
74
75    #[return_ref]
76    pub items: SpanVec<'db, AstItem<'db>>,
77}
78
79impl<'db> Spanned<'db> for AstModule<'db> {
80    fn span(&self, db: &'db dyn crate::Db) -> Span<'db> {
81        self.items(db).span
82    }
83}
84
85#[derive(
86    Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Update, FromImpls, Serialize,
87)]
88pub enum AstItem<'db> {
89    SourceFile(SourceFile),
90    Use(AstUse<'db>),
91    Aggregate(AstAggregate<'db>),
92    Function(AstFunction<'db>),
93    MainFunction(AstMainFunction<'db>),
94}
95
96/// A "path" identifies an item and a partial set of substitutions.
97#[derive(SalsaSerialize)]
98#[salsa::tracked(debug)]
99pub struct AstPath<'db> {
100    #[return_ref]
101    pub kind: AstPathKind<'db>,
102}
103
104#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Update, Serialize)]
105pub enum AstPathKind<'db> {
106    /// `$id` that starts a path
107    Identifier(SpannedIdentifier<'db>),
108
109    /// `$path[...]`
110    GenericArgs {
111        path: AstPath<'db>,
112        args: SpanVec<'db, AstGenericTerm<'db>>,
113    },
114
115    /// `$path.$id`
116    Member {
117        path: AstPath<'db>,
118        id: SpannedIdentifier<'db>,
119    },
120}
121
122impl<'db> AstPath<'db> {
123    pub fn len(self, db: &'db dyn crate::Db) -> usize {
124        match self.kind(db) {
125            AstPathKind::Identifier(_) => 1,
126            AstPathKind::GenericArgs { path, .. } => path.len(db) + 1,
127            AstPathKind::Member { path, .. } => path.len(db) + 1,
128        }
129    }
130
131    pub fn first_id(self, db: &'db dyn crate::Db) -> SpannedIdentifier<'db> {
132        match *self.kind(db) {
133            AstPathKind::Identifier(id) => id,
134            AstPathKind::GenericArgs { path, .. } => path.first_id(db),
135            AstPathKind::Member { path, .. } => path.first_id(db),
136        }
137    }
138
139    pub fn last_id(self, db: &'db dyn crate::Db) -> SpannedIdentifier<'db> {
140        match *self.kind(db) {
141            AstPathKind::Identifier(id) => id,
142            AstPathKind::GenericArgs { path, .. } => path.first_id(db),
143            AstPathKind::Member { id: ident, .. } => ident,
144        }
145    }
146}
147
148impl<'db> Spanned<'db> for AstPath<'db> {
149    fn span(&self, db: &'db dyn crate::Db) -> Span<'db> {
150        match self.kind(db) {
151            AstPathKind::Identifier(id) => id.span,
152            AstPathKind::GenericArgs { path, args } => path.first_id(db).span.to(db, args.span),
153            AstPathKind::Member { path, id: ident } => path.first_id(db).span.to(db, ident.span),
154        }
155    }
156}
157
158#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Update, Debug, Serialize)]
159pub struct SpannedIdentifier<'db> {
160    pub span: Span<'db>,
161    pub id: Identifier<'db>,
162}
163
164impl<'db> Spanned<'db> for SpannedIdentifier<'db> {
165    fn span(&self, _db: &'db dyn crate::Db) -> Span<'db> {
166        self.span
167    }
168}
169
170/// For functions, classes, and other items we often defer parsing their contents.
171/// This struct captures the contents and the span at which they appeared.
172/// It can then be used to parse the contents later.
173/// We also use it to parse an expression like `a[...]`,
174/// as the `...` may wind up being parsed as a generic term
175/// or an expression.
176#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Update, Debug, Serialize)]
177pub struct DeferredParse<'db> {
178    pub span: Span<'db>,
179    pub contents: String,
180}
181
182#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Update, Debug, Serialize)]
183pub struct AstVisibility<'db> {
184    pub span: Span<'db>,
185    pub kind: VisibilityKind,
186}
187
188impl<'db> Spanned<'db> for AstVisibility<'db> {
189    fn span(&self, _db: &'db dyn crate::Db) -> Span<'db> {
190        self.span
191    }
192}
193
194#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Update, Debug, Serialize)]
195pub enum VisibilityKind {
196    Export,
197    Pub,
198}