nlcc/
ast.rs

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
171// Reminder: &Exp will act like &UntypedExp
172impl 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}