rush_analyzer/
ast.rs

1use std::collections::HashSet;
2
3use rush_parser::ast::{AssignOp, InfixOp, PrefixOp, Type};
4
5#[derive(Debug, Clone, PartialEq)]
6pub struct AnalyzedProgram<'src> {
7    pub globals: Vec<AnalyzedLetStmt<'src>>,
8    pub functions: Vec<AnalyzedFunctionDefinition<'src>>,
9    pub main_fn: AnalyzedBlock<'src>,
10    pub used_builtins: HashSet<&'src str>,
11}
12
13#[derive(Debug, Clone, PartialEq)]
14pub struct AnalyzedFunctionDefinition<'src> {
15    pub used: bool,
16    pub name: &'src str,
17    pub params: Vec<AnalyzedParameter<'src>>,
18    pub return_type: Type,
19    pub block: AnalyzedBlock<'src>,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct AnalyzedParameter<'src> {
24    pub mutable: bool,
25    pub name: &'src str,
26    pub type_: Type,
27}
28
29#[derive(Debug, Clone, PartialEq)]
30pub struct AnalyzedBlock<'src> {
31    pub result_type: Type,
32    pub stmts: Vec<AnalyzedStatement<'src>>,
33    pub expr: Option<AnalyzedExpression<'src>>,
34}
35
36#[derive(Debug, Clone, PartialEq)]
37pub enum AnalyzedStatement<'src> {
38    Let(AnalyzedLetStmt<'src>),
39    Return(AnalyzedReturnStmt<'src>),
40    Loop(AnalyzedLoopStmt<'src>),
41    While(AnalyzedWhileStmt<'src>),
42    For(AnalyzedForStmt<'src>),
43    Break,
44    Continue,
45    Expr(AnalyzedExpression<'src>),
46}
47
48impl AnalyzedStatement<'_> {
49    pub fn result_type(&self) -> Type {
50        match self {
51            Self::Let(_) => Type::Unit,
52            Self::Return(_) => Type::Never,
53            Self::Loop(node) => match node.never_terminates {
54                true => Type::Never,
55                false => Type::Unit,
56            }, // Used for detecting never-ending loops
57            Self::While(node) => match node.never_terminates {
58                true => Type::Never,
59                false => Type::Unit,
60            }, // Used for detecting never-ending loops
61            Self::For(node) => match node.never_terminates {
62                true => Type::Never,
63                false => Type::Unit,
64            }, // Used for detecting never-ending loops
65            Self::Break => Type::Never,
66            Self::Continue => Type::Never,
67            Self::Expr(expr) => expr.result_type(),
68        }
69    }
70
71    pub fn constant(&self) -> bool {
72        match self {
73            Self::Expr(expr) => expr.constant(),
74            _ => false,
75        }
76    }
77}
78
79#[derive(Debug, Clone, PartialEq)]
80pub struct AnalyzedLetStmt<'src> {
81    pub name: &'src str,
82    pub expr: AnalyzedExpression<'src>,
83    pub mutable: bool,
84    pub used: bool,
85}
86
87pub type AnalyzedReturnStmt<'src> = Option<AnalyzedExpression<'src>>;
88
89#[derive(Debug, Clone, PartialEq)]
90pub struct AnalyzedLoopStmt<'src> {
91    pub block: AnalyzedBlock<'src>,
92    pub never_terminates: bool,
93}
94
95#[derive(Debug, Clone, PartialEq)]
96pub struct AnalyzedWhileStmt<'src> {
97    pub cond: AnalyzedExpression<'src>,
98    pub block: AnalyzedBlock<'src>,
99    pub never_terminates: bool,
100}
101
102#[derive(Debug, Clone, PartialEq)]
103pub struct AnalyzedForStmt<'src> {
104    pub ident: &'src str,
105    pub initializer: AnalyzedExpression<'src>,
106    pub cond: AnalyzedExpression<'src>,
107    pub update: AnalyzedExpression<'src>,
108    pub block: AnalyzedBlock<'src>,
109    pub never_terminates: bool,
110}
111
112#[derive(Debug, Clone, PartialEq)]
113pub enum AnalyzedExpression<'src> {
114    Block(Box<AnalyzedBlock<'src>>),
115    If(Box<AnalyzedIfExpr<'src>>),
116    Int(i64),
117    Float(f64),
118    Bool(bool),
119    Char(u8),
120    Ident(AnalyzedIdentExpr<'src>),
121    Prefix(Box<AnalyzedPrefixExpr<'src>>),
122    Infix(Box<AnalyzedInfixExpr<'src>>),
123    Assign(Box<AnalyzedAssignExpr<'src>>),
124    Call(Box<AnalyzedCallExpr<'src>>),
125    Cast(Box<AnalyzedCastExpr<'src>>),
126    Grouped(Box<AnalyzedExpression<'src>>),
127}
128
129impl AnalyzedExpression<'_> {
130    pub fn result_type(&self) -> Type {
131        match self {
132            Self::Block(expr) => expr.result_type,
133            Self::Int(_) => Type::Int(0),
134            Self::Float(_) => Type::Float(0),
135            Self::Bool(_) => Type::Bool(0),
136            Self::Char(_) => Type::Char(0),
137            Self::Ident(expr) => expr.result_type,
138            Self::If(expr) => expr.result_type,
139            Self::Prefix(expr) => expr.result_type,
140            Self::Infix(expr) => expr.result_type,
141            Self::Assign(expr) => expr.result_type,
142            Self::Call(expr) => expr.result_type,
143            Self::Cast(expr) => expr.result_type,
144            Self::Grouped(expr) => expr.result_type(),
145        }
146    }
147
148    pub fn constant(&self) -> bool {
149        matches!(
150            self,
151            Self::Int(_) | Self::Float(_) | Self::Bool(_) | Self::Char(_)
152        )
153    }
154
155    pub fn as_constant(&self) -> Option<Self> {
156        match self {
157            AnalyzedExpression::Int(_)
158            | AnalyzedExpression::Float(_)
159            | AnalyzedExpression::Bool(_)
160            | AnalyzedExpression::Char(_) => {
161                // this clone is cheap, as inner values of these variants all impl `Copy`
162                Some(self.clone())
163            }
164            _ => None,
165        }
166    }
167}
168
169#[derive(Debug, Clone, PartialEq)]
170pub struct AnalyzedIfExpr<'src> {
171    pub result_type: Type,
172    pub cond: AnalyzedExpression<'src>,
173    pub then_block: AnalyzedBlock<'src>,
174    pub else_block: Option<AnalyzedBlock<'src>>,
175}
176
177#[derive(Debug, Clone, PartialEq, Eq)]
178pub struct AnalyzedIdentExpr<'src> {
179    pub result_type: Type,
180    pub ident: &'src str,
181}
182
183#[derive(Debug, Clone, PartialEq)]
184pub struct AnalyzedPrefixExpr<'src> {
185    pub result_type: Type,
186    pub op: PrefixOp,
187    pub expr: AnalyzedExpression<'src>,
188}
189
190#[derive(Debug, Clone, PartialEq)]
191pub struct AnalyzedInfixExpr<'src> {
192    pub result_type: Type,
193    pub lhs: AnalyzedExpression<'src>,
194    pub op: InfixOp,
195    pub rhs: AnalyzedExpression<'src>,
196}
197
198#[derive(Debug, Clone, PartialEq)]
199pub struct AnalyzedAssignExpr<'src> {
200    pub result_type: Type,
201    pub assignee: &'src str,
202    pub assignee_ptr_count: usize,
203    pub op: AssignOp,
204    pub expr: AnalyzedExpression<'src>,
205}
206
207#[derive(Debug, Clone, PartialEq)]
208pub struct AnalyzedCallExpr<'src> {
209    pub result_type: Type,
210    pub func: &'src str,
211    pub args: Vec<AnalyzedExpression<'src>>,
212}
213
214#[derive(Debug, Clone, PartialEq)]
215pub struct AnalyzedCastExpr<'src> {
216    pub result_type: Type,
217    pub expr: AnalyzedExpression<'src>,
218    pub type_: Type,
219}