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 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 if width >= *j && *j >= *i {
227 let new_width = j - i;
228 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}