Skip to content

Commit eba4578

Browse files
author
Daniel Kroening
committed
let_exprt now uses binding_exprt
This enables let_exprt to do multiple binding, which matches what the SMT-LIB standard does. The new let_exprt can be re-written into a lambda binding plus a function application in the standard way.
1 parent 2d6cc72 commit eba4578

File tree

3 files changed

+106
-14
lines changed

3 files changed

+106
-14
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/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: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4327,48 +4327,112 @@ class binding_exprt : public binary_exprt
43274327
};
43284328

43294329
/// \brief A let expression
4330-
class let_exprt : public ternary_exprt
4330+
class let_exprt : public binary_exprt
43314331
{
43324332
public:
4333-
let_exprt(symbol_exprt symbol, exprt value, const exprt &where)
4334-
: ternary_exprt(
4333+
let_exprt(
4334+
binding_exprt::variablest variables,
4335+
operandst values,
4336+
const exprt &where)
4337+
: binary_exprt(
4338+
binding_exprt(
4339+
ID_let_binding,
4340+
std::move(variables),
4341+
where,
4342+
where.type()),
43354343
ID_let,
4336-
std::move(symbol),
4337-
std::move(value),
4338-
where,
4344+
multi_ary_exprt(irep_idt(), std::move(values), typet(ID_tuple)),
43394345
where.type())
43404346
{
4347+
PRECONDITION(this->variables().size() == this->values().size());
4348+
}
4349+
4350+
/// convenience constructor for the case of a single binding
4351+
let_exprt(symbol_exprt symbol, exprt value, const exprt &where)
4352+
: let_exprt(
4353+
binding_exprt::variablest{std::move(symbol)},
4354+
operandst{std::move(value)},
4355+
where)
4356+
{
4357+
}
4358+
4359+
binding_exprt &binding()
4360+
{
4361+
return static_cast<binding_exprt &>(op0());
4362+
}
4363+
4364+
const binding_exprt &binding() const
4365+
{
4366+
return static_cast<const binding_exprt &>(op0());
43414367
}
43424368

4369+
/// convenience accessor for the symbol of a single binding
43434370
symbol_exprt &symbol()
43444371
{
4345-
return static_cast<symbol_exprt &>(op0());
4372+
auto &variables = binding().variables();
4373+
PRECONDITION(variables.size() == 1);
4374+
return variables.front();
43464375
}
43474376

4377+
/// convenience accessor for the symbol of a single binding
43484378
const symbol_exprt &symbol() const
43494379
{
4350-
return static_cast<const symbol_exprt &>(op0());
4380+
const auto &variables = binding().variables();
4381+
PRECONDITION(variables.size() == 1);
4382+
return variables.front();
43514383
}
43524384

4385+
/// convenience accessor for the value of a single binding
43534386
exprt &value()
43544387
{
4355-
return op1();
4388+
auto &values = this->values();
4389+
PRECONDITION(values.size() == 1);
4390+
return values.front();
43564391
}
43574392

4393+
/// convenience accessor for the value of a single binding
43584394
const exprt &value() const
43594395
{
4360-
return op1();
4396+
const auto &values = this->values();
4397+
PRECONDITION(values.size() == 1);
4398+
return values.front();
4399+
}
4400+
4401+
operandst &values()
4402+
{
4403+
return static_cast<multi_ary_exprt &>(op1()).operands();
4404+
}
4405+
4406+
const operandst &values() const
4407+
{
4408+
return static_cast<const multi_ary_exprt &>(op1()).operands();
4409+
}
4410+
4411+
/// convenience accessor for binding().variables()
4412+
binding_exprt::variablest &variables()
4413+
{
4414+
return binding().variables();
4415+
}
4416+
4417+
/// convenience accessor for binding().variables()
4418+
const binding_exprt::variablest &variables() const
4419+
{
4420+
return binding().variables();
43614421
}
43624422

4423+
/// convenience accessor for binding().where()
43634424
exprt &where()
43644425
{
4365-
return op2();
4426+
return binding().where();
43664427
}
43674428

4429+
/// convenience accessor for binding().where()
43684430
const exprt &where() const
43694431
{
4370-
return op2();
4432+
return binding().where();
43714433
}
4434+
4435+
static void validate(const exprt &, validation_modet);
43724436
};
43734437

43744438
template <>
@@ -4377,9 +4441,9 @@ inline bool can_cast_expr<let_exprt>(const exprt &base)
43774441
return base.id() == ID_let;
43784442
}
43794443

4380-
inline void validate_expr(const let_exprt &value)
4444+
inline void validate_expr(const let_exprt &let_expr)
43814445
{
4382-
validate_operands(value, 3, "Let must have three operands");
4446+
validate_operands(let_expr, 2, "Let must have two operands");
43834447
}
43844448

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

0 commit comments

Comments
 (0)