1use std::ops::Deref;
2
3pub type Identifier = String;
4
5#[derive(Debug, Clone)]
6pub struct Ast {
7 pub declarations: Vec<Declaration>,
8}
9
10pub type AstBlockItems = Vec<AstBlockItem>;
11
12#[derive(Clone, Debug)]
13pub struct AstBlock {
14 pub items: AstBlockItems,
15}
16
17#[derive(Debug, Default, Clone, Eq, PartialEq)]
18pub enum Type {
19 #[default]
20 Int,
21 Long,
22 UInt,
23 ULong,
24 Fun {
25 ptypes: Vec<Type>,
26 return_type: Box<Type>,
27 },
28}
29
30#[derive(Copy, Clone, Debug)]
31pub enum StorageClass {
32 Static,
33 Extern,
34 Auto,
35}
36
37#[derive(Clone, Debug)]
38pub enum AstBlockItem {
39 S(Statement),
40 D(Declaration),
41}
42
43#[derive(Clone, Debug)]
44pub enum Declaration {
45 Var(VarDec),
46 Fun(FunDec),
47}
48
49#[derive(Clone, Debug)]
50pub struct FunDec {
51 pub name: Identifier,
52 pub params: Vec<Identifier>,
53 pub body: Option<AstBlock>,
54 pub storage_class: StorageClass,
55 pub fun_type: Type,
56}
57
58#[derive(Debug, Clone)]
59pub struct VarDec {
60 pub name: Identifier,
61 pub init: Option<Exp>,
62 pub storage_class: StorageClass,
63 pub var_type: Type,
64}
65
66pub type Cases = Vec<(Option<AstConst>, Identifier)>;
67
68#[derive(Debug, Clone)]
69pub struct DoWhile {
70 pub body: Box<Statement>,
71 pub condition: Exp,
72 pub label: Identifier,
73}
74
75#[derive(Debug, Clone)]
76pub struct While {
77 pub condition: Exp,
78 pub body: Box<Statement>,
79 pub label: Identifier,
80}
81
82#[derive(Debug, Clone)]
83pub struct For {
84 pub init: AstForInit,
85 pub condition: Option<Exp>,
86 pub post: Option<Exp>,
87 pub body: Box<Statement>,
88 pub label: Identifier,
89}
90
91#[derive(Debug, Clone)]
92pub struct If {
93 pub condition: Exp,
94 pub then: Box<Statement>,
95 pub els: Option<Box<Statement>>,
96}
97
98#[derive(Debug, Clone)]
99pub struct Switch {
100 pub ctrl_exp: Exp,
101 pub body: Box<Statement>,
102 pub cases: Cases,
103 pub label: Identifier,
104}
105
106#[derive(Debug, Clone)]
107pub struct CasedStatement {
108 pub exp: Exp,
109 pub body: Box<Statement>,
110 pub label: Identifier,
111}
112
113#[derive(Debug, Clone)]
114pub struct DCasedStatement {
115 pub body: Box<Statement>,
116 pub label: Identifier,
117}
118
119#[derive(Debug, Clone)]
120pub enum Statement {
121 While(While),
122 DoWhile(DoWhile),
123 For(For),
124 If(If),
125 Switch(Switch),
126 Cased(CasedStatement),
127 DCased(DCasedStatement),
128 Labeled(Identifier, Box<Statement>),
129 Continue(Identifier),
130 Compound(AstBlock),
131 Break(Identifier),
132 Goto(Identifier),
133 Return(Exp),
134 Exp(Exp),
135 Null,
136}
137
138#[derive(Debug, Clone)]
139pub enum AstForInit {
140 InitDecl(VarDec),
141 InitExp(Option<Exp>),
142}
143
144#[derive(Debug, Clone)]
145pub struct ConditionalExp {
146 pub condition: Box<Exp>,
147 pub then: Box<Exp>,
148 pub els: Box<Exp>,
149}
150
151impl From<Exp> for UntypedExp {
152 fn from(value: Exp) -> Self {
153 match value {
154 Exp::Untyped(ue) | Exp::Typed(_, ue) => ue,
155 }
156 }
157}
158
159impl From<UntypedExp> for Exp {
160 fn from(value: UntypedExp) -> Self {
161 Self::Untyped(value)
162 }
163}
164
165#[derive(Debug, Clone)]
166pub enum Exp {
167 Typed(Type, UntypedExp),
168 Untyped(UntypedExp),
169}
170
171impl Deref for Exp {
173 type Target = UntypedExp;
174 fn deref(&self) -> &Self::Target {
175 let (Self::Typed(_, e) | Self::Untyped(e)) = self;
176 e
177 }
178}
179
180impl Exp {
181 pub fn get_type(&self) -> Option<Type> {
182 match self {
183 Self::Typed(t, _) | Self::Untyped(UntypedExp::Cast(t, _)) => Some(t.clone()),
184 Self::Untyped(_) => None,
185 }
186 }
187
188 pub fn set_type(self, t: Type) -> Self {
189 let (Self::Typed(_, e) | Self::Untyped(e)) = self;
190 Self::Typed(t, e)
191 }
192
193 pub fn conditional(c: ConditionalExp) -> Self {
194 Self::Untyped(UntypedExp::Conditional(c))
195 }
196
197 pub fn cast(t: Type, e: Box<Exp>) -> Self {
198 Self::Untyped(UntypedExp::Cast(t, e))
199 }
200
201 pub fn binary(op: AstBinaryOp, src: Box<Exp>, dst: Box<Exp>) -> Self {
202 Self::Untyped(UntypedExp::Binary(op, src, dst))
203 }
204
205 pub fn unary(op: AstUnaryOp, e: Box<Exp>) -> Self {
206 Self::Untyped(UntypedExp::Unary(op, e))
207 }
208
209 pub fn assignment(dst: Box<Exp>, src: Box<Exp>) -> Self {
210 Self::Untyped(UntypedExp::Assignment(dst, src))
211 }
212
213 pub fn call(name: Identifier, args: Vec<Exp>) -> Self {
214 Self::Untyped(UntypedExp::Call(name, args))
215 }
216
217 pub fn var(name: Identifier) -> Self {
218 Self::Untyped(UntypedExp::Var(name))
219 }
220
221 pub fn constant(cs: AstConst) -> Self {
222 Self::Untyped(UntypedExp::Constant(cs))
223 }
224
225 pub fn constant_from_unsigned(u: u64) -> Self {
226 let cs = if u < u64::from(u32::MAX) {
227 AstConst::UInt(u as u32)
228 } else {
229 AstConst::ULong(u)
230 };
231
232 Self::Untyped(UntypedExp::Constant(cs))
233 }
234
235 pub fn constant_from_signed(i: i64) -> Self {
236 let cs = if i < i64::from(i32::MAX) {
237 AstConst::Int(i as i32)
238 } else {
239 AstConst::Long(i)
240 };
241
242 Self::Untyped(UntypedExp::Constant(cs))
243 }
244}
245
246#[derive(Debug, Clone)]
247pub enum UntypedExp {
248 Conditional(ConditionalExp),
249 Cast(Type, Box<Exp>),
250 Binary(AstBinaryOp, Box<Exp>, Box<Exp>),
251 Unary(AstUnaryOp, Box<Exp>),
252 Assignment(Box<Exp>, Box<Exp>),
253 Call(Identifier, Vec<Exp>),
254 Var(Identifier),
255 Constant(AstConst),
256}
257
258#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
259pub enum AstConst {
260 Int(i32),
261 Long(i64),
262 UInt(u32),
263 ULong(u64),
264}
265
266impl AstConst {
267 pub fn is_negative(&self) -> bool {
268 match self {
269 Self::Int(i) => *i < 0,
270 Self::Long(l) => *l < 0,
271 Self::UInt(_) | Self::ULong(_) => false,
272 }
273 }
274
275 pub fn abs(&self) -> Self {
276 match self {
277 Self::Int(i) => Self::Int(i32::abs(*i)),
278 Self::Long(l) => Self::Long(i64::abs(*l)),
279 Self::UInt(_) | Self::ULong(_) => *self,
280 }
281 }
282
283 #[allow(clippy::cast_possible_truncation)]
284 pub fn new_signed(t: &Type, v: i64) -> Option<Self> {
285 match t {
286 Type::Int => Some(AstConst::Int(v as i32)),
287 Type::Long => Some(AstConst::Long(v)),
288 Type::Fun { .. } | Type::ULong | Type::UInt => None,
289 }
290 }
291
292 pub fn new_unsigned(t: &Type, v: u64) -> Option<Self> {
293 match t {
294 Type::UInt => Some(AstConst::UInt(v as u32)),
295 Type::ULong => Some(AstConst::ULong(v)),
296 Type::Fun { .. } | Type::Long | Type::Int => None,
297 }
298 }
299
300 pub fn get_type(&self) -> Type {
301 match self {
302 Self::Int(_) => Type::Int,
303 Self::Long(_) => Type::Long,
304 Self::ULong(_) => Type::ULong,
305 Self::UInt(_) => Type::UInt,
306 }
307 }
308
309 fn get_value_i64(&self) -> Option<i64> {
310 match self {
311 Self::Int(i) => Some(i64::from(*i)),
312 Self::Long(i) => Some(*i),
313 Self::UInt(_) | Self::ULong(_) => None,
314 }
315 }
316
317 fn get_value_u64(&self) -> Option<u64> {
318 match self {
319 Self::UInt(u) => Some(u64::from(*u)),
320 Self::ULong(u) => Some(*u),
321 Self::Int(_) | Self::Long(_) => None,
322 }
323 }
324
325 #[allow(clippy::cast_possible_truncation)]
326 pub fn convert_to(&self, t: &Type) -> Self {
327 let self_type = self.get_type();
328 if t == &self_type {
329 return *self;
330 }
331 if self_type.is_signed() {
332 let value = self.get_value_i64().unwrap();
333 match t {
334 Type::Int => AstConst::Int(value as i32),
335 Type::UInt => AstConst::UInt(value as u32),
336 Type::ULong => AstConst::ULong(value as u64),
337 Type::Long => AstConst::Long(value),
338 Type::Fun { .. } => *self,
339 }
340 } else {
341 let value = self.get_value_u64().unwrap();
342 match t {
343 Type::Int => AstConst::Int(value as i32),
344 Type::UInt => AstConst::UInt(value as u32),
345 Type::Long => AstConst::Long(value as i64),
346 Type::ULong => AstConst::ULong(value as u64),
347 Type::Fun { .. } => *self,
348 }
349 }
350 }
351}
352
353impl std::fmt::Display for AstConst {
354 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
355 match self {
356 AstConst::Int(i) => write!(f, "{i}"),
357 AstConst::Long(i) => write!(f, "{i}"),
358 AstConst::ULong(u) => write!(f, "{u}"),
359 AstConst::UInt(u) => write!(f, "{u}"),
360 }
361 }
362}
363
364#[derive(Debug, Copy, Clone)]
365pub enum AstBinaryOp {
366 Add,
367 Multiply,
368 Div,
369 Mod,
370 Substract,
371 LogicalAnd,
372 LogicalOr,
373 IsEqual,
374 IsNotEqual,
375 LessThan,
376 LessOrEqual,
377 GreaterThan,
378 GreaterOrEqual,
379 BitwiseAnd,
380 BitwiseOr,
381 BitwiseXor,
382 ShiftLeft,
383 ShiftRight,
384}
385
386#[derive(Debug, Clone, Copy)]
387pub enum AstUnaryOp {
388 Complement,
389 Negate,
390 LogicalNot,
391 PostfixDecrement,
392 PrefixDecrement,
393 PostfixIncrement,
394 PrefixIncrement,
395}
396
397impl AstUnaryOp {
398 #[inline]
399 pub fn is_prefix_incdec(&self) -> bool {
400 matches!(self, Self::PrefixIncrement | Self::PrefixDecrement)
401 }
402
403 #[inline]
404 pub fn is_postfix_incdec(&self) -> bool {
405 matches!(self, Self::PostfixIncrement | Self::PostfixDecrement)
406 }
407
408 #[inline]
409 pub fn is_incdec(&self) -> bool {
410 self.is_prefix_incdec() || self.is_postfix_incdec()
411 }
412}
413
414impl AstBinaryOp {
415 pub fn is_shift(&self) -> bool {
416 matches!(self, Self::ShiftLeft | Self::ShiftRight)
417 }
418 pub fn is_logical(&self) -> bool {
419 matches!(self, Self::LogicalAnd | Self::LogicalOr)
420 }
421 pub fn is_eq(&self) -> bool {
422 matches!(
423 self,
424 Self::IsEqual
425 | Self::IsNotEqual
426 | Self::LessThan
427 | Self::GreaterThan
428 | Self::LessOrEqual
429 | Self::GreaterOrEqual
430 )
431 }
432}
433
434impl Type {
435 #[inline]
436 pub fn is_function(&self) -> bool {
437 matches!(self, Type::Fun { .. })
438 }
439
440 pub fn get_ptypes(&self) -> Option<&Vec<Type>> {
441 match self {
442 Self::Fun { ptypes, .. } => Some(ptypes),
443 _ => None,
444 }
445 }
446
447 pub fn get_rtype(&self) -> Option<&Type> {
448 match self {
449 Self::Fun { return_type, .. } => Some(return_type),
450 _ => None,
451 }
452 }
453
454 pub fn get_size(&self) -> u64 {
455 match self {
456 Self::Int | Self::UInt => 4,
457 Self::Long | Self::ULong => 8,
458 Self::Fun { .. } => panic!("Attempt to get size of function type"),
459 }
460 }
461
462 pub fn get_common(t1: &Self, t2: &Self) -> Self {
463 let t1_size = t1.get_size();
464 let t2_size = t2.get_size();
465 if t1 == t2 {
466 t1.clone()
467 } else if t1_size == t2_size {
468 if t1.is_signed() {
469 t2.clone()
470 } else {
471 t1.clone()
472 }
473 } else if t1_size > t2_size {
474 t1.clone()
475 } else {
476 t2.clone()
477 }
478 }
479
480 #[inline]
481 pub fn is_signed(&self) -> bool {
482 matches!(self, Self::Int | Self::Long)
483 }
484
485 #[inline]
486 pub fn is_unsigned(&self) -> bool {
487 matches!(self, Self::UInt | Self::ULong)
488 }
489}
490
491impl UntypedExp {
492 pub fn is_var(&self) -> bool {
493 matches!(self, Self::Var(_))
494 }
495}
496
497impl StorageClass {
498 pub fn is_static(&self) -> bool {
499 matches!(self, Self::Static)
500 }
501
502 pub fn is_extern(&self) -> bool {
503 matches!(self, Self::Extern)
504 }
505
506 pub fn is_auto(&self) -> bool {
507 matches!(self, Self::Auto)
508 }
509}