Skip to content

Commit 3c94c78

Browse files
committed
Parse tuples in annotations
1 parent f942d5d commit 3c94c78

File tree

6 files changed

+144
-53
lines changed

6 files changed

+144
-53
lines changed

src/annot.rs

Lines changed: 117 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,28 @@ where
168168
}
169169
}
170170

171+
fn parse_term_or_tuple(&mut self) -> Result<(chc::Term<T::Output>, chc::Sort)> {
172+
let mut terms_and_sorts = Vec::new();
173+
loop {
174+
terms_and_sorts.push(self.parse_term()?);
175+
if let Some(Token {
176+
kind: TokenKind::Comma,
177+
..
178+
}) = self.look_ahead_token(0)
179+
{
180+
self.consume();
181+
} else {
182+
break;
183+
}
184+
}
185+
if terms_and_sorts.len() == 1 {
186+
Ok(terms_and_sorts.pop().unwrap())
187+
} else {
188+
let (terms, sorts) = terms_and_sorts.into_iter().unzip();
189+
Ok((chc::Term::tuple(terms), chc::Sort::tuple(sorts)))
190+
}
191+
}
192+
171193
fn parse_atom_term(&mut self) -> Result<(chc::Term<T::Output>, chc::Sort)> {
172194
let tt = self.next_token_tree("term")?.clone();
173195

@@ -178,103 +200,145 @@ where
178200
resolver: self.boxed_resolver(),
179201
cursor: s.trees(),
180202
};
181-
let term = parser.parse_term()?;
203+
let (term, sort) = parser.parse_term_or_tuple()?;
182204
parser.end_of_input()?;
183-
return Ok(term);
205+
return Ok((term, sort));
184206
}
185-
_ => unimplemented!(),
207+
_ => return Err(ParseAttrError::unexpected_token_tree("token", tt)),
186208
};
187209

188-
if let Some((ident, _)) = t.ident() {
210+
let (term, sort) = if let Some((ident, _)) = t.ident() {
189211
let (v, sort) = self.resolve(ident)?;
190-
return Ok((chc::Term::var(v), sort));
212+
(chc::Term::var(v), sort)
213+
} else {
214+
match t.kind {
215+
TokenKind::Literal(lit) => match lit.kind {
216+
LitKind::Integer => (
217+
chc::Term::int(lit.symbol.as_str().parse().unwrap()),
218+
chc::Sort::int(),
219+
),
220+
_ => unimplemented!(),
221+
},
222+
_ => {
223+
return Err(ParseAttrError::unexpected_token(
224+
"identifier, or literal",
225+
t.clone(),
226+
));
227+
}
228+
}
229+
};
230+
231+
Ok((term, sort))
232+
}
233+
234+
fn parse_postfix_term(&mut self) -> Result<(chc::Term<T::Output>, chc::Sort)> {
235+
let (term, sort) = self.parse_atom_term()?;
236+
237+
let mut fields = Vec::new();
238+
loop {
239+
if let Some(Token {
240+
kind: TokenKind::Dot,
241+
..
242+
}) = self.look_ahead_token(0)
243+
{
244+
self.consume();
245+
match self.next_token("field")? {
246+
Token {
247+
kind: TokenKind::Literal(lit),
248+
..
249+
} if matches!(lit.kind, LitKind::Integer) => {
250+
let idx = lit.symbol.as_str().parse().unwrap();
251+
fields.push(idx);
252+
}
253+
t => return Err(ParseAttrError::unexpected_token("field", t.clone())),
254+
}
255+
} else {
256+
break;
257+
}
191258
}
192-
let (term, sort) = match t.kind {
193-
TokenKind::Literal(lit) => match lit.kind {
194-
LitKind::Integer => (
195-
chc::Term::int(lit.symbol.as_str().parse().unwrap()),
196-
chc::Sort::int(),
197-
),
198-
_ => unimplemented!(),
199-
},
200-
TokenKind::BinOp(BinOpToken::Minus) => {
201-
let (operand, sort) = self.parse_atom_term()?;
259+
260+
let term = fields.iter().fold(term, |acc, idx| acc.tuple_proj(*idx));
261+
let sort = fields.iter().fold(sort, |acc, idx| acc.tuple_elem(*idx));
262+
Ok((term, sort))
263+
}
264+
265+
fn parse_prefix_term(&mut self) -> Result<(chc::Term<T::Output>, chc::Sort)> {
266+
let (term, sort) = match self.look_ahead_token(0).map(|t| &t.kind) {
267+
Some(TokenKind::BinOp(BinOpToken::Minus)) => {
268+
self.consume();
269+
let (operand, sort) = self.parse_postfix_term()?;
202270
(operand.neg(), sort)
203271
}
204-
TokenKind::BinOp(BinOpToken::Star) => {
205-
let (operand, sort) = self.parse_atom_term()?;
272+
Some(TokenKind::BinOp(BinOpToken::Star)) => {
273+
self.consume();
274+
let (operand, sort) = self.parse_postfix_term()?;
206275
match sort {
207276
chc::Sort::Box(inner) => (chc::Term::box_current(operand), *inner),
208277
chc::Sort::Mut(inner) => (chc::Term::mut_current(operand), *inner),
209278
_ => return Err(ParseAttrError::unsorted_op("*", sort)),
210279
}
211280
}
212-
TokenKind::BinOp(BinOpToken::Caret) => {
213-
let (operand, sort) = self.parse_atom_term()?;
281+
Some(TokenKind::BinOp(BinOpToken::Caret)) => {
282+
self.consume();
283+
let (operand, sort) = self.parse_postfix_term()?;
214284
if let chc::Sort::Mut(inner) = sort {
215285
(chc::Term::mut_final(operand), *inner)
216286
} else {
217287
return Err(ParseAttrError::unsorted_op("^", sort));
218288
}
219289
}
220-
_ => {
221-
return Err(ParseAttrError::unexpected_token_tree(
222-
"-, *, ^, (, identifier, or literal",
223-
tt,
224-
))
225-
}
290+
_ => self.parse_postfix_term()?,
226291
};
227-
228292
Ok((term, sort))
229293
}
230294

231295
fn parse_term(&mut self) -> Result<(chc::Term<T::Output>, chc::Sort)> {
232-
let (lhs, lhs_sort) = self.parse_atom_term()?;
296+
let (lhs, lhs_sort) = self.parse_prefix_term()?;
233297

234298
let (term, sort) = match self.look_ahead_token(0).map(|t| &t.kind) {
235299
Some(TokenKind::BinOp(BinOpToken::Plus)) => {
236300
self.consume();
237-
let (rhs, _) = self.parse_atom_term()?;
301+
let (rhs, _) = self.parse_prefix_term()?;
238302
(lhs.add(rhs), chc::Sort::int())
239303
}
240304
Some(TokenKind::BinOp(BinOpToken::Minus)) => {
241305
self.consume();
242-
let (rhs, _) = self.parse_atom_term()?;
306+
let (rhs, _) = self.parse_prefix_term()?;
243307
(lhs.sub(rhs), chc::Sort::int())
244308
}
245309
Some(TokenKind::BinOp(BinOpToken::Star)) => {
246310
self.consume();
247-
let (rhs, _) = self.parse_atom_term()?;
311+
let (rhs, _) = self.parse_prefix_term()?;
248312
(lhs.mul(rhs), chc::Sort::int())
249313
}
250314
Some(TokenKind::EqEq) => {
251315
self.consume();
252-
let (rhs, _) = self.parse_atom_term()?;
316+
let (rhs, _) = self.parse_prefix_term()?;
253317
(lhs.eq(rhs), chc::Sort::bool())
254318
}
255319
Some(TokenKind::Ne) => {
256320
self.consume();
257-
let (rhs, _) = self.parse_atom_term()?;
321+
let (rhs, _) = self.parse_prefix_term()?;
258322
(lhs.ne(rhs), chc::Sort::bool())
259323
}
260324
Some(TokenKind::Ge) => {
261325
self.consume();
262-
let (rhs, _) = self.parse_atom_term()?;
326+
let (rhs, _) = self.parse_prefix_term()?;
263327
(lhs.ge(rhs), chc::Sort::bool())
264328
}
265329
Some(TokenKind::Le) => {
266330
self.consume();
267-
let (rhs, _) = self.parse_atom_term()?;
331+
let (rhs, _) = self.parse_prefix_term()?;
268332
(lhs.le(rhs), chc::Sort::bool())
269333
}
270334
Some(TokenKind::Gt) => {
271335
self.consume();
272-
let (rhs, _) = self.parse_atom_term()?;
336+
let (rhs, _) = self.parse_prefix_term()?;
273337
(lhs.gt(rhs), chc::Sort::bool())
274338
}
275339
Some(TokenKind::Lt) => {
276340
self.consume();
277-
let (rhs, _) = self.parse_atom_term()?;
341+
let (rhs, _) = self.parse_prefix_term()?;
278342
(lhs.lt(rhs), chc::Sort::bool())
279343
}
280344
_ => return Ok((lhs, lhs_sort)),
@@ -295,7 +359,7 @@ where
295359
}
296360
}
297361

298-
let (lhs, _) = self.parse_atom_term()?;
362+
let (lhs, _) = self.parse_prefix_term()?;
299363
let pred = match self.next_token("<=, >=, <, >, == or !=")? {
300364
Token {
301365
kind: TokenKind::EqEq,
@@ -321,7 +385,12 @@ where
321385
kind: TokenKind::Lt,
322386
..
323387
} => chc::KnownPred::LESS_THAN,
324-
t => return Err(ParseAttrError::unexpected_token("==", t.clone())),
388+
t => {
389+
return Err(ParseAttrError::unexpected_token(
390+
"<=, >=, <, >, == or !=",
391+
t.clone(),
392+
))
393+
}
325394
};
326395
let (rhs, _) = self.parse_term()?;
327396
Ok(chc::Atom::new(pred.into(), vec![lhs, rhs]))
@@ -340,16 +409,16 @@ where
340409
let atom = self.parse_atom()?;
341410
Ok(chc::Formula::Atom(atom).not())
342411
}
343-
Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, s)) => {
344-
self.consume();
345-
let mut parser = Parser {
346-
resolver: self.boxed_resolver(),
347-
cursor: s.trees(),
348-
};
349-
let formula = parser.parse_formula()?;
350-
parser.end_of_input()?;
351-
Ok(formula)
352-
}
412+
//Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, s)) => {
413+
// self.consume();
414+
// let mut parser = Parser {
415+
// resolver: self.boxed_resolver(),
416+
// cursor: s.trees(),
417+
// };
418+
// let formula = parser.parse_formula()?;
419+
// parser.end_of_input()?;
420+
// Ok(formula)
421+
//}
353422
_ => {
354423
let atom = self.parse_atom()?;
355424
Ok(chc::Formula::Atom(atom))

src/chc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl Sort {
176176
}
177177
}
178178

179-
fn tuple_elem(self, index: usize) -> Self {
179+
pub fn tuple_elem(self, index: usize) -> Self {
180180
match self {
181181
Sort::Tuple(ss) => ss[index].clone(),
182182
_ => panic!("invalid tuple_elem"),

tests/ui/fail/take_max_annot.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ fn rand() -> i64 { unimplemented!() }
88

99
#[thrust::requires(true)]
1010
#[thrust::ensures(
11-
(*ma >= *mb && *ma == ^ma && ma == result) ||
12-
(*ma < *mb && *mb == ^mb && mb == result)
11+
*ma >= *mb && *ma == ^ma && ma == result ||
12+
*ma < *mb && *mb == ^mb && mb == result
1313
)]
1414
fn take_max<'a>(ma: &'a mut i64, mb: &'a mut i64) -> &'a mut i64 {
1515
if *ma >= *mb {

tests/ui/fail/tuple_annot.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@error-in-other-file: Unsat
2+
//@compile-flags: -C debug-assertions=off
3+
4+
#[thrust::requires(true)]
5+
#[thrust::ensures(^x == ((*x).1, (*x).1))]
6+
fn swap_tuple(x: &mut (i32, i32)) {
7+
let v = *x;
8+
*x = (v.1, v.0);
9+
}
10+
11+
fn main() {}

tests/ui/pass/take_max_annot.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ fn rand() -> i64 { unimplemented!() }
88

99
#[thrust::requires(true)]
1010
#[thrust::ensures(
11-
(*ma >= *mb && *mb == ^mb && ma == result) ||
12-
(*ma < *mb && *ma == ^ma && mb == result)
11+
*ma >= *mb && *mb == ^mb && ma == result ||
12+
*ma < *mb && *ma == ^ma && mb == result
1313
)]
1414
fn take_max<'a>(ma: &'a mut i64, mb: &'a mut i64) -> &'a mut i64 {
1515
if *ma >= *mb {

tests/ui/pass/tuple_annot.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@check-pass
2+
//@compile-flags: -C debug-assertions=off
3+
4+
#[thrust::requires(true)]
5+
#[thrust::ensures(^x == ((*x).1, (*x).0))]
6+
fn swap_tuple(x: &mut (i32, i32)) {
7+
let v = *x;
8+
*x = (v.1, v.0);
9+
}
10+
11+
fn main() {}

0 commit comments

Comments
 (0)