Skip to main content

litex/runtime/
runtime_resolve_obj.rs

1use crate::common::count_range_integer::{
2    count_closed_range_integer_endpoints, count_half_open_range_integer_endpoints,
3};
4use crate::prelude::*;
5use crate::verify::{compare_normalized_number_str_to_zero, NumberCompareResult};
6
7impl Runtime {
8    pub fn resolve_obj_to_number(&self, obj: &Obj) -> Option<Number> {
9        if let Some(number) = obj.evaluate_to_normalized_decimal_number() {
10            return Some(number);
11        }
12        let obj_key = obj.to_string();
13        if let Some(number) = self.get_object_equal_to_normalized_decimal_number(&obj_key) {
14            return Some(number);
15        }
16        None
17    }
18
19    pub fn resolve_obj_to_number_resolved(&self, obj: &Obj) -> Option<Number> {
20        self.resolve_obj_to_number(&self.resolve_obj(obj))
21    }
22
23    // After resolving children, fold literals; if still not a number, use
24    // `known_objs_equal_to_normalized_decimal_number` so e.g. `a - b` becomes `100` when that
25    // binding exists, then outer `(... - 10)` can evaluate (used by equality `calculation`).
26    fn resolve_obj_try_fold_arithmetic(&self, result: Obj) -> Obj {
27        if let Some(calculated) = result.evaluate_to_normalized_decimal_number() {
28            return calculated.into();
29        }
30        if let Some(n) = self.resolve_obj_to_number(&result) {
31            return n.into();
32        }
33        result
34    }
35
36    pub fn resolve_obj(&self, obj: &Obj) -> Obj {
37        if let Some(number) = self.resolve_obj_to_number(obj) {
38            return number.into();
39        }
40        match obj {
41            Obj::Number(number) => number.clone().into(),
42            Obj::Add(add) => {
43                let result: Obj =
44                    Add::new(self.resolve_obj(&add.left), self.resolve_obj(&add.right)).into();
45                self.resolve_obj_try_fold_arithmetic(result)
46            }
47            Obj::Sub(sub) => {
48                let result: Obj =
49                    Sub::new(self.resolve_obj(&sub.left), self.resolve_obj(&sub.right)).into();
50                self.resolve_obj_try_fold_arithmetic(result)
51            }
52            Obj::Mul(mul) => {
53                let result: Obj =
54                    Mul::new(self.resolve_obj(&mul.left), self.resolve_obj(&mul.right)).into();
55                self.resolve_obj_try_fold_arithmetic(result)
56            }
57            Obj::Mod(mod_obj) => {
58                let result: Obj = Mod::new(
59                    self.resolve_obj(&mod_obj.left),
60                    self.resolve_obj(&mod_obj.right),
61                )
62                .into();
63                self.resolve_obj_try_fold_arithmetic(result)
64            }
65            Obj::Pow(pow) => {
66                let result: Obj =
67                    Pow::new(self.resolve_obj(&pow.base), self.resolve_obj(&pow.exponent)).into();
68                self.resolve_obj_try_fold_arithmetic(result)
69            }
70            Obj::Div(div) => {
71                let result: Obj =
72                    Div::new(self.resolve_obj(&div.left), self.resolve_obj(&div.right)).into();
73                self.resolve_obj_try_fold_arithmetic(result)
74            }
75            Obj::Abs(a) => {
76                let result: Obj = Abs::new(self.resolve_obj(&a.arg)).into();
77                self.resolve_obj_try_fold_arithmetic(result)
78            }
79            Obj::Max(m) => {
80                let result: Obj =
81                    Max::new(self.resolve_obj(&m.left), self.resolve_obj(&m.right)).into();
82                self.resolve_obj_try_fold_arithmetic(result)
83            }
84            Obj::Min(m) => {
85                let result: Obj =
86                    Min::new(self.resolve_obj(&m.left), self.resolve_obj(&m.right)).into();
87                self.resolve_obj_try_fold_arithmetic(result)
88            }
89            Obj::Log(l) => {
90                let result: Obj =
91                    Log::new(self.resolve_obj(&l.base), self.resolve_obj(&l.arg)).into();
92                self.resolve_obj_try_fold_arithmetic(result)
93            }
94            Obj::FiniteSeqSet(fs) => {
95                FiniteSeqSet::new(self.resolve_obj(&fs.set), self.resolve_obj(&fs.n)).into()
96            }
97            Obj::SeqSet(ss) => SeqSet::new(self.resolve_obj(&ss.set)).into(),
98            Obj::MatrixSet(ms) => MatrixSet::new(
99                self.resolve_obj(&ms.set),
100                self.resolve_obj(&ms.row_len),
101                self.resolve_obj(&ms.col_len),
102            )
103            .into(),
104            Obj::FiniteSeqListObj(list) => {
105                let objs: Vec<Obj> = list.objs.iter().map(|o| self.resolve_obj(o)).collect();
106                FiniteSeqListObj::new(objs).into()
107            }
108            Obj::MatrixListObj(matrix) => {
109                let rows: Vec<Vec<Obj>> = matrix
110                    .rows
111                    .iter()
112                    .map(|row| row.iter().map(|o| self.resolve_obj(o)).collect())
113                    .collect();
114                MatrixListObj::new(rows).into()
115            }
116            Obj::FnObj(fn_obj) => {
117                if fn_obj.body.len() == 1 && fn_obj.body[0].len() == 1 {
118                    let head_key = fn_obj.head.to_string();
119                    if let Some(list) = self.get_obj_equal_to_finite_seq_list(&head_key) {
120                        let arg = self.resolve_obj(fn_obj.body[0][0].as_ref());
121                        if let Some(ix) = self.resolve_obj_to_number(&arg) {
122                            if let Ok(one_based) = ix.normalized_value.parse::<usize>() {
123                                if one_based >= 1 && one_based <= list.objs.len() {
124                                    return (*list.objs[one_based - 1]).clone();
125                                }
126                            }
127                        }
128                    }
129                }
130                if fn_obj.body.len() == 2 && fn_obj.body[0].len() == 1 && fn_obj.body[1].len() == 1
131                {
132                    let head_key = fn_obj.head.to_string();
133                    if let Some(mat) = self.get_obj_equal_to_matrix_list(&head_key) {
134                        let r_arg = self.resolve_obj(fn_obj.body[0][0].as_ref());
135                        let c_arg = self.resolve_obj(fn_obj.body[1][0].as_ref());
136                        if let (Some(rn), Some(cn)) = (
137                            self.resolve_obj_to_number(&r_arg),
138                            self.resolve_obj_to_number(&c_arg),
139                        ) {
140                            if let (Ok(r1), Ok(c1)) = (
141                                rn.normalized_value.parse::<usize>(),
142                                cn.normalized_value.parse::<usize>(),
143                            ) {
144                                if r1 >= 1
145                                    && r1 <= mat.rows.len()
146                                    && c1 >= 1
147                                    && c1 <= mat.rows[r1 - 1].len()
148                                {
149                                    return (*mat.rows[r1 - 1][c1 - 1]).clone();
150                                }
151                            }
152                        }
153                    }
154                }
155                if fn_obj.body.len() == 1 && fn_obj.body[0].len() == 2 {
156                    let head_key = fn_obj.head.to_string();
157                    if let Some(mat) = self.get_obj_equal_to_matrix_list(&head_key) {
158                        let r_arg = self.resolve_obj(fn_obj.body[0][0].as_ref());
159                        let c_arg = self.resolve_obj(fn_obj.body[0][1].as_ref());
160                        if let (Some(rn), Some(cn)) = (
161                            self.resolve_obj_to_number(&r_arg),
162                            self.resolve_obj_to_number(&c_arg),
163                        ) {
164                            if let (Ok(r1), Ok(c1)) = (
165                                rn.normalized_value.parse::<usize>(),
166                                cn.normalized_value.parse::<usize>(),
167                            ) {
168                                if r1 >= 1
169                                    && r1 <= mat.rows.len()
170                                    && c1 >= 1
171                                    && c1 <= mat.rows[r1 - 1].len()
172                                {
173                                    return (*mat.rows[r1 - 1][c1 - 1]).clone();
174                                }
175                            }
176                        }
177                    }
178                }
179                if let Some(number) = self.resolve_obj_to_number(obj) {
180                    number.into()
181                } else {
182                    obj.clone()
183                }
184            }
185            Obj::Atom(AtomObj::Identifier(_)) | Obj::Atom(AtomObj::IdentifierWithMod(_)) => {
186                if let Some(number) = self.resolve_obj_to_number(obj) {
187                    number.into()
188                } else {
189                    obj.clone()
190                }
191            }
192            Obj::Count(count) => match &*count.set {
193                Obj::ListSet(list_set) => Number::new(list_set.list.len().to_string()).into(),
194                Obj::ClosedRange(cr) => {
195                    if let (Some(a_num), Some(b_num)) = (
196                        self.resolve_obj_to_number_resolved(cr.start.as_ref()),
197                        self.resolve_obj_to_number_resolved(cr.end.as_ref()),
198                    ) {
199                        if let Some(n) = count_closed_range_integer_endpoints(&a_num, &b_num) {
200                            return n.into();
201                        }
202                    }
203                    obj.clone()
204                }
205                Obj::Range(r) => {
206                    if let (Some(a_num), Some(b_num)) = (
207                        self.resolve_obj_to_number_resolved(r.start.as_ref()),
208                        self.resolve_obj_to_number_resolved(r.end.as_ref()),
209                    ) {
210                        if let Some(n) = count_half_open_range_integer_endpoints(&a_num, &b_num) {
211                            return n.into();
212                        }
213                    }
214                    obj.clone()
215                }
216                _ => obj.clone(),
217            },
218            Obj::TupleDim(dim) => match &*dim.arg {
219                Obj::Tuple(tuple) => Number::new(tuple.args.len().to_string()).into(),
220                _ => obj.clone(),
221            },
222            Obj::CartDim(cart_dim) => match &*cart_dim.set {
223                Obj::Cart(cart) => Number::new(cart.args.len().to_string()).into(),
224                _ => obj.clone(),
225            },
226            Obj::Proj(proj) => match &*proj.set {
227                Obj::Cart(cart) => {
228                    let projection_index_number = self.resolve_obj_to_number(&proj.dim);
229                    if let Some(projection_index_number) = projection_index_number {
230                        let projection_index_parsed_result =
231                            projection_index_number.normalized_value.parse::<usize>();
232                        if let Ok(projection_index_one_based) = projection_index_parsed_result {
233                            if projection_index_one_based >= 1
234                                && projection_index_one_based <= cart.args.len()
235                            {
236                                return (*cart.args[projection_index_one_based - 1]).clone();
237                            }
238                        }
239                    }
240                    obj.clone()
241                }
242                _ => {
243                    let known_cart_obj = self.get_object_equal_to_cart(&proj.set.to_string());
244                    if let Some(known_cart_obj) = known_cart_obj {
245                        let projection_index_number = self.resolve_obj_to_number(&proj.dim);
246                        if let Some(projection_index_number) = projection_index_number {
247                            let projection_index_parsed_result =
248                                projection_index_number.normalized_value.parse::<usize>();
249                            if let Ok(projection_index_one_based) = projection_index_parsed_result {
250                                if projection_index_one_based >= 1
251                                    && projection_index_one_based <= known_cart_obj.args.len()
252                                {
253                                    return (*known_cart_obj.args[projection_index_one_based - 1])
254                                        .clone();
255                                }
256                            }
257                        }
258                    }
259                    obj.clone()
260                }
261            },
262            Obj::ObjAtIndex(obj_at_index) => match &*obj_at_index.obj {
263                Obj::Tuple(tuple) => {
264                    let tuple_index_number = self.resolve_obj_to_number(&obj_at_index.index);
265                    if let Some(tuple_index_number) = tuple_index_number {
266                        let tuple_index_parsed_result =
267                            tuple_index_number.normalized_value.parse::<usize>();
268                        if let Ok(tuple_index_one_based) = tuple_index_parsed_result {
269                            if tuple_index_one_based >= 1
270                                && tuple_index_one_based <= tuple.args.len()
271                            {
272                                return (*tuple.args[tuple_index_one_based - 1]).clone();
273                            }
274                        }
275                    }
276                    obj.clone()
277                }
278                Obj::FiniteSeqListObj(list) => {
279                    let ix = self.resolve_obj_to_number(&obj_at_index.index);
280                    if let Some(ix) = ix {
281                        if let Ok(one_based) = ix.normalized_value.parse::<usize>() {
282                            if one_based >= 1 && one_based <= list.objs.len() {
283                                return (*list.objs[one_based - 1]).clone();
284                            }
285                        }
286                    }
287                    obj.clone()
288                }
289                _ => {
290                    let known_tuple_obj =
291                        self.get_obj_equal_to_tuple(&obj_at_index.obj.to_string());
292                    if let Some(known_tuple_obj) = known_tuple_obj {
293                        let tuple_index_number = self.resolve_obj_to_number(&obj_at_index.index);
294                        if let Some(tuple_index_number) = tuple_index_number {
295                            let tuple_index_parsed_result =
296                                tuple_index_number.normalized_value.parse::<usize>();
297                            if let Ok(tuple_index_one_based) = tuple_index_parsed_result {
298                                if tuple_index_one_based >= 1
299                                    && tuple_index_one_based <= known_tuple_obj.args.len()
300                                {
301                                    return (*known_tuple_obj.args[tuple_index_one_based - 1])
302                                        .clone();
303                                }
304                            }
305                        }
306                    }
307                    if let Some(known_list) =
308                        self.get_obj_equal_to_finite_seq_list(&obj_at_index.obj.to_string())
309                    {
310                        let ix = self.resolve_obj_to_number(&obj_at_index.index);
311                        if let Some(ix) = ix {
312                            if let Ok(one_based) = ix.normalized_value.parse::<usize>() {
313                                if one_based >= 1 && one_based <= known_list.objs.len() {
314                                    return (*known_list.objs[one_based - 1]).clone();
315                                }
316                            }
317                        }
318                    }
319                    obj.clone()
320                }
321            },
322            Obj::FamilyObj(f) => {
323                let params: Vec<Obj> = f.params.iter().map(|p| self.resolve_obj(p)).collect();
324                FamilyObj::new(f.name.clone(), params).into()
325            }
326            _ => obj.clone(),
327        }
328    }
329
330    pub(crate) fn obj_is_resolved_zero(&self, obj: &Obj) -> bool {
331        self.resolve_obj_to_number(obj)
332            .map(|n| {
333                matches!(
334                    compare_normalized_number_str_to_zero(&n.normalized_value),
335                    NumberCompareResult::Equal
336                )
337            })
338            .unwrap_or(false)
339    }
340
341    /// If `obj` is `(-1) * u` or `u * (-1)` with literal `-1`, returns `u`.
342    pub(crate) fn peel_mul_by_literal_neg_one(&self, obj: &Obj) -> Option<Obj> {
343        let Obj::Mul(m) = obj else {
344            return None;
345        };
346        if let Some(ln) = self.resolve_obj_to_number(m.left.as_ref()) {
347            if ln.normalized_value == "-1" {
348                return Some(m.right.as_ref().clone());
349            }
350        }
351        if let Some(rn) = self.resolve_obj_to_number(m.right.as_ref()) {
352            if rn.normalized_value == "-1" {
353                return Some(m.left.as_ref().clone());
354            }
355        }
356        None
357    }
358}