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 }, Self::While(node) => match node.never_terminates {
58 true => Type::Never,
59 false => Type::Unit,
60 }, Self::For(node) => match node.never_terminates {
62 true => Type::Never,
63 false => Type::Unit,
64 }, 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 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}