Skip to content

Commit 31cd424

Browse files
author
Daniel Kroening
authored
Merge pull request #4992 from diffblue/let-is-a-binding
let_exprt can now do multiple bindings
2 parents 093e97c + 71a20e9 commit 31cd424

File tree

4 files changed

+150
-55
lines changed

4 files changed

+150
-55
lines changed

src/util/irep_ids.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
IREP_ID_TWO(empty_string, )
66
IREP_ID_ONE(let)
7+
IREP_ID_ONE(let_binding)
78
IREP_ID_ONE(nil)
89
IREP_ID_ONE(type)
910
IREP_ID_ONE(bool)

src/util/mathematical_expr.h

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -271,47 +271,6 @@ inline function_application_exprt &to_function_application_expr(exprt &expr)
271271
return ret;
272272
}
273273

274-
/// \brief A base class for variable bindings (quantifiers, let, lambda)
275-
class binding_exprt : public binary_exprt
276-
{
277-
public:
278-
using variablest = std::vector<symbol_exprt>;
279-
280-
/// construct the binding expression
281-
binding_exprt(
282-
irep_idt _id,
283-
const variablest &_variables,
284-
exprt _where,
285-
typet _type)
286-
: binary_exprt(
287-
tuple_exprt((const operandst &)_variables),
288-
_id,
289-
std::move(_where),
290-
std::move(_type))
291-
{
292-
}
293-
294-
variablest &variables()
295-
{
296-
return (variablest &)static_cast<tuple_exprt &>(op0()).operands();
297-
}
298-
299-
const variablest &variables() const
300-
{
301-
return (variablest &)static_cast<const tuple_exprt &>(op0()).operands();
302-
}
303-
304-
exprt &where()
305-
{
306-
return op1();
307-
}
308-
309-
const exprt &where() const
310-
{
311-
return op1();
312-
}
313-
};
314-
315274
/// \brief A base class for quantifier expressions
316275
class quantifier_exprt : public binding_exprt
317276
{

src/util/std_expr.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Author: Daniel Kroening, [email protected]
1717
#include "mathematical_types.h"
1818
#include "namespace.h"
1919
#include "pointer_offset_size.h"
20+
#include "range.h"
2021
#include "simplify_expr.h"
2122

2223
bool constant_exprt::value_is_zero_string() const
@@ -303,3 +304,29 @@ void dereference_exprt::validate(
303304
"dereference expression's type must match the subtype of the type of its "
304305
"operand");
305306
}
307+
308+
void let_exprt::validate(const exprt &expr, const validation_modet vm)
309+
{
310+
check(expr, vm);
311+
312+
const auto &let_expr = to_let_expr(expr);
313+
314+
DATA_CHECK(
315+
vm,
316+
let_expr.values().size() == let_expr.variables().size(),
317+
"number of variables must match number of values");
318+
319+
for(const auto &binding :
320+
make_range(let_expr.variables()).zip(let_expr.values()))
321+
{
322+
DATA_CHECK(
323+
vm,
324+
binding.first.id() == ID_symbol,
325+
"let binding symbols must be symbols");
326+
327+
DATA_CHECK(
328+
vm,
329+
binding.first.type() == binding.second.type(),
330+
"let bindings must be type consistent");
331+
}
332+
}

src/util/std_expr.h

Lines changed: 122 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4306,49 +4306,157 @@ class infinity_exprt : public nullary_exprt
43064306
}
43074307
};
43084308

4309+
/// \brief A base class for variable bindings (quantifiers, let, lambda)
4310+
class binding_exprt : public binary_exprt
4311+
{
4312+
public:
4313+
using variablest = std::vector<symbol_exprt>;
4314+
4315+
/// construct the binding expression
4316+
binding_exprt(
4317+
irep_idt _id,
4318+
const variablest &_variables,
4319+
exprt _where,
4320+
typet _type)
4321+
: binary_exprt(
4322+
multi_ary_exprt(
4323+
ID_tuple,
4324+
(const operandst &)_variables,
4325+
typet(ID_tuple)),
4326+
_id,
4327+
std::move(_where),
4328+
std::move(_type))
4329+
{
4330+
}
4331+
4332+
variablest &variables()
4333+
{
4334+
return (variablest &)to_multi_ary_expr(op0()).operands();
4335+
}
4336+
4337+
const variablest &variables() const
4338+
{
4339+
return (variablest &)to_multi_ary_expr(op0()).operands();
4340+
}
4341+
4342+
exprt &where()
4343+
{
4344+
return op1();
4345+
}
4346+
4347+
const exprt &where() const
4348+
{
4349+
return op1();
4350+
}
4351+
};
4352+
43094353
/// \brief A let expression
4310-
class let_exprt : public ternary_exprt
4354+
class let_exprt : public binary_exprt
43114355
{
43124356
public:
4313-
let_exprt(symbol_exprt symbol, exprt value, const exprt &where)
4314-
: ternary_exprt(
4357+
let_exprt(
4358+
binding_exprt::variablest variables,
4359+
operandst values,
4360+
const exprt &where)
4361+
: binary_exprt(
4362+
binding_exprt(
4363+
ID_let_binding,
4364+
std::move(variables),
4365+
where,
4366+
where.type()),
43154367
ID_let,
4316-
std::move(symbol),
4317-
std::move(value),
4318-
where,
4368+
multi_ary_exprt(irep_idt(), std::move(values), typet(ID_tuple)),
43194369
where.type())
43204370
{
4371+
PRECONDITION(this->variables().size() == this->values().size());
43214372
}
43224373

4374+
/// convenience constructor for the case of a single binding
4375+
let_exprt(symbol_exprt symbol, exprt value, const exprt &where)
4376+
: let_exprt(
4377+
binding_exprt::variablest{std::move(symbol)},
4378+
operandst{std::move(value)},
4379+
where)
4380+
{
4381+
}
4382+
4383+
binding_exprt &binding()
4384+
{
4385+
return static_cast<binding_exprt &>(op0());
4386+
}
4387+
4388+
const binding_exprt &binding() const
4389+
{
4390+
return static_cast<const binding_exprt &>(op0());
4391+
}
4392+
4393+
/// convenience accessor for the symbol of a single binding
43234394
symbol_exprt &symbol()
43244395
{
4325-
return static_cast<symbol_exprt &>(op0());
4396+
auto &variables = binding().variables();
4397+
PRECONDITION(variables.size() == 1);
4398+
return variables.front();
43264399
}
43274400

4401+
/// convenience accessor for the symbol of a single binding
43284402
const symbol_exprt &symbol() const
43294403
{
4330-
return static_cast<const symbol_exprt &>(op0());
4404+
const auto &variables = binding().variables();
4405+
PRECONDITION(variables.size() == 1);
4406+
return variables.front();
43314407
}
43324408

4409+
/// convenience accessor for the value of a single binding
43334410
exprt &value()
43344411
{
4335-
return op1();
4412+
auto &values = this->values();
4413+
PRECONDITION(values.size() == 1);
4414+
return values.front();
43364415
}
43374416

4417+
/// convenience accessor for the value of a single binding
43384418
const exprt &value() const
43394419
{
4340-
return op1();
4420+
const auto &values = this->values();
4421+
PRECONDITION(values.size() == 1);
4422+
return values.front();
43414423
}
43424424

4425+
operandst &values()
4426+
{
4427+
return static_cast<multi_ary_exprt &>(op1()).operands();
4428+
}
4429+
4430+
const operandst &values() const
4431+
{
4432+
return static_cast<const multi_ary_exprt &>(op1()).operands();
4433+
}
4434+
4435+
/// convenience accessor for binding().variables()
4436+
binding_exprt::variablest &variables()
4437+
{
4438+
return binding().variables();
4439+
}
4440+
4441+
/// convenience accessor for binding().variables()
4442+
const binding_exprt::variablest &variables() const
4443+
{
4444+
return binding().variables();
4445+
}
4446+
4447+
/// convenience accessor for binding().where()
43434448
exprt &where()
43444449
{
4345-
return op2();
4450+
return binding().where();
43464451
}
43474452

4453+
/// convenience accessor for binding().where()
43484454
const exprt &where() const
43494455
{
4350-
return op2();
4456+
return binding().where();
43514457
}
4458+
4459+
static void validate(const exprt &, validation_modet);
43524460
};
43534461

43544462
template <>
@@ -4357,9 +4465,9 @@ inline bool can_cast_expr<let_exprt>(const exprt &base)
43574465
return base.id() == ID_let;
43584466
}
43594467

4360-
inline void validate_expr(const let_exprt &value)
4468+
inline void validate_expr(const let_exprt &let_expr)
43614469
{
4362-
validate_operands(value, 3, "Let must have three operands");
4470+
validate_operands(let_expr, 2, "Let must have two operands");
43634471
}
43644472

43654473
/// \brief Cast an exprt to a \ref let_exprt

0 commit comments

Comments
 (0)