Skip to main content

litex/stmt/
definition_stmt.rs

1use crate::{common::keywords::GREATER_EQUAL, prelude::*, stmt::parameter_def::ParamDefWithType};
2use std::fmt;
3
4#[derive(Clone)]
5pub struct HaveFnByInducNestedCase {
6    pub case_fact: AndChainAtomicFact,
7    pub equal_to: Obj,
8}
9
10#[derive(Clone)]
11pub enum HaveFnByInducLastCase {
12    EqualTo(Obj),
13    NestedCases(Vec<HaveFnByInducNestedCase>),
14}
15
16// have fn by induc from 0: f(x Z: x >= 0) R:
17//     case 0: 1
18//     case 1: 1
19//     case >= 2:
20//         case x % 2 = 0: f(x / 2)
21//         case x % 2 = 1: f(x / 2) + f(x / 2 + 1)
22#[derive(Clone)]
23pub struct HaveFnByInducStmt {
24    pub induc_from: Obj,
25    pub name: String,
26    pub param: String,
27    pub ret_set: Obj,
28    pub special_cases_equal_tos: Vec<Obj>,
29    pub last_case: HaveFnByInducLastCase,
30    pub line_file: LineFile,
31}
32
33#[derive(Clone)]
34pub struct DefAbstractPropStmt {
35    pub name: String,
36    pub params: Vec<String>,
37    pub line_file: LineFile,
38}
39
40impl DefAbstractPropStmt {
41    pub fn new(name: String, params: Vec<String>, line_file: LineFile) -> Self {
42        DefAbstractPropStmt {
43            name,
44            params,
45            line_file,
46        }
47    }
48}
49
50#[derive(Clone)]
51pub struct DefStructStmt {
52    pub name: String,
53    pub param_defs: ParamDefWithType,
54    pub dom_facts: Vec<OrAndChainAtomicFact>,
55    pub fields: Vec<(String, ParamType)>,
56    pub facts: Vec<OrAndChainAtomicFact>,
57    pub line_file: LineFile,
58}
59
60#[derive(Clone)]
61pub struct DefFamilyStmt {
62    pub name: String,
63    pub params_def_with_type: ParamDefWithType,
64    pub dom_facts: Vec<OrAndChainAtomicFact>,
65    pub equal_to: Obj,
66    pub line_file: LineFile,
67}
68
69/// `have fn` 里 `{ … }` 一段的源码形态:形参名为用户符,dom/ret 中标识符亦为源码名;**不含** `__` mangling。
70/// 需要存入 `Obj::FnSet` 时由 [`Runtime::fn_set_for_storage_from_have_fn_clause`] 生成存储用 [`FnSet`]。
71#[derive(Clone)]
72pub struct FnSetClause {
73    pub params_def_with_set: Vec<ParamGroupWithSet>,
74    pub dom_facts: Vec<OrAndChainAtomicFact>,
75    pub ret_set: Obj,
76}
77
78#[derive(Clone)]
79pub struct HaveFnEqualCaseByCaseStmt {
80    pub name: String,
81    pub fn_set_clause: FnSetClause,
82    pub cases: Vec<AndChainAtomicFact>,
83    pub equal_tos: Vec<Obj>,
84    pub line_file: LineFile,
85}
86
87#[derive(Clone)]
88pub struct HaveFnEqualStmt {
89    pub name: String,
90    pub fn_set_clause: FnSetClause,
91    pub equal_to: Obj,
92    pub line_file: LineFile,
93}
94
95#[derive(Clone)]
96pub struct HaveByExistStmt {
97    pub equal_tos: Vec<String>,
98    pub exist_fact_in_have_obj_st: ExistFact,
99    pub line_file: LineFile,
100}
101
102#[derive(Clone)]
103pub struct HaveObjEqualStmt {
104    pub param_def: ParamDefWithType,
105    pub objs_equal_to: Vec<Obj>,
106    pub line_file: LineFile,
107}
108
109#[derive(Clone)]
110pub struct HaveObjInNonemptySetOrParamTypeStmt {
111    pub param_def: ParamDefWithType,
112    pub line_file: LineFile,
113}
114
115#[derive(Clone)]
116pub struct DefLetStmt {
117    pub param_def: ParamDefWithType,
118    pub facts: Vec<Fact>,
119    pub line_file: LineFile,
120}
121
122#[derive(Clone)]
123pub struct DefPropStmt {
124    pub name: String,
125    pub params_def_with_type: ParamDefWithType,
126    pub iff_facts: Vec<Fact>,
127    pub line_file: LineFile,
128}
129
130impl fmt::Display for DefAbstractPropStmt {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        write!(
133            f,
134            "{} {}{}{}{}",
135            ABSTRACT_PROP,
136            self.name,
137            LEFT_BRACE,
138            vec_to_string_join_by_comma(&self.params),
139            RIGHT_BRACE
140        )
141    }
142}
143
144impl fmt::Display for DefStructStmt {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        // 格式: struct name(params): \n  field1 or1 \n  field2 or2 \n  <=>: \n  facts...
147        // 解析器会为每个类型参数自动前置一条 field;Display 只还原用户写出来的字段。
148        let implicit_prefix_len = self.param_defs.number_of_params();
149        let fields_str: String = self
150            .fields
151            .iter()
152            .skip(implicit_prefix_len)
153            .map(|(name, or_val)| format!("{} {}", name, or_val))
154            .collect::<Vec<_>>()
155            .join("\n");
156        let fields_indented =
157            to_string_and_add_four_spaces_at_beginning_of_each_line(&fields_str, 1);
158        let equiv_line = add_four_spaces_at_beginning(format!("{}{}", EQUIVALENT_SIGN, COLON), 1);
159        let facts_indented = vec_to_string_add_four_spaces_at_beginning_of_each_line(
160            &self
161                .facts
162                .iter()
163                .skip(implicit_prefix_len)
164                .cloned()
165                .collect(),
166            1,
167        );
168        write!(
169            f,
170            "{} {}{}{}{} {}\n{}\n{}\n{}",
171            STRUCT,
172            self.name,
173            LEFT_BRACE,
174            self.param_defs.to_string(),
175            RIGHT_BRACE,
176            COLON,
177            fields_indented,
178            equiv_line,
179            facts_indented
180        )
181    }
182}
183
184impl DefPropStmt {
185    pub fn new(
186        name: String,
187        params_def_with_type: ParamDefWithType,
188        iff_facts: Vec<Fact>,
189        line_file: LineFile,
190    ) -> Self {
191        DefPropStmt {
192            name,
193            params_def_with_type,
194            iff_facts,
195            line_file,
196        }
197    }
198}
199
200impl fmt::Display for DefPropStmt {
201    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202        match self.iff_facts.len() {
203            0 => write!(
204                f,
205                "{} {}{}",
206                PROP,
207                self.name,
208                braced_string(&self.params_def_with_type)
209            ),
210            _ => write!(
211                f,
212                "{} {}{}{}\n{}",
213                PROP,
214                self.name,
215                braced_string(&self.params_def_with_type),
216                COLON,
217                vec_to_string_add_four_spaces_at_beginning_of_each_line(&self.iff_facts, 1)
218            ),
219        }
220    }
221}
222
223impl DefLetStmt {
224    pub fn new(param_def: ParamDefWithType, facts: Vec<Fact>, line_file: LineFile) -> Self {
225        DefLetStmt {
226            param_def,
227            facts,
228            line_file,
229        }
230    }
231}
232
233impl fmt::Display for DefLetStmt {
234    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235        let param_str = self.param_def.to_string();
236        match self.facts.len() {
237            0 => write!(f, "{} {}", LET, param_str),
238            _ => write!(
239                f,
240                "{} {}{}\n{}",
241                LET,
242                param_str,
243                COLON,
244                vec_to_string_add_four_spaces_at_beginning_of_each_line(&self.facts, 1)
245            ),
246        }
247    }
248}
249
250impl HaveObjInNonemptySetOrParamTypeStmt {
251    pub fn new(param_def: ParamDefWithType, line_file: LineFile) -> Self {
252        HaveObjInNonemptySetOrParamTypeStmt {
253            param_def,
254            line_file,
255        }
256    }
257}
258
259impl fmt::Display for HaveObjInNonemptySetOrParamTypeStmt {
260    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261        write!(f, "{} {}", HAVE, self.param_def.to_string())
262    }
263}
264
265impl HaveObjEqualStmt {
266    pub fn new(param_def: ParamDefWithType, objs_equal_to: Vec<Obj>, line_file: LineFile) -> Self {
267        HaveObjEqualStmt {
268            param_def,
269            objs_equal_to,
270            line_file,
271        }
272    }
273}
274
275impl fmt::Display for HaveObjEqualStmt {
276    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277        write!(
278            f,
279            "{} {} {} {}",
280            HAVE,
281            self.param_def.to_string(),
282            EQUAL,
283            vec_to_string_join_by_comma(&self.objs_equal_to)
284        )
285    }
286}
287
288impl HaveByExistStmt {
289    pub fn new(
290        equal_tos: Vec<String>,
291        exist_fact_in_have_obj_st: ExistFact,
292        line_file: LineFile,
293    ) -> Self {
294        HaveByExistStmt {
295            equal_tos,
296            exist_fact_in_have_obj_st,
297            line_file,
298        }
299    }
300}
301
302impl fmt::Display for HaveByExistStmt {
303    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304        write!(
305            f,
306            "{} {} {} {} {}",
307            HAVE,
308            BY,
309            self.exist_fact_in_have_obj_st,
310            COLON,
311            vec_to_string_join_by_comma(&self.equal_tos),
312        )
313    }
314}
315
316impl HaveFnEqualStmt {
317    pub fn new(
318        name: String,
319        fn_set_clause: FnSetClause,
320        equal_to: Obj,
321        line_file: LineFile,
322    ) -> Self {
323        HaveFnEqualStmt {
324            name,
325            fn_set_clause,
326            equal_to,
327            line_file,
328        }
329    }
330}
331
332impl fmt::Display for HaveFnEqualStmt {
333    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334        write!(
335            f,
336            "{} {} {}{} {} {}",
337            HAVE,
338            FN_LOWER_CASE,
339            self.name,
340            brace_vec_colon_vec_to_string(
341                &self.fn_set_clause.params_def_with_set,
342                &self.fn_set_clause.dom_facts
343            ),
344            EQUAL,
345            self.equal_to
346        )
347    }
348}
349
350impl fmt::Display for HaveFnEqualCaseByCaseStmt {
351    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352        let cases_and_proofs = self
353            .cases
354            .iter()
355            .enumerate()
356            .map(|(i, case)| {
357                to_string_and_add_four_spaces_at_beginning_of_each_line(
358                    &format!(
359                        "{} {}{} {}{} {} {}",
360                        CASE,
361                        case,
362                        COMMA,
363                        self.name,
364                        braced_vec_to_string(&ParamGroupWithSet::collect_param_names(
365                            &self.fn_set_clause.params_def_with_set,
366                        )),
367                        EQUAL,
368                        self.equal_tos[i]
369                    ),
370                    1,
371                )
372            })
373            .collect::<Vec<String>>();
374
375        write!(
376            f,
377            "{} {} {}{} {} {}\n{}",
378            HAVE,
379            FN_LOWER_CASE,
380            self.name,
381            brace_vec_colon_vec_to_string(
382                &self.fn_set_clause.params_def_with_set,
383                &self.fn_set_clause.dom_facts
384            ),
385            EQUAL,
386            COLON,
387            vec_to_string_with_sep(&cases_and_proofs, "\n".to_string())
388        )
389    }
390}
391
392impl HaveFnEqualCaseByCaseStmt {
393    pub fn new(
394        name: String,
395        fn_set_clause: FnSetClause,
396        cases: Vec<AndChainAtomicFact>,
397        equal_tos: Vec<Obj>,
398        line_file: LineFile,
399    ) -> Self {
400        HaveFnEqualCaseByCaseStmt {
401            name,
402            fn_set_clause,
403            cases,
404            equal_tos,
405            line_file,
406        }
407    }
408}
409
410pub fn induc_obj_plus_offset(induc_from: &Obj, offset: usize) -> Obj {
411    if offset == 0 {
412        induc_from.clone()
413    } else {
414        Add::new(induc_from.clone(), Number::new(offset.to_string()).into()).into()
415    }
416}
417
418fn flatten_and_chain_to_atomic_facts(c: &AndChainAtomicFact) -> Vec<AtomicFact> {
419    match c {
420        AndChainAtomicFact::AtomicFact(a) => vec![a.clone()],
421        AndChainAtomicFact::AndFact(af) => af.facts.clone(),
422        AndChainAtomicFact::ChainFact(cf) => cf.facts().unwrap(),
423    }
424}
425
426fn merge_two_and_chain_clauses(
427    a: AndChainAtomicFact,
428    b: AndChainAtomicFact,
429    line_file: LineFile,
430) -> AndChainAtomicFact {
431    let mut atoms = flatten_and_chain_to_atomic_facts(&a);
432    atoms.extend(flatten_and_chain_to_atomic_facts(&b));
433    AndChainAtomicFact::AndFact(AndFact::new(atoms, line_file))
434}
435
436impl HaveFnByInducStmt {
437    /// 与源码一致的 `fn` 空间(用户形参名 + dom + ret),不含 `__`;存 `Obj::FnSet` 时用 [`Runtime::fn_set_for_storage_from_have_fn_clause`]。
438    pub fn fn_user_fn_set_clause(&self) -> FnSetClause {
439        FnSetClause {
440            params_def_with_set: vec![ParamGroupWithSet::new(
441                vec![self.param.clone()],
442                StandardSet::Z.into(),
443            )],
444            dom_facts: vec![OrAndChainAtomicFact::AtomicFact(
445                GreaterEqualFact::new(
446                    self.param.clone().into(),
447                    self.induc_from.clone(),
448                    self.line_file.clone(),
449                )
450                .into(),
451            )],
452            ret_set: self.ret_set.clone(),
453        }
454    }
455
456    /// `forall x Z: ...` 里与 `fn` 定义域一致的那一段:标识符用源码 [`Self::param`],与 [`Self::fn_user_fn_set_clause`] 的 dom 语义相同。
457    pub fn forall_fn_base_dom_exist_or_facts(&self) -> Vec<Fact> {
458        vec![GreaterEqualFact::new(
459            self.param.clone().into(),
460            self.induc_from.clone(),
461            self.line_file.clone(),
462        )
463        .into()]
464    }
465
466    pub fn new(
467        name: String,
468        param: String,
469        ret_set: Obj,
470        induc_from: Obj,
471        special_cases_equal_tos: Vec<Obj>,
472        last_case: HaveFnByInducLastCase,
473        line_file: LineFile,
474    ) -> Self {
475        HaveFnByInducStmt {
476            name,
477            param,
478            ret_set,
479            induc_from,
480            special_cases_equal_tos,
481            last_case,
482            line_file,
483        }
484    }
485
486    /// 展开为与旧 `HaveFnEqualCaseByCaseStmt` 兼容的平铺 `case` 列表(源码最后一条为 `case >= n:`(n 为特例个数),此处仍展开为 `param = from + n` 与可选子条件的合取)。
487    pub fn to_have_fn_equal_case_by_case_stmt(&self) -> HaveFnEqualCaseByCaseStmt {
488        let line_file = self.line_file.clone();
489        let left_id: Obj = self.param.clone().into();
490        let n = self.special_cases_equal_tos.len();
491        let mut cases: Vec<AndChainAtomicFact> = Vec::new();
492        let mut equal_tos: Vec<Obj> = Vec::new();
493        for i in 0..n {
494            let when = AndChainAtomicFact::AtomicFact(
495                EqualFact::new(
496                    left_id.clone(),
497                    induc_obj_plus_offset(&self.induc_from, i),
498                    line_file.clone(),
499                )
500                .into(),
501            );
502            cases.push(when);
503            equal_tos.push(self.special_cases_equal_tos[i].clone());
504        }
505        let step = AndChainAtomicFact::AtomicFact(
506            EqualFact::new(
507                left_id.clone(),
508                induc_obj_plus_offset(&self.induc_from, n),
509                line_file.clone(),
510            )
511            .into(),
512        );
513        match &self.last_case {
514            HaveFnByInducLastCase::EqualTo(eq) => {
515                cases.push(step);
516                equal_tos.push(eq.clone());
517            }
518            HaveFnByInducLastCase::NestedCases(last_pairs) => {
519                for nested in last_pairs {
520                    let merged = merge_two_and_chain_clauses(
521                        step.clone(),
522                        nested.case_fact.clone(),
523                        line_file.clone(),
524                    );
525                    cases.push(merged);
526                    equal_tos.push(nested.equal_to.clone());
527                }
528            }
529        }
530        HaveFnEqualCaseByCaseStmt::new(
531            self.name.clone(),
532            self.fn_user_fn_set_clause(),
533            cases,
534            equal_tos,
535            line_file,
536        )
537    }
538}
539
540impl fmt::Display for HaveFnByInducStmt {
541    /// 与源码一致:形参用用户名字,不出现 `__`;存 `FnSet` 时再 mangling。
542    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
543        let n = self.special_cases_equal_tos.len();
544        write!(
545            f,
546            "{} {} {} {} {} {} {}{}",
547            HAVE, FN_LOWER_CASE, BY, INDUC, FROM, " ", self.induc_from, COLON,
548        )?;
549        write!(f, " {} {}{}", self.name, LEFT_BRACE, self.param)?;
550        write!(
551            f,
552            " {} {} {} {} {} {} {} {} {} {} {} {}",
553            Z,
554            COLON,
555            " ",
556            self.param,
557            " ",
558            GREATER_EQUAL,
559            " ",
560            self.induc_from,
561            RIGHT_BRACE,
562            " ",
563            self.ret_set,
564            COLON,
565        )?;
566        for (i, eq) in self.special_cases_equal_tos.iter().enumerate() {
567            writeln!(f)?;
568            write!(f, "    {} {}: {}", CASE, i, eq)?;
569        }
570        writeln!(f)?;
571        match &self.last_case {
572            HaveFnByInducLastCase::EqualTo(eq) => {
573                write!(f, "    {} {} {}: {}", CASE, GREATER_EQUAL, n, eq)?;
574            }
575            HaveFnByInducLastCase::NestedCases(nested) => {
576                write!(f, "    {} {} {}:", CASE, GREATER_EQUAL, n)?;
577                for nc in nested {
578                    writeln!(f)?;
579                    write!(f, "        {} {}: {}", CASE, nc.case_fact, nc.equal_to)?;
580                }
581            }
582        }
583        Ok(())
584    }
585}
586
587impl DefFamilyStmt {
588    pub fn new(
589        name: String,
590        params_def_with_type: ParamDefWithType,
591        dom_facts: Vec<OrAndChainAtomicFact>,
592        equal_to: Obj,
593        line_file: LineFile,
594    ) -> Self {
595        DefFamilyStmt {
596            name,
597            params_def_with_type,
598            dom_facts,
599            equal_to,
600            line_file,
601        }
602    }
603}
604
605impl fmt::Display for DefFamilyStmt {
606    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
607        write!(
608            f,
609            "{} {}{}{} {} {}{} {} {}",
610            FAMILY,
611            self.name,
612            LEFT_BRACE,
613            self.params_def_with_type.to_string(),
614            COLON,
615            vec_to_string_join_by_comma(&self.dom_facts),
616            RIGHT_BRACE,
617            EQUAL,
618            self.equal_to
619        )
620    }
621}
622
623impl DefStructStmt {
624    pub fn new(
625        name: String,
626        param_defs: ParamDefWithType,
627        dom_facts: Vec<OrAndChainAtomicFact>,
628        fields: Vec<(String, ParamType)>,
629        facts: Vec<OrAndChainAtomicFact>,
630        line_file: LineFile,
631    ) -> Self {
632        if fields.len() <= 1 {
633            unreachable!();
634        }
635
636        DefStructStmt {
637            name,
638            param_defs,
639            dom_facts,
640            fields,
641            facts,
642            line_file,
643        }
644    }
645
646    pub fn number_of_params(&self) -> usize {
647        self.param_defs.number_of_params()
648    }
649
650    /// 按定义顺序展开所有类型形参名(与 `struct T(...)` 中参数顺序一致)。
651    pub fn get_params(&self) -> Vec<String> {
652        self.param_defs.collect_param_names()
653    }
654}