machine_check_common/iir/
expr.rs

1pub mod call;
2pub mod op;
3
4use std::fmt::Debug;
5
6use mck::{abstr::AbstractValue, refin::RefinementValue};
7use serde::{Deserialize, Serialize};
8
9use crate::iir::{
10    context::IFnContext, expr::call::IExprCall, join_limited, variable::IVarId, IAbstr, IRefin,
11};
12
13#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub enum IExpr {
15    Move(IVarId),
16    Call(IExprCall),
17    Reference(IExprReference),
18    Field(IExprField),
19    Struct(IExprStruct),
20}
21
22#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
23pub struct IExprField {
24    pub base: IVarId,
25    pub member_index: usize,
26}
27
28#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
29pub struct IExprStruct {
30    pub fields: Vec<IVarId>,
31}
32
33#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
34pub enum IExprReference {
35    Ident(IVarId),
36    Field(IExprField),
37}
38
39impl IExpr {
40    pub fn forward_interpret(&self, context: &IFnContext, abstr: &IAbstr) -> Option<AbstractValue> {
41        match self {
42            IExpr::Move(var_id) => Some(abstr.value(*var_id).clone()),
43            IExpr::Call(expr_call) => expr_call.forward_interpret(context, abstr),
44            IExpr::Reference(expr_reference) => {
45                // copies instead of referencing for simplicity
46                match expr_reference {
47                    IExprReference::Ident(var_id) => Some(abstr.value(*var_id).clone()),
48                    IExprReference::Field(expr_field) => expr_field.forward_interpret(abstr),
49                }
50            }
51            IExpr::Field(expr_field) => expr_field.forward_interpret(abstr),
52            IExpr::Struct(expr_struct) => {
53                let mut values = Vec::new();
54
55                for field in expr_struct.fields.iter().cloned() {
56                    values.push(abstr.value(field).clone());
57                }
58
59                Some(AbstractValue::Struct(values))
60            }
61        }
62    }
63
64    pub fn backward_interpret(
65        &self,
66        context: &IFnContext,
67        abstr: &IAbstr,
68        refin: &mut IRefin,
69        later: RefinementValue,
70    ) {
71        match self {
72            IExpr::Move(var_id) => {
73                // propagate the later value to earlier
74                join_limited(abstr, refin, *var_id, later);
75            }
76            IExpr::Call(expr_call) => expr_call.backward_interpret(context, abstr, refin, later),
77            IExpr::Reference(expr_reference) => {
78                // copies instead of referencing for simplicity
79                match expr_reference {
80                    IExprReference::Ident(var_id) => {
81                        join_limited(abstr, refin, *var_id, later);
82                    }
83                    IExprReference::Field(expr_field) => {
84                        expr_field.backward_interpret(abstr, refin, later);
85                    }
86                }
87            }
88            IExpr::Field(expr_field) => {
89                expr_field.backward_interpret(abstr, refin, later);
90            }
91            IExpr::Struct(expr_struct) => {
92                let later_fields = later.expect_struct();
93                assert_eq!(expr_struct.fields.len(), later_fields.len());
94
95                // limited-join all the fields comprising the struct
96                for (field_id, field_earlier) in expr_struct.fields.iter().zip(later_fields) {
97                    join_limited(abstr, refin, *field_id, field_earlier.clone());
98                }
99            }
100        }
101    }
102}
103
104impl IExprField {
105    pub fn forward_interpret(&self, abstr: &IAbstr) -> Option<AbstractValue> {
106        let base = abstr.value(self.base).expect_struct();
107        Some(base[self.member_index].clone())
108    }
109
110    fn backward_interpret(&self, abstr: &IAbstr, refin: &mut IRefin, later: RefinementValue) {
111        // limited-join the part of the struct
112        let mut base = if let Some(base) = refin.value_opt(self.base) {
113            base.clone()
114        } else {
115            RefinementValue::unmarked_for(abstr.value(self.base))
116        };
117
118        let base_fields = base.expect_struct_mut();
119        let member = &mut base_fields[self.member_index];
120        *member = mck::misc::Join::join(later, member);
121
122        join_limited(abstr, refin, self.base, base);
123    }
124}
125
126impl Debug for IExpr {
127    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128        match self {
129            IExpr::Move(ident) => write!(f, "{:?}", ident),
130            IExpr::Call(call) => write!(f, "{:?}", call),
131            IExpr::Reference(reference) => write!(f, "{:?}", reference),
132            IExpr::Field(field) => write!(f, "{:?}", field),
133            IExpr::Struct(expr_struct) => write!(f, "{:?}", expr_struct),
134        }
135    }
136}
137
138impl Debug for IExprField {
139    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140        write!(f, "{:?}.{:?}", self.base, self.member_index)
141    }
142}
143
144impl Debug for IExprStruct {
145    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146        write!(f, "{{ ")?;
147        for (index, field) in self.fields.iter().enumerate() {
148            write!(f, "{}: {:?}, ", index, field)?;
149        }
150        write!(f, " }}")
151    }
152}
153
154impl Debug for IExprReference {
155    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156        write!(f, "&")?;
157        match self {
158            Self::Ident(ident) => write!(f, "{:?}", ident),
159            Self::Field(field) => field.fmt(f),
160        }
161    }
162}