1use std::fmt::{self, Debug, Display, Formatter};
2
3use crate::Span;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum Type {
7 Int(usize),
8 Float(usize),
9 Bool(usize),
10 Char(usize),
11 Unit,
12 Never,
14 Unknown,
16}
17
18impl Display for Type {
19 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
20 match self {
21 Self::Int(indirections) => write!(f, "{}int", "*".repeat(*indirections)),
22 Self::Float(indirections) => write!(f, "{}float", "*".repeat(*indirections)),
23 Self::Bool(indirections) => write!(f, "{}bool", "*".repeat(*indirections)),
24 Self::Char(indirections) => write!(f, "{}char", "*".repeat(*indirections)),
25 Self::Unit => write!(f, "()"),
26 Self::Never => write!(f, "!"),
27 Self::Unknown => write!(f, "{{unknown}}"),
28 }
29 }
30}
31
32impl Type {
33 pub fn add_ref(self) -> Option<Self> {
34 Some(match self {
35 Type::Int(ptr) => Type::Int(ptr + 1),
36 Type::Float(ptr) => Type::Float(ptr + 1),
37 Type::Bool(ptr) => Type::Bool(ptr + 1),
38 Type::Char(ptr) => Type::Char(ptr + 1),
39 _ => return None,
40 })
41 }
42
43 pub fn sub_deref(self) -> Option<Self> {
44 Some(match self {
45 Type::Int(ptr) | Type::Float(ptr) | Type::Bool(ptr) | Type::Char(ptr) if ptr == 0 => {
46 return None
47 }
48 Type::Int(ptr) => Type::Int(ptr - 1),
49 Type::Float(ptr) => Type::Float(ptr - 1),
50 Type::Bool(ptr) => Type::Bool(ptr - 1),
51 Type::Char(ptr) => Type::Char(ptr - 1),
52 _ => return None,
53 })
54 }
55
56 pub fn ptr_count(&self) -> Option<usize> {
57 match self {
58 Type::Int(ptr) => Some(*ptr),
59 Type::Float(ptr) => Some(*ptr),
60 Type::Bool(ptr) => Some(*ptr),
61 Type::Char(ptr) => Some(*ptr),
62 Type::Unit => None,
63 Type::Never => None,
64 Type::Unknown => None,
65 }
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq)]
70pub struct Spanned<'src, T> {
71 pub span: Span<'src>,
72 pub inner: T,
73}
74
75#[derive(Debug, Clone, PartialEq)]
76pub struct Program<'src> {
77 pub span: Span<'src>,
78 pub functions: Vec<FunctionDefinition<'src>>,
79 pub globals: Vec<LetStmt<'src>>,
80}
81
82#[derive(Debug, Clone, PartialEq)]
83pub struct FunctionDefinition<'src> {
84 pub span: Span<'src>,
85 pub name: Spanned<'src, &'src str>,
86 pub params: Spanned<'src, Vec<Parameter<'src>>>,
87 pub return_type: Spanned<'src, Option<Type>>,
88 pub block: Block<'src>,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq)]
92pub struct Parameter<'src> {
93 pub mutable: bool,
94 pub name: Spanned<'src, &'src str>,
95 pub type_: Spanned<'src, Type>,
96}
97
98#[derive(Debug, Clone, PartialEq)]
99pub struct Block<'src> {
100 pub span: Span<'src>,
101 pub stmts: Vec<Statement<'src>>,
102 pub expr: Option<Expression<'src>>,
103}
104
105impl<'src> Block<'src> {
106 pub fn result_span(&self) -> Span<'src> {
108 self.expr.as_ref().map_or_else(
109 || self.stmts.last().map_or(self.span, |stmt| stmt.span()),
110 |expr| expr.span(),
111 )
112 }
113}
114
115#[derive(Debug, Clone, PartialEq)]
116pub enum Statement<'src> {
117 Let(LetStmt<'src>),
118 Return(ReturnStmt<'src>),
119 Loop(LoopStmt<'src>),
120 While(WhileStmt<'src>),
121 For(ForStmt<'src>),
122 Break(BreakStmt<'src>),
123 Continue(ContinueStmt<'src>),
124 Expr(ExprStmt<'src>),
125}
126
127impl<'src> Statement<'src> {
128 pub fn span(&self) -> Span<'src> {
129 match self {
130 Self::Let(stmt) => stmt.span,
131 Self::Return(stmt) => stmt.span,
132 Self::Loop(stmt) => stmt.span,
133 Self::While(stmt) => stmt.span,
134 Self::For(stmt) => stmt.span,
135 Self::Break(stmt) => stmt.span,
136 Self::Continue(stmt) => stmt.span,
137 Self::Expr(stmt) => stmt.span,
138 }
139 }
140}
141
142#[derive(Debug, Clone, PartialEq)]
143pub struct LetStmt<'src> {
144 pub span: Span<'src>,
145 pub mutable: bool,
146 pub name: Spanned<'src, &'src str>,
147 pub type_: Option<Spanned<'src, Type>>,
148 pub expr: Expression<'src>,
149}
150
151#[derive(Debug, Clone, PartialEq)]
152pub struct ReturnStmt<'src> {
153 pub span: Span<'src>,
154 pub expr: Option<Expression<'src>>,
155}
156
157#[derive(Debug, Clone, PartialEq)]
158pub struct LoopStmt<'src> {
159 pub span: Span<'src>,
160 pub block: Block<'src>,
161}
162
163#[derive(Debug, Clone, PartialEq)]
164pub struct WhileStmt<'src> {
165 pub span: Span<'src>,
166 pub cond: Expression<'src>,
167 pub block: Block<'src>,
168}
169
170#[derive(Debug, Clone, PartialEq)]
171pub struct ForStmt<'src> {
172 pub span: Span<'src>,
173 pub ident: Spanned<'src, &'src str>,
174 pub initializer: Expression<'src>,
175 pub cond: Expression<'src>,
176 pub update: Expression<'src>,
177 pub block: Block<'src>,
178}
179
180#[derive(Debug, Clone, PartialEq, Eq)]
181pub struct BreakStmt<'src> {
182 pub span: Span<'src>,
183}
184
185#[derive(Debug, Clone, PartialEq, Eq)]
186pub struct ContinueStmt<'src> {
187 pub span: Span<'src>,
188}
189
190#[derive(Debug, Clone, PartialEq)]
191pub struct ExprStmt<'src> {
192 pub span: Span<'src>,
193 pub expr: Expression<'src>,
194}
195
196#[derive(Debug, Clone, PartialEq)]
197pub enum Expression<'src> {
198 Block(Box<Block<'src>>),
199 If(Box<IfExpr<'src>>),
200 Int(Spanned<'src, i64>),
201 Float(Spanned<'src, f64>),
202 Bool(Spanned<'src, bool>),
203 Char(Spanned<'src, u8>),
204 Ident(Spanned<'src, &'src str>),
205 Prefix(Box<PrefixExpr<'src>>),
206 Infix(Box<InfixExpr<'src>>),
207 Assign(Box<AssignExpr<'src>>),
208 Call(Box<CallExpr<'src>>),
209 Cast(Box<CastExpr<'src>>),
210 Grouped(Spanned<'src, Box<Expression<'src>>>),
211}
212
213impl<'src> Expression<'src> {
214 pub fn span(&self) -> Span<'src> {
215 match self {
216 Self::Block(expr) => expr.span,
217 Self::If(expr) => expr.span,
218 Self::Int(expr) => expr.span,
219 Self::Float(expr) => expr.span,
220 Self::Bool(expr) => expr.span,
221 Self::Char(expr) => expr.span,
222 Self::Ident(expr) => expr.span,
223 Self::Prefix(expr) => expr.span,
224 Self::Infix(expr) => expr.span,
225 Self::Assign(expr) => expr.span,
226 Self::Call(expr) => expr.span,
227 Self::Cast(expr) => expr.span,
228 Self::Grouped(expr) => expr.span,
229 }
230 }
231}
232
233#[derive(Debug, Clone, PartialEq)]
234pub struct IfExpr<'src> {
235 pub span: Span<'src>,
236 pub cond: Expression<'src>,
237 pub then_block: Block<'src>,
238 pub else_block: Option<Block<'src>>,
239}
240
241#[derive(Debug, Clone, PartialEq)]
242pub struct PrefixExpr<'src> {
243 pub span: Span<'src>,
244 pub op: PrefixOp,
245 pub expr: Expression<'src>,
246}
247
248#[derive(Debug, Clone, Copy, PartialEq, Eq)]
249pub enum PrefixOp {
250 Not,
252 Neg,
254 Ref,
256 Deref,
258}
259
260impl Display for PrefixOp {
261 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
262 write!(
263 f,
264 "{}",
265 match self {
266 PrefixOp::Not => "!",
267 PrefixOp::Neg => "-",
268 PrefixOp::Ref => "&",
269 PrefixOp::Deref => "*",
270 }
271 )
272 }
273}
274
275#[derive(Debug, Clone, PartialEq)]
276pub struct InfixExpr<'src> {
277 pub span: Span<'src>,
278 pub lhs: Expression<'src>,
279 pub op: InfixOp,
280 pub rhs: Expression<'src>,
281}
282
283#[derive(Debug, Clone, Copy, PartialEq, Eq)]
284pub enum InfixOp {
285 Plus,
287 Minus,
289 Mul,
291 Div,
293 Rem,
295 Pow,
297
298 Eq,
300 Neq,
302 Lt,
304 Gt,
306 Lte,
308 Gte,
310
311 Shl,
313 Shr,
315 BitOr,
317 BitAnd,
319 BitXor,
321
322 And,
324 Or,
326}
327
328impl From<AssignOp> for InfixOp {
329 fn from(src: AssignOp) -> Self {
330 match src {
331 AssignOp::Plus => InfixOp::Plus,
332 AssignOp::Minus => InfixOp::Minus,
333 AssignOp::Mul => InfixOp::Mul,
334 AssignOp::Div => InfixOp::Div,
335 AssignOp::Shl => InfixOp::Shl,
336 AssignOp::Shr => InfixOp::Shr,
337 AssignOp::Rem => InfixOp::Rem,
338 AssignOp::Pow => InfixOp::Pow,
339 AssignOp::BitOr => InfixOp::BitOr,
340 AssignOp::BitAnd => InfixOp::BitAnd,
341 AssignOp::BitXor => Self::BitXor,
342 AssignOp::Basic => panic!("cannot convert assign op basic to infix op"),
343 }
344 }
345}
346
347impl Display for InfixOp {
348 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
349 write!(
350 f,
351 "{}",
352 match self {
353 Self::Plus => "+",
354 Self::Minus => "-",
355 Self::Mul => "*",
356 Self::Div => "/",
357 Self::Rem => "%",
358 Self::Pow => "**",
359 Self::Eq => "==",
360 Self::Neq => "!=",
361 Self::Lt => "<",
362 Self::Gt => ">",
363 Self::Lte => "<=",
364 Self::Gte => ">=",
365 Self::Shl => "<<",
366 Self::Shr => ">>",
367 Self::BitOr => "|",
368 Self::BitAnd => "&",
369 Self::BitXor => "^",
370 Self::And => "&&",
371 Self::Or => "||",
372 }
373 )
374 }
375}
376
377#[derive(Debug, Clone, PartialEq)]
378pub struct AssignExpr<'src> {
379 pub span: Span<'src>,
380 pub assignee: Spanned<'src, &'src str>,
381 pub assignee_ptr_count: usize,
382 pub op: AssignOp,
383 pub expr: Expression<'src>,
384}
385
386#[derive(Debug, Clone, Copy, PartialEq, Eq)]
387pub enum AssignOp {
388 Basic,
390 Plus,
392 Minus,
394 Mul,
396 Div,
398 Rem,
400 Pow,
402 Shl,
404 Shr,
406 BitOr,
408 BitAnd,
410 BitXor,
412}
413
414impl Display for AssignOp {
415 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
416 write!(
417 f,
418 "{}=",
419 match self {
420 Self::Basic => "",
421 Self::Plus => "+",
422 Self::Minus => "-",
423 Self::Mul => "*",
424 Self::Div => "/",
425 Self::Rem => "%",
426 Self::Pow => "**",
427 Self::Shl => "<<",
428 Self::Shr => ">>",
429 Self::BitOr => "|",
430 Self::BitAnd => "&",
431 Self::BitXor => "^",
432 }
433 )
434 }
435}
436
437#[derive(Debug, Clone, PartialEq)]
438pub struct CallExpr<'src> {
439 pub span: Span<'src>,
440 pub func: Spanned<'src, &'src str>,
441 pub args: Vec<Expression<'src>>,
442}
443
444#[derive(Debug, Clone, PartialEq)]
445pub struct CastExpr<'src> {
446 pub span: Span<'src>,
447 pub expr: Expression<'src>,
448 pub type_: Spanned<'src, Type>,
449}