litex/parse/by_stmt/
transitive_prop_by_stmt.rs1use crate::prelude::*;
2
3impl Runtime {
4 pub fn parse_by_transitive_prop_stmt(
5 &mut self,
6 tb: &mut TokenBlock,
7 ) -> Result<Stmt, RuntimeError> {
8 tb.skip_token(TRANSITIVE_PROP)?;
9 tb.skip_token(COLON)?;
10 if !tb.exceed_end_of_head() {
11 return Err(RuntimeError::from(ParseRuntimeError(
12 RuntimeErrorStruct::new_with_msg_and_line_file(
13 "by transitive_prop: expected end of head after `:`".to_string(),
14 tb.line_file.clone(),
15 ),
16 )));
17 }
18 if tb.body.is_empty() {
19 return Err(RuntimeError::from(ParseRuntimeError(
20 RuntimeErrorStruct::new_with_msg_and_line_file(
21 "by transitive_prop: expects a body".to_string(),
22 tb.line_file.clone(),
23 ),
24 )));
25 }
26
27 let prove_block = tb.body.get_mut(0).ok_or_else(|| {
28 RuntimeError::from(ParseRuntimeError(
29 RuntimeErrorStruct::new_with_msg_and_line_file(
30 "by transitive_prop: expected prove block".to_string(),
31 tb.line_file.clone(),
32 ),
33 ))
34 })?;
35 if prove_block.header.get(0).map(|s| s.as_str()) != Some(PROVE) {
36 return Err(RuntimeError::from(ParseRuntimeError(
37 RuntimeErrorStruct::new_with_msg_and_line_file(
38 "by transitive_prop: first block must be `prove:`".to_string(),
39 prove_block.line_file.clone(),
40 ),
41 )));
42 }
43 prove_block.skip_token_and_colon_and_exceed_end_of_head(PROVE)?;
44 if prove_block.body.len() != 1 {
45 return Err(RuntimeError::from(ParseRuntimeError(
46 RuntimeErrorStruct::new_with_msg_and_line_file(
47 "by transitive_prop: `prove:` must contain exactly one forall fact".to_string(),
48 prove_block.line_file.clone(),
49 ),
50 )));
51 }
52
53 let forall_block = prove_block.body.get_mut(0).ok_or_else(|| {
54 RuntimeError::from(ParseRuntimeError(
55 RuntimeErrorStruct::new_with_msg_and_line_file(
56 "by transitive_prop: missing forall block".to_string(),
57 tb.line_file.clone(),
58 ),
59 ))
60 })?;
61 let fact = self.parse_fact(forall_block)?;
62 let forall_fact = match fact {
63 Fact::ForallFact(ff) => ff,
64 Fact::ForallFactWithIff(_) => {
65 return Err(RuntimeError::from(ParseRuntimeError(
66 RuntimeErrorStruct::new_with_msg_and_line_file(
67 "by transitive_prop: forall with `<=>` is not allowed here".to_string(),
68 forall_block.line_file.clone(),
69 ),
70 )));
71 }
72 _ => {
73 return Err(RuntimeError::from(ParseRuntimeError(
74 RuntimeErrorStruct::new_with_msg_and_line_file(
75 "by transitive_prop: `prove:` must be a single `forall` fact".to_string(),
76 forall_block.line_file.clone(),
77 ),
78 )));
79 }
80 };
81
82 let shape_check =
83 ByTransitivePropStmt::new(forall_fact.clone(), Vec::new(), tb.line_file.clone())
84 .transitive_prop_name();
85 if let Err(msg) = shape_check {
86 return Err(RuntimeError::from(ParseRuntimeError(
87 RuntimeErrorStruct::new_with_msg_and_line_file(msg, forall_fact.line_file.clone()),
88 )));
89 }
90
91 let names = forall_fact.params_def_with_type.collect_param_names();
92 let lf = tb.line_file.clone();
93 let proof: Vec<Stmt> = self.parse_stmts_with_optional_free_param_scope(
94 ParamObjType::Forall,
95 &names,
96 lf,
97 |this| {
98 tb.body
99 .iter_mut()
100 .skip(1)
101 .map(|b| this.parse_stmt(b))
102 .collect::<Result<_, _>>()
103 },
104 )?;
105
106 Ok(ByTransitivePropStmt::new(forall_fact, proof, tb.line_file.clone()).into())
107 }
108}