diff --git a/src/annot.rs b/src/annot.rs index bb4c118..128c289 100644 --- a/src/annot.rs +++ b/src/annot.rs @@ -196,6 +196,7 @@ enum FormulaOrTerm { Term(chc::Term, chc::Sort), BinOp(chc::Term, AmbiguousBinOp, chc::Term), Not(Box>), + Literal(bool), } impl FormulaOrTerm { @@ -215,6 +216,13 @@ impl FormulaOrTerm { chc::Formula::Atom(chc::Atom::new(pred.into(), vec![lhs, rhs])) } FormulaOrTerm::Not(formula_or_term) => formula_or_term.into_formula()?.not(), + FormulaOrTerm::Literal(b) => { + if b { + chc::Formula::top() + } else { + chc::Formula::bottom() + } + } }; Some(fo) } @@ -233,6 +241,7 @@ impl FormulaOrTerm { let (t, _) = formula_or_term.into_term()?; (t.not(), chc::Sort::bool()) } + FormulaOrTerm::Literal(b) => (chc::Term::bool(b), chc::Sort::bool()), }; Some((t, s)) } @@ -461,8 +470,8 @@ where ident.as_str(), self.formula_existentials.get(ident.name.as_str()), ) { - ("true", _) => FormulaOrTerm::Formula(chc::Formula::top()), - ("false", _) => FormulaOrTerm::Formula(chc::Formula::bottom()), + ("true", _) => FormulaOrTerm::Literal(true), + ("false", _) => FormulaOrTerm::Literal(false), (_, Some(sort)) => { let var = chc::Term::FormulaExistentialVar(sort.clone(), ident.name.to_string()); @@ -502,6 +511,31 @@ where ), _ => unimplemented!(), }, + TokenKind::Lt => { + let (t1, s1) = self + .parse_binop_2()? + .into_term() + .ok_or_else(|| ParseAttrError::unexpected_formula("in box/mut term"))?; + + match self.next_token("> or ,")? { + Token { + kind: TokenKind::Gt, + .. + } => FormulaOrTerm::Term(chc::Term::box_(t1), chc::Sort::box_(s1)), + Token { + kind: TokenKind::Comma, + .. + } => { + let (t2, _s2) = self + .parse_binop_2()? + .into_term() + .ok_or_else(|| ParseAttrError::unexpected_formula("in mut term"))?; + self.expect_next_token(TokenKind::Gt, ">")?; + FormulaOrTerm::Term(chc::Term::mut_(t1, t2), chc::Sort::mut_(s1)) + } + t => return Err(ParseAttrError::unexpected_token("> or ,", t.clone())), + } + } _ => { return Err(ParseAttrError::unexpected_token( "identifier, or literal", @@ -801,6 +835,26 @@ where fn parse_sort(&mut self) -> Result { let tt = self.next_token_tree("sort")?.clone(); match tt { + TokenTree::Token( + Token { + kind: TokenKind::BinOp(BinOpToken::And), + .. + }, + _, + ) => match self.look_ahead_token(0) { + Some(Token { + kind: TokenKind::Ident(sym, _), + .. + }) if sym.as_str() == "mut" => { + self.consume(); + let inner_sort = self.parse_sort()?; + Ok(chc::Sort::mut_(inner_sort)) + } + _ => { + let inner_sort = self.parse_sort()?; + Ok(chc::Sort::box_(inner_sort)) + } + }, TokenTree::Token( Token { kind: TokenKind::Ident(sym, _), @@ -814,7 +868,16 @@ where "string" => unimplemented!(), "null" => chc::Sort::null(), "fn" => unimplemented!(), - _ => unimplemented!(), + name => { + // TODO: ad-hoc + if let Some(i) = + name.strip_prefix('T').and_then(|s| s.parse::().ok()) + { + chc::Sort::param(i) + } else { + unimplemented!(); + } + } }; Ok(sort) } diff --git a/tests/ui/fail/annot_box_term.rs b/tests/ui/fail/annot_box_term.rs new file mode 100644 index 0000000..cdb3eb6 --- /dev/null +++ b/tests/ui/fail/annot_box_term.rs @@ -0,0 +1,17 @@ +//@error-in-other-file: Unsat +//@compile-flags: -C debug-assertions=off + +#[thrust::sig(fn(x: int) -> {r: Box | r == })] +fn box_create(x: i64) -> Box { + Box::new(x) +} + +#[thrust::requires(b == )] +fn box_consume(b: Box, v: i64) { + assert!(*b == v); +} + +fn main() { + let b = box_create(42); + box_consume(b, 10); +} diff --git a/tests/ui/fail/annot_mut_term.rs b/tests/ui/fail/annot_mut_term.rs new file mode 100644 index 0000000..f1037dd --- /dev/null +++ b/tests/ui/fail/annot_mut_term.rs @@ -0,0 +1,13 @@ +//@error-in-other-file: Unsat + +#[thrust::requires(true)] +#[thrust::ensures(x == <*x, y>)] +fn f(x: &mut i64, y: i64) { + *x = y; +} + +fn main() { + let mut a = 1; + f(&mut a, 2); + assert!(a == 1); +} diff --git a/tests/ui/pass/annot_box_term.rs b/tests/ui/pass/annot_box_term.rs new file mode 100644 index 0000000..95d4775 --- /dev/null +++ b/tests/ui/pass/annot_box_term.rs @@ -0,0 +1,17 @@ +//@check-pass +//@compile-flags: -C debug-assertions=off + +#[thrust::sig(fn(x: int) -> {r: Box | r == })] +fn box_create(x: i64) -> Box { + Box::new(x) +} + +#[thrust::requires(b == )] +fn box_consume(b: Box, v: i64) { + assert!(*b == v); +} + +fn main() { + let b = box_create(42); + box_consume(b, 42); +} diff --git a/tests/ui/pass/annot_mut_term.rs b/tests/ui/pass/annot_mut_term.rs new file mode 100644 index 0000000..172a1df --- /dev/null +++ b/tests/ui/pass/annot_mut_term.rs @@ -0,0 +1,13 @@ +//@check-pass + +#[thrust::requires(true)] +#[thrust::ensures(x == <*x, y>)] +fn f(x: &mut i64, y: i64) { + *x = y; +} + +fn main() { + let mut a = 1; + f(&mut a, 2); + assert!(a == 2); +}