Skip to content

Commit 2319668

Browse files
committed
feat!(argus-parser): complete parser
This changes the API for `ExprBuilder`, but that is OK.
1 parent 17042a2 commit 2319668

File tree

9 files changed

+545
-146
lines changed

9 files changed

+545
-146
lines changed

argus-core/src/expr.rs

Lines changed: 146 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ pub enum ExprRef<'a> {
119119
}
120120

121121
/// An expression (either [`BoolExpr`] or [`NumExpr`])
122-
#[derive(Clone, Debug, derive_more::From)]
122+
#[derive(Clone, Debug, derive_more::From, derive_more::TryInto)]
123123
pub enum Expr {
124124
/// A reference to a [`BoolExpr`]
125125
Bool(BoolExpr),
@@ -146,220 +146,284 @@ impl ExprBuilder {
146146
}
147147

148148
/// Declare a constant boolean expression
149-
pub fn bool_const(&self, value: bool) -> Box<BoolExpr> {
150-
Box::new(BoolLit(value).into())
149+
pub fn bool_const(&self, value: bool) -> BoolExpr {
150+
BoolLit(value).into()
151151
}
152152

153153
/// Declare a constant integer expression
154-
pub fn int_const(&self, value: i64) -> Box<NumExpr> {
155-
Box::new(IntLit(value).into())
154+
pub fn int_const(&self, value: i64) -> NumExpr {
155+
IntLit(value).into()
156156
}
157157

158158
/// Declare a constant unsigned integer expression
159-
pub fn uint_const(&self, value: u64) -> Box<NumExpr> {
160-
Box::new(UIntLit(value).into())
159+
pub fn uint_const(&self, value: u64) -> NumExpr {
160+
UIntLit(value).into()
161161
}
162162

163163
/// Declare a constant floating point expression
164-
pub fn float_const(&self, value: f64) -> Box<NumExpr> {
165-
Box::new(FloatLit(value).into())
164+
pub fn float_const(&self, value: f64) -> NumExpr {
165+
FloatLit(value).into()
166166
}
167167

168168
/// Declare a boolean variable
169-
pub fn bool_var(&mut self, name: String) -> ArgusResult<Box<BoolExpr>> {
169+
pub fn bool_var(&mut self, name: String) -> ArgusResult<BoolExpr> {
170170
if self.declarations.insert(name.clone()) {
171-
Ok(Box::new((BoolVar { name }).into()))
171+
Ok((BoolVar { name }).into())
172172
} else {
173173
Err(Error::IdentifierRedeclaration)
174174
}
175175
}
176176

177177
/// Declare a integer variable
178-
pub fn int_var(&mut self, name: String) -> ArgusResult<Box<NumExpr>> {
178+
pub fn int_var(&mut self, name: String) -> ArgusResult<NumExpr> {
179179
if self.declarations.insert(name.clone()) {
180-
Ok(Box::new((IntVar { name }).into()))
180+
Ok((IntVar { name }).into())
181181
} else {
182182
Err(Error::IdentifierRedeclaration)
183183
}
184184
}
185185

186186
/// Declare a unsigned integer variable
187-
pub fn uint_var(&mut self, name: String) -> ArgusResult<Box<NumExpr>> {
187+
pub fn uint_var(&mut self, name: String) -> ArgusResult<NumExpr> {
188188
if self.declarations.insert(name.clone()) {
189-
Ok(Box::new((UIntVar { name }).into()))
189+
Ok((UIntVar { name }).into())
190190
} else {
191191
Err(Error::IdentifierRedeclaration)
192192
}
193193
}
194194

195195
/// Declare a floating point variable
196-
pub fn float_var(&mut self, name: String) -> ArgusResult<Box<NumExpr>> {
196+
pub fn float_var(&mut self, name: String) -> ArgusResult<NumExpr> {
197197
if self.declarations.insert(name.clone()) {
198-
Ok(Box::new((FloatVar { name }).into()))
198+
Ok((FloatVar { name }).into())
199199
} else {
200200
Err(Error::IdentifierRedeclaration)
201201
}
202202
}
203203

204204
/// Create a [`NumExpr::Neg`] expression
205-
pub fn make_neg(&self, arg: Box<NumExpr>) -> Box<NumExpr> {
206-
Box::new((Neg { arg }).into())
205+
pub fn make_neg(&self, arg: Box<NumExpr>) -> NumExpr {
206+
(Neg { arg }).into()
207207
}
208208

209209
/// Create a [`NumExpr::Add`] expression
210-
pub fn make_add<I>(&self, args: I) -> ArgusResult<Box<NumExpr>>
210+
pub fn make_add<I>(&self, args: I) -> ArgusResult<NumExpr>
211211
where
212212
I: IntoIterator<Item = NumExpr>,
213213
{
214-
let args: Vec<_> = args.into_iter().collect();
215-
if args.len() < 2 {
214+
let mut new_args = Vec::<NumExpr>::new();
215+
for arg in args.into_iter() {
216+
// Flatten the args if there is an Add
217+
if let NumExpr::Add(Add { args }) = arg {
218+
new_args.extend(args.into_iter());
219+
} else {
220+
new_args.push(arg);
221+
}
222+
}
223+
if new_args.len() < 2 {
216224
Err(Error::IncompleteArgs)
217225
} else {
218-
Ok(Box::new((Add { args }).into()))
226+
Ok((Add { args: new_args }).into())
219227
}
220228
}
221229

222230
/// Create a [`NumExpr::Mul`] expression
223-
pub fn make_mul<I>(&self, args: I) -> ArgusResult<Box<NumExpr>>
231+
pub fn make_mul<I>(&self, args: I) -> ArgusResult<NumExpr>
224232
where
225233
I: IntoIterator<Item = NumExpr>,
226234
{
227-
let args: Vec<_> = args.into_iter().collect();
228-
if args.len() < 2 {
235+
let mut new_args = Vec::<NumExpr>::new();
236+
for arg in args.into_iter() {
237+
// Flatten the args if there is a Mul
238+
if let NumExpr::Mul(Mul { args }) = arg {
239+
new_args.extend(args.into_iter());
240+
} else {
241+
new_args.push(arg);
242+
}
243+
}
244+
if new_args.len() < 2 {
229245
Err(Error::IncompleteArgs)
230246
} else {
231-
Ok(Box::new((Mul { args }).into()))
247+
Ok((Mul { args: new_args }).into())
232248
}
233249
}
234250

251+
/// Create a [`NumExpr::Sub`] expression
252+
pub fn make_sub(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> NumExpr {
253+
(Sub { lhs, rhs }).into()
254+
}
255+
235256
/// Create a [`NumExpr::Div`] expression
236-
pub fn make_div(&self, dividend: Box<NumExpr>, divisor: Box<NumExpr>) -> Box<NumExpr> {
237-
Box::new((Div { dividend, divisor }).into())
257+
pub fn make_div(&self, dividend: Box<NumExpr>, divisor: Box<NumExpr>) -> NumExpr {
258+
(Div { dividend, divisor }).into()
238259
}
239260

240261
/// Create a [`BoolExpr::Cmp`] expression
241-
pub fn make_cmp(&self, op: Ordering, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> Box<BoolExpr> {
242-
Box::new((Cmp { op, lhs, rhs }).into())
262+
pub fn make_cmp(&self, op: Ordering, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> BoolExpr {
263+
(Cmp { op, lhs, rhs }).into()
243264
}
244265

245266
/// Create a "less than" ([`BoolExpr::Cmp`]) expression
246-
pub fn make_lt(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> Box<BoolExpr> {
267+
pub fn make_lt(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> BoolExpr {
247268
self.make_cmp(Ordering::Less { strict: true }, lhs, rhs)
248269
}
249270

250271
/// Create a "less than or equal" ([`BoolExpr::Cmp`]) expression
251-
pub fn make_le(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> Box<BoolExpr> {
272+
pub fn make_le(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> BoolExpr {
252273
self.make_cmp(Ordering::Less { strict: false }, lhs, rhs)
253274
}
254275

255276
/// Create a "greater than" ([`BoolExpr::Cmp`]) expression
256-
pub fn make_gt(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> Box<BoolExpr> {
277+
pub fn make_gt(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> BoolExpr {
257278
self.make_cmp(Ordering::Greater { strict: true }, lhs, rhs)
258279
}
259280

260281
/// Create a "greater than or equal" ([`BoolExpr::Cmp`]) expression
261-
pub fn make_ge(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> Box<BoolExpr> {
282+
pub fn make_ge(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> BoolExpr {
262283
self.make_cmp(Ordering::Greater { strict: false }, lhs, rhs)
263284
}
264285

265286
/// Create a "equals" ([`BoolExpr::Cmp`]) expression
266-
pub fn make_eq(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> Box<BoolExpr> {
287+
pub fn make_eq(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> BoolExpr {
267288
self.make_cmp(Ordering::Eq, lhs, rhs)
268289
}
269290

270291
/// Create a "not equals" ([`BoolExpr::Cmp`]) expression
271-
pub fn make_neq(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> Box<BoolExpr> {
292+
pub fn make_neq(&self, lhs: Box<NumExpr>, rhs: Box<NumExpr>) -> BoolExpr {
272293
self.make_cmp(Ordering::NotEq, lhs, rhs)
273294
}
274295

275296
/// Create a [`BoolExpr::Not`] expression.
276-
pub fn make_not(&self, arg: Box<BoolExpr>) -> Box<BoolExpr> {
277-
Box::new((Not { arg }).into())
297+
pub fn make_not(&self, arg: Box<BoolExpr>) -> BoolExpr {
298+
(Not { arg }).into()
278299
}
279300

280301
/// Create a [`BoolExpr::Or`] expression.
281-
pub fn make_or<I>(&self, args: I) -> ArgusResult<Box<BoolExpr>>
302+
pub fn make_or<I>(&self, args: I) -> ArgusResult<BoolExpr>
282303
where
283304
I: IntoIterator<Item = BoolExpr>,
284305
{
285-
let args: Vec<_> = args.into_iter().collect();
286-
if args.len() < 2 {
306+
let mut new_args = Vec::<BoolExpr>::new();
307+
for arg in args.into_iter() {
308+
// Flatten the args if there is an Or
309+
if let BoolExpr::Or(Or { args }) = arg {
310+
new_args.extend(args.into_iter());
311+
} else {
312+
new_args.push(arg);
313+
}
314+
}
315+
if new_args.len() < 2 {
287316
Err(Error::IncompleteArgs)
288317
} else {
289-
Ok(Box::new((Or { args }).into()))
318+
Ok((Or { args: new_args }).into())
290319
}
291320
}
292321

293322
/// Create a [`BoolExpr::And`] expression.
294-
pub fn make_and<I>(&self, args: I) -> ArgusResult<Box<BoolExpr>>
323+
pub fn make_and<I>(&self, args: I) -> ArgusResult<BoolExpr>
295324
where
296325
I: IntoIterator<Item = BoolExpr>,
297326
{
298-
let args: Vec<_> = args.into_iter().collect();
299-
if args.len() < 2 {
327+
let mut new_args = Vec::<BoolExpr>::new();
328+
for arg in args.into_iter() {
329+
// Flatten the args if there is an And
330+
if let BoolExpr::And(And { args }) = arg {
331+
new_args.extend(args.into_iter());
332+
} else {
333+
new_args.push(arg);
334+
}
335+
}
336+
if new_args.len() < 2 {
300337
Err(Error::IncompleteArgs)
301338
} else {
302-
Ok(Box::new((And { args }).into()))
339+
Ok((And { args: new_args }).into())
303340
}
304341
}
305342

343+
/// Create an expression equivalent to `lhs -> rhs`.
344+
///
345+
/// This essentially breaks down the expression as `~lhs | rhs`.
346+
#[allow(clippy::boxed_local)]
347+
pub fn make_implies(&self, lhs: Box<BoolExpr>, rhs: Box<BoolExpr>) -> ArgusResult<BoolExpr> {
348+
let np = self.make_not(lhs);
349+
self.make_or([np, *rhs])
350+
}
351+
352+
/// Create an expression equivalent to `lhs <-> rhs`.
353+
///
354+
/// This essentially breaks down the expression as `(lhs & rhs) | (~lhs & ~rhs)`.
355+
pub fn make_equiv(&self, lhs: Box<BoolExpr>, rhs: Box<BoolExpr>) -> ArgusResult<BoolExpr> {
356+
let np = self.make_not(lhs.clone());
357+
let nq = self.make_not(rhs.clone());
358+
359+
let npnq = self.make_and([np, nq])?;
360+
let pq = self.make_and([*lhs, *rhs])?;
361+
362+
self.make_or([pq, npnq])
363+
}
364+
365+
/// Create an expression equivalent to `lhs ^ rhs`.
366+
///
367+
/// This essentially breaks down the expression as `~(lhs <-> rhs)`.
368+
pub fn make_xor(&self, lhs: Box<BoolExpr>, rhs: Box<BoolExpr>) -> ArgusResult<BoolExpr> {
369+
Ok(self.make_not(Box::new(self.make_equiv(lhs, rhs)?)))
370+
}
371+
306372
/// Create a [`BoolExpr::Next`] expression.
307-
pub fn make_next(&self, arg: Box<BoolExpr>) -> Box<BoolExpr> {
308-
Box::new((Next { arg }).into())
373+
pub fn make_next(&self, arg: Box<BoolExpr>) -> BoolExpr {
374+
(Next { arg }).into()
309375
}
310376

311377
/// Create a [`BoolExpr::Oracle`] expression.
312-
pub fn make_oracle(&self, steps: usize, arg: Box<BoolExpr>) -> Box<BoolExpr> {
313-
Box::new((Oracle { steps, arg }).into())
378+
pub fn make_oracle(&self, steps: usize, arg: Box<BoolExpr>) -> BoolExpr {
379+
if steps == 1 {
380+
self.make_next(arg)
381+
} else {
382+
(Oracle { steps, arg }).into()
383+
}
314384
}
315385

316386
/// Create a [`BoolExpr::Always`] expression.
317-
pub fn make_always(&self, arg: Box<BoolExpr>) -> Box<BoolExpr> {
318-
Box::new(
319-
(Always {
320-
arg,
321-
interval: (..).into(),
322-
})
323-
.into(),
324-
)
387+
pub fn make_always(&self, arg: Box<BoolExpr>) -> BoolExpr {
388+
(Always {
389+
arg,
390+
interval: (..).into(),
391+
})
392+
.into()
325393
}
326394

327395
/// Create a [`BoolExpr::Always`] expression with an interval.
328-
pub fn make_timed_always(&self, interval: Interval, arg: Box<BoolExpr>) -> Box<BoolExpr> {
329-
Box::new((Always { arg, interval }).into())
396+
pub fn make_timed_always(&self, interval: Interval, arg: Box<BoolExpr>) -> BoolExpr {
397+
(Always { arg, interval }).into()
330398
}
331399

332400
/// Create a [`BoolExpr::Eventually`] expression.
333-
pub fn make_eventually(&self, arg: Box<BoolExpr>) -> Box<BoolExpr> {
334-
Box::new(
335-
(Eventually {
336-
arg,
337-
interval: (..).into(),
338-
})
339-
.into(),
340-
)
401+
pub fn make_eventually(&self, arg: Box<BoolExpr>) -> BoolExpr {
402+
(Eventually {
403+
arg,
404+
interval: (..).into(),
405+
})
406+
.into()
341407
}
342408

343409
/// Create a [`BoolExpr::Eventually`] expression with an interval.
344-
pub fn make_timed_eventually(&self, interval: Interval, arg: Box<BoolExpr>) -> Box<BoolExpr> {
345-
Box::new((Eventually { arg, interval }).into())
410+
pub fn make_timed_eventually(&self, interval: Interval, arg: Box<BoolExpr>) -> BoolExpr {
411+
(Eventually { arg, interval }).into()
346412
}
347413

348414
/// Create a [`BoolExpr::Until`] expression.
349-
pub fn make_until(&self, lhs: Box<BoolExpr>, rhs: Box<BoolExpr>) -> Box<BoolExpr> {
350-
Box::new(
351-
(Until {
352-
lhs,
353-
rhs,
354-
interval: (..).into(),
355-
})
356-
.into(),
357-
)
415+
pub fn make_until(&self, lhs: Box<BoolExpr>, rhs: Box<BoolExpr>) -> BoolExpr {
416+
(Until {
417+
lhs,
418+
rhs,
419+
interval: (..).into(),
420+
})
421+
.into()
358422
}
359423

360424
/// Create a [`BoolExpr::Until`] expression with an interval.
361-
pub fn make_timed_until(&self, interval: Interval, lhs: Box<BoolExpr>, rhs: Box<BoolExpr>) -> Box<BoolExpr> {
362-
Box::new((Until { lhs, rhs, interval }).into())
425+
pub fn make_timed_until(&self, interval: Interval, lhs: Box<BoolExpr>, rhs: Box<BoolExpr>) -> BoolExpr {
426+
BoolExpr::from(Until { lhs, rhs, interval })
363427
}
364428
}
365429

argus-core/src/expr/iter.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ mod tests {
5353
fn simple_iter() {
5454
let mut ctx = ExprBuilder::new();
5555

56-
let x = ctx.float_var("x".to_owned()).unwrap();
57-
let y = ctx.float_var("y".to_owned()).unwrap();
58-
let lit = ctx.float_const(2.0);
56+
let x = Box::new(ctx.float_var("x".to_owned()).unwrap());
57+
let y = Box::new(ctx.float_var("y".to_owned()).unwrap());
58+
let lit = Box::new(ctx.float_const(2.0));
5959

60-
let pred1 = ctx.make_le(x.clone(), lit.clone());
61-
let pred2 = ctx.make_gt(y.clone(), lit.clone());
62-
let spec = ctx.make_or([*pred1.clone(), *pred2.clone()]).unwrap();
60+
let pred1 = Box::new(ctx.make_le(x.clone(), lit.clone()));
61+
let pred2 = Box::new(ctx.make_gt(y.clone(), lit.clone()));
62+
let spec = Box::new(ctx.make_or([*pred1.clone(), *pred2.clone()]).unwrap());
6363

6464
drop(ctx);
6565

0 commit comments

Comments
 (0)