bitsy_lang/sim/
eval.rs

1use super::*;
2use crate::sim::Sim;
3use crate::sim::Value;
4
5impl Expr {
6    pub fn eval(&self, bitsy: &Sim) -> Value {
7        self.eval_with_ctx(bitsy, Context::empty())
8    }
9
10    fn eval_with_ctx(&self, bitsy: &Sim, ctx: Context<Path, Value>) -> Value {
11        match self {
12            Expr::Reference(_loc, _typ, path) => {
13                if let Some(value) = ctx.lookup(path) {
14                    value.clone()
15                } else {
16                    bitsy.peek(path.clone())
17                }
18            }
19            Expr::Net(_loc, _typ, netid) => bitsy.peek_net(*netid),
20            Expr::Word(_loc, typ, _width, value) => {
21                if let Type::Word(width) = typ.get().unwrap() {
22                    Value::Word(*width, *value)
23                } else {
24                    unreachable!()
25                }
26            },
27            Expr::Enum(_loc, _typ, typedef, name) => Value::Enum(typedef.clone(), name.clone()),
28            Expr::Ctor(_loc, _typ, name, es) => {
29                let values: Vec<Value> = es.iter().map(|e| e.eval_with_ctx(bitsy, ctx.clone())).collect();
30                Value::Ctor(name.to_string(), values)
31            },
32            Expr::Struct(_loc, typ, fields) => {
33                // TODO canonicalize ordering
34                let mut field_values = vec![];
35                for (name, e) in fields {
36                    let value = e.eval_with_ctx(bitsy, ctx.clone());
37                    field_values.push((name.to_string(), value));
38                }
39                Value::Struct(typ.get().unwrap().clone(), field_values)
40            },
41            Expr::Let(_loc, _typ, name, e, b) => {
42                let v = e.eval_with_ctx(bitsy, ctx.clone());
43                b.eval_with_ctx(bitsy, ctx.extend(name.clone().into(), v))
44            },
45            Expr::UnOp(_loc, _typ, op, e) => {
46                match (op, e.eval_with_ctx(bitsy, ctx.clone())) {
47                    (UnOp::Not, Value::Word(n, v)) => Value::Word(n, (!v) & ((1 << n) - 1)),
48                    _ => Value::X,
49                }
50            },
51            Expr::BinOp(_loc, _typ, op, e1, e2) => {
52                match (op, e1.eval_with_ctx(bitsy, ctx.clone()), e2.eval_with_ctx(bitsy, ctx.clone())) {
53                    (BinOp::Add, Value::X, _other) => Value::X,
54                    (BinOp::Add, _other, Value::X) => Value::X,
55                    (BinOp::Add, Value::Word(w, a),  Value::Word(_w, b)) => Value::Word(w, a.wrapping_add(b) % (1 << w)),
56                    (BinOp::AddCarry, Value::Word(w, a),  Value::Word(_w, b)) => {
57                        let new_w = w + 1;
58                        Value::Word(new_w, a.wrapping_add(b) % (1 << new_w))
59                    },
60                    (BinOp::Sub, Value::Word(w, a),  Value::Word(_w, b)) => Value::Word(w, a.wrapping_sub(b) % (1 << w)),
61                    (BinOp::And, Value::Word(w, a),  Value::Word(_w, b)) => Value::Word(w, a & b),
62                    (BinOp::Or,  Value::Word(w, a),  Value::Word(_w, b)) => Value::Word(w, a | b),
63                    (BinOp::Eq,  Value::Word(_w, a), Value::Word(_v, b)) => (a == b).into(),
64                    (BinOp::Eq,  Value::Enum(_typedef, a), Value::Enum(_typedef2, b)) => (a == b).into(),
65                    (BinOp::Lt,  Value::Word(_w, a), Value::Word(_v, b)) => (a < b).into(),
66                    (BinOp::Neq, Value::Word(_w, a), Value::Word(_v, b)) => (a != b).into(),
67                    (BinOp::Xor, Value::Word(n, a),  Value::Word(_m, b)) => Value::Word(n, a ^ b),
68                    _ => Value::X,
69                }
70            },
71            Expr::If(_loc, _typ, cond, e1, e2) => {
72                let cond_v = cond.eval_with_ctx(bitsy, ctx.clone());
73                let v1 = e1.eval_with_ctx(bitsy, ctx.clone());
74                let v2 = e2.eval_with_ctx(bitsy, ctx.clone());
75                if cond_v.is_x() || v1.is_x() || v2.is_x() {
76                    return Value::X;
77                }
78                match cond_v {
79                    Value::Word(1, 1) => v1,
80                    Value::Word(1, 0) => v2,
81                    _ => Value::X,
82                }
83            },
84            Expr::Match(_loc, _typ, subject, arms) => {
85                let subject_value = subject.eval_with_ctx(bitsy, ctx.clone());
86                if subject_value.is_x() {
87                    return Value::X;
88                }
89
90                for MatchArm(pat, e) in arms {
91                    if let Some(new_ctx) = pat.bind(&subject_value, ctx.clone()) {
92                        let e_value = e.eval_with_ctx(bitsy, new_ctx);
93                        return e_value;
94                    }
95                }
96                panic!("No match arm matched")
97            },
98            Expr::Mux(_loc, _typ, cond, e1, e2) => {
99                let cond_v = cond.eval_with_ctx(bitsy, ctx.clone());
100                let v1 = e1.eval_with_ctx(bitsy, ctx.clone());
101                let v2 = e2.eval_with_ctx(bitsy, ctx.clone());
102                if cond_v.is_x() || v1.is_x() || v2.is_x() {
103                    return Value::X;
104                }
105                match cond_v {
106                    Value::Word(1, 1) => v1,
107                    Value::Word(1, 0) => v2,
108                    _ => Value::X,
109                }
110            },
111            Expr::Cat(_loc, _typ, es) => {
112                let mut cat_width: u64 = 0;
113                let mut cat_val: u64 = 0;
114                let mut wss: Vec<Value> = vec![];
115                for v in es.iter().map(|e| e.eval_with_ctx(bitsy, ctx.clone())).rev() {
116                    if let Value::X = v {
117                        return Value::X;
118                    } else if let Value::Word(width, val) = v {
119                        cat_val |= val << cat_width;
120                        cat_width += width;
121                    } else if let Value::Vec(ws) = v {
122                        wss.extend(ws.into_iter().rev());
123                    } else {
124                        panic!("Can't cat on a non-Word");
125                    }
126                }
127                if wss.len() == 0 {
128                    Value::Word(cat_width, cat_val)
129                } else {
130                    Value::Vec(wss.into_iter().rev().collect())
131                }
132            },
133            Expr::Sext(_loc, typ, e) => {
134                let n = if let Type::Word(n) = typ.get().unwrap() {
135                    n
136                } else {
137                    unreachable!()
138                };
139                match e.eval_with_ctx(bitsy, ctx.clone()) {
140                    Value::X => Value::X,
141                    Value::Word(0, _x) => panic!("Can't sext a Word<0>"),
142                    Value::Word(w, x) => {
143                        if w <= *n {
144                            let is_negative = x & (1 << (w - 1)) > 0;
145                            if is_negative {
146                                let flips = ((1 << (n - w)) - 1) << w;
147                                Value::Word(*n, flips | x)
148                            } else {
149                                Value::Word(*n, x)
150                            }
151                        } else {
152                            panic!("Can't sext a Word<{w}> to Word<{n}> because {w} > {n}.")
153                        }
154                    },
155                    Value::Vec(_vs) => panic!("Can't sext a Vec"),
156                    Value::Enum(typedef, _name) => panic!("Can't sext a {}", typedef.name()),
157                    _ => panic!("Can't sext {self:?}"),
158                }
159            }
160            Expr::ToWord(_loc, _typ, e) => {
161                let v = e.eval_with_ctx(bitsy, ctx.clone());
162                match v {
163                    Value::X => Value::X,
164                    Value::Enum(typ, name) => {
165                        if let Type::Enum(typ) = typ {
166                            Value::Word(typ.bitwidth(), typ.value_of(&name).unwrap())
167                        } else {
168                            panic!();
169                        }
170                    },
171                    _ => panic!("Can only call word() on enum values, but found {v:?}"),
172                }
173            },
174            Expr::Vec(_loc, _typ, es) => {
175                let mut vs = vec![];
176                for v in es.iter().map(|e| e.eval_with_ctx(bitsy, ctx.clone())) {
177                    if let Value::X = v {
178                        return Value::X;
179                    } else {
180                        vs.push(v.clone());
181                    }
182                }
183                Value::Vec(vs)
184            },
185            Expr::IdxField(_loc, _typ, e, field) => {
186                let value = e.eval_with_ctx(bitsy, ctx.clone());
187                if let Value::X = value {
188                    Value::X
189                } else if let Value::Struct(_typ, fields) = e.eval_with_ctx(bitsy, ctx.clone()) {
190                    for (fieldname, fieldval) in fields {
191                        if *field == fieldname {
192                            return fieldval;
193                        }
194                    }
195                    panic!();
196                } else {
197                    panic!();
198                }
199            },
200            Expr::Idx(_loc, _typ, e, i) => {
201                let value = e.eval_with_ctx(bitsy, ctx.clone());
202                if let Value::X = value {
203                    Value::X
204                } else if let Value::Word(width, val) = value {
205                    if *i < width {
206                        Value::Word(1, (val >> i) & 1)
207                    } else {
208                        panic!("Index at {i} out of range (width {width})")
209                    }
210                } else if let Value::Vec(vs) = value {
211                    if *i < vs.len().try_into().unwrap() {
212                        vs[*i as usize].clone()
213                    } else {
214                        panic!("Index at {i} out of range (length {})", vs.len())
215                    }
216                } else {
217                        panic!("Index with invalid value: {value:?}")
218                }
219            },
220            Expr::IdxRange(_loc, _typ, e, j, i) => {
221                let value = e.eval_with_ctx(bitsy, ctx.clone());
222                if let Value::X = value {
223                    Value::X
224                } else if let Value::Word(width, val) = value {
225                    // TODO make errors better
226                    if width >= *j && *j >= *i {
227                        let new_width = j - i;
228                        // eg, if new_width = 3, shift over 3 to get 0b1000
229                        // then subtract 1 to get 0b01111
230                        let mask = (1 << new_width) - 1;
231                        Value::Word(new_width, (val >> i) & mask)
232                    } else {
233                        panic!("Index {j}..{i} out of range (width {width})")
234                    }
235                } else if let Value::Vec(vs) = value {
236                    let width = vs.len();
237                    if j <= i && *i <= width as u64 {
238                        Value::Vec(vs[*j as usize..*i as usize].to_vec())
239                    } else {
240                        panic!("Index {j}..{i} out of range (length {width})")
241                    }
242                } else {
243                    panic!("Can't index into value: {value:?}")
244                }
245            },
246            Expr::Call(_loc, _typ, fndef, es) => {
247                assert_eq!(fndef.args.len(), es.len());
248                let mut new_ctx = ctx.clone();
249
250                for ((arg_name, _arg_typ), e) in fndef.args.iter().zip(es.iter()) {
251                    let v = e.eval_with_ctx(bitsy, ctx.clone());
252                    new_ctx = new_ctx.extend(arg_name.clone().into(), v);
253                }
254
255                fndef.body.eval_with_ctx(bitsy, new_ctx)
256            },
257            Expr::Hole(_loc, _typ, opt_name) => {
258                match opt_name {
259                    Some(name) => panic!("EVALUATED A HOLE: ?{name}"),
260                    None => panic!("EVALUATED A HOLE"),
261                }
262            },
263        }
264    }
265}
266
267impl Pat {
268    fn bind(&self, v: &Value, ctx: Context<Path, Value>) -> Option<Context<Path, Value>> {
269        match self {
270            Pat::At(ctor, pats) => {
271                match v {
272                    Value::X => None,
273                    Value::Word(_w, _n) => None,
274                    Value::Vec(_vs) => None,
275                    Value::Ctor(v_ctor, vs) => {
276                        if ctor == v_ctor {
277                            assert_eq!(pats.len(), vs.len());
278                            let mut ctx_result = ctx.clone();
279                            for (pat, v) in pats.iter().zip(vs.iter()) {
280                                if let Some(ctx) = pat.bind(v, ctx.clone()) {
281                                    ctx_result = ctx;
282                                } else {
283                                    return None;
284                                }
285                            }
286                            Some(ctx_result)
287                        } else {
288                            None
289                        }
290                    },
291                    Value::Enum(_typ, val) => {
292                        assert_eq!(pats.len(), 0);
293                        if ctor == val {
294                            Some(ctx)
295                        } else {
296                            None
297                        }
298                    },
299                    Value::Struct(_typ, _fields) => None,
300                }
301            },
302            Pat::Bind(x) => Some(ctx.extend(x.clone().into(), v.clone())),
303            Pat::Otherwise => Some(ctx),
304        }
305    }
306}