1use crate::{
17 ir::classes::SymField,
18 ir::functions::SymFunction,
19 ir::types::{SymGenericTerm, SymPlace, SymTy},
20 ir::variables::{FromVar, SymVariable},
21};
22use dada_ir_ast::{
23 ast::{AstBinaryOp, PermissionOp},
24 diagnostic::{Err, Reported},
25 span::{SourceSpanned, Span},
26};
27use dada_util::SalsaSerialize;
28use ordered_float::OrderedFloat;
29use salsa::Update;
30use serde::Serialize;
31
32#[derive(SalsaSerialize)]
33#[salsa::tracked(debug)]
34pub struct SymExpr<'db> {
35 pub span: Span<'db>,
41
42 pub ty: SymTy<'db>,
44
45 #[return_ref]
47 pub kind: SymExprKind<'db>,
48}
49
50impl<'db> SymExpr<'db> {
51 pub(crate) fn false_literal(db: &'db dyn crate::Db, span: Span<'db>) -> SymExpr<'db> {
53 SymExpr::new(
54 db,
55 span,
56 SymTy::boolean(db),
57 SymExprKind::Primitive(SymLiteral::Integral { bits: 0 }),
58 )
59 }
60
61 pub(crate) fn true_literal(db: &'db dyn crate::Db, span: Span<'db>) -> SymExpr<'db> {
63 SymExpr::new(
64 db,
65 span,
66 SymTy::boolean(db),
67 SymExprKind::Primitive(SymLiteral::Integral { bits: 1 }),
68 )
69 }
70
71 pub(crate) fn if_then_else(
73 db: &'db dyn crate::Db,
74 span: Span<'db>,
75 condition: SymExpr<'db>,
76 if_true: SymExpr<'db>,
77 if_false: SymExpr<'db>,
78 ) -> SymExpr<'db> {
79 SymExpr::new(
80 db,
81 span,
82 SymTy::boolean(db),
83 SymExprKind::Match {
84 arms: vec![
85 SymMatchArm {
86 condition: Some(condition),
87 body: if_true,
88 },
89 SymMatchArm {
90 condition: None,
91 body: if_false,
92 },
93 ],
94 },
95 )
96 }
97}
98
99impl<'db> SourceSpanned<'db> for SymExpr<'db> {
100 fn source_span(&self, db: &'db dyn dada_ir_ast::Db) -> Span<'db> {
101 self.span(db)
102 }
103}
104
105impl<'db> Err<'db> for SymExpr<'db> {
106 fn err(db: &'db dyn dada_ir_ast::Db, r: Reported) -> Self {
107 SymExpr::new(db, r.span(db), SymTy::err(db, r), SymExprKind::Error(r))
108 }
109}
110
111#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Update, Serialize)]
112pub enum SymExprKind<'db> {
113 Semi(SymExpr<'db>, SymExpr<'db>),
115
116 Tuple(Vec<SymExpr<'db>>),
118
119 Primitive(SymLiteral),
121
122 ByteLiteral(SymByteLiteral<'db>),
124
125 LetIn {
127 lv: SymVariable<'db>,
128 ty: SymTy<'db>,
129 initializer: Option<SymExpr<'db>>,
130 body: SymExpr<'db>,
131 },
132
133 Await {
135 future: SymExpr<'db>,
136 await_keyword: Span<'db>,
137 },
138
139 Assign {
141 place: SymPlaceExpr<'db>,
142 value: SymExpr<'db>,
143 },
144
145 PermissionOp(PermissionOp, SymPlaceExpr<'db>),
147
148 Call {
153 function: SymFunction<'db>,
154 substitution: Vec<SymGenericTerm<'db>>,
155 arg_temps: Vec<SymVariable<'db>>,
156 },
157
158 Return(SymExpr<'db>),
160
161 Not {
163 operand: SymExpr<'db>,
164 op_span: Span<'db>,
165 },
166
167 BinaryOp(SymBinaryOp, SymExpr<'db>, SymExpr<'db>),
169
170 Aggregate {
172 ty: SymTy<'db>,
173 fields: Vec<SymExpr<'db>>,
174 },
175
176 Match { arms: Vec<SymMatchArm<'db>> },
178
179 Error(Reported),
181}
182
183#[derive(SalsaSerialize)]
184#[salsa::tracked(debug)]
185pub struct SymByteLiteral<'db> {
186 pub span: Span<'db>,
187 pub data: SymByteLiteralData<'db>,
188}
189
190#[derive(SalsaSerialize)]
191#[salsa::interned(debug)]
192pub struct SymByteLiteralData<'db> {
193 pub value: Vec<u8>,
194}
195
196#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Update, Serialize)]
197pub enum SymLiteral {
198 Integral { bits: u64 },
200
201 Float { bits: OrderedFloat<f64> },
203}
204
205#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Update, Debug, Serialize)]
206pub enum SymBinaryOp {
207 Add,
208 Sub,
209 Mul,
210 Div,
211 GreaterThan,
212 LessThan,
213 GreaterEqual,
214 LessEqual,
215 EqualEqual,
216}
217
218impl TryFrom<AstBinaryOp> for SymBinaryOp {
219 type Error = dada_util::Error;
220
221 fn try_from(value: AstBinaryOp) -> Result<Self, Self::Error> {
222 match value {
223 AstBinaryOp::Add => Ok(SymBinaryOp::Add),
224 AstBinaryOp::Sub => Ok(SymBinaryOp::Sub),
225 AstBinaryOp::Mul => Ok(SymBinaryOp::Mul),
226 AstBinaryOp::Div => Ok(SymBinaryOp::Div),
227 AstBinaryOp::GreaterThan => Ok(SymBinaryOp::GreaterThan),
228 AstBinaryOp::LessThan => Ok(SymBinaryOp::LessThan),
229 AstBinaryOp::GreaterEqual => Ok(SymBinaryOp::GreaterEqual),
230 AstBinaryOp::LessEqual => Ok(SymBinaryOp::LessEqual),
231 AstBinaryOp::EqualEqual => Ok(SymBinaryOp::EqualEqual),
232 AstBinaryOp::AndAnd | AstBinaryOp::OrOr | AstBinaryOp::Assign => {
233 dada_util::bail!("no equivalent object binary op")
234 }
235 }
236 }
237}
238
239#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Update, Serialize)]
241pub struct SymMatchArm<'db> {
242 pub condition: Option<SymExpr<'db>>,
245
246 pub body: SymExpr<'db>,
248}
249
250#[derive(SalsaSerialize)]
251#[salsa::tracked(debug)]
252pub struct SymPlaceExpr<'db> {
253 pub span: Span<'db>,
254 pub ty: SymTy<'db>,
255
256 #[return_ref]
257 pub kind: SymPlaceExprKind<'db>,
258}
259
260impl<'db> Err<'db> for SymPlaceExpr<'db> {
261 fn err(db: &'db dyn dada_ir_ast::Db, r: Reported) -> Self {
262 SymPlaceExpr::new(
263 db,
264 r.span(db),
265 SymTy::err(db, r),
266 SymPlaceExprKind::Error(r),
267 )
268 }
269}
270
271impl<'db> SymPlaceExpr<'db> {
272 pub fn give(self, db: &'db dyn crate::Db) -> SymExpr<'db> {
273 SymExpr::new(
274 db,
275 self.span(db),
276 self.ty(db),
277 SymExprKind::PermissionOp(PermissionOp::Give, self),
278 )
279 }
280
281 pub fn into_sym_place(self, db: &'db dyn crate::Db) -> SymPlace<'db> {
282 match *self.kind(db) {
283 SymPlaceExprKind::Var(lv) => SymPlace::var(db, lv),
284 SymPlaceExprKind::Field(place, field) => place.into_sym_place(db).field(db, field),
285 SymPlaceExprKind::Error(r) => SymPlace::err(db, r),
286 }
287 }
288}
289
290#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Update, Serialize)]
291pub enum SymPlaceExprKind<'db> {
292 Var(SymVariable<'db>),
293 Field(SymPlaceExpr<'db>, SymField<'db>),
294 Error(Reported),
295}