Skip to content

Commit cff58cd

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 724efb2 commit cff58cd

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
@@ -4324,48 +4324,112 @@ class binding_exprt : public binary_exprt
43244324
};
43254325

43264326
/// \brief A let expression
4327-
class let_exprt : public ternary_exprt
4327+
class let_exprt : public binary_exprt
43284328
{
43294329
public:
4330-
let_exprt(symbol_exprt symbol, exprt value, const exprt &where)
4331-
: ternary_exprt(
4330+
let_exprt(
4331+
binding_exprt::variablest variables,
4332+
operandst values,
4333+
const exprt &where)
4334+
: binary_exprt(
4335+
binding_exprt(
4336+
ID_let_binding,
4337+
std::move(variables),
4338+
where,
4339+
where.type()),
43324340
ID_let,
4333-
std::move(symbol),
4334-
std::move(value),
4335-
where,
4341+
multi_ary_exprt(irep_idt(), std::move(values), typet(ID_tuple)),
43364342
where.type())
43374343
{
4344+
PRECONDITION(this->variables().size() == this->values().size());
4345+
}
4346+
4347+
/// convenience constructor for the case of a single binding
4348+
let_exprt(symbol_exprt symbol, exprt value, const exprt &where)
4349+
: let_exprt(
4350+
binding_exprt::variablest{std::move(symbol)},
4351+
operandst{std::move(value)},
4352+
where)
4353+
{
4354+
}
4355+
4356+
binding_exprt &binding()
4357+
{
4358+
return static_cast<binding_exprt &>(op0());
4359+
}
4360+
4361+
const binding_exprt &binding() const
4362+
{
4363+
return static_cast<const binding_exprt &>(op0());
43384364
}
43394365

4366+
/// convenience accessor for the symbol of a single binding
43404367
symbol_exprt &symbol()
43414368
{
4342-
return static_cast<symbol_exprt &>(op0());
4369+
auto &variables = binding().variables();
4370+
PRECONDITION(variables.size() == 1);
4371+
return variables.front();
43434372
}
43444373

4374+
/// convenience accessor for the symbol of a single binding
43454375
const symbol_exprt &symbol() const
43464376
{
4347-
return static_cast<const symbol_exprt &>(op0());
4377+
const auto &variables = binding().variables();
4378+
PRECONDITION(variables.size() == 1);
4379+
return variables.front();
43484380
}
43494381

4382+
/// convenience accessor for the value of a single binding
43504383
exprt &value()
43514384
{
4352-
return op1();
4385+
auto &values = this->values();
4386+
PRECONDITION(values.size() == 1);
4387+
return values.front();
43534388
}
43544389

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

4420+
/// convenience accessor for binding().where()
43604421
exprt &where()
43614422
{
4362-
return op2();
4423+
return binding().where();
43634424
}
43644425

4426+
/// convenience accessor for binding().where()
43654427
const exprt &where() const
43664428
{
4367-
return op2();
4429+
return binding().where();
43684430
}
4431+
4432+
static void validate(const exprt &, validation_modet);
43694433
};
43704434

43714435
template <>
@@ -4374,9 +4438,9 @@ inline bool can_cast_expr<let_exprt>(const exprt &base)
43744438
return base.id() == ID_let;
43754439
}
43764440

4377-
inline void validate_expr(const let_exprt &value)
4441+
inline void validate_expr(const let_exprt &let_expr)
43784442
{
4379-
validate_operands(value, 3, "Let must have three operands");
4443+
validate_operands(let_expr, 2, "Let must have two operands");
43804444
}
43814445

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

0 commit comments

Comments
 (0)