Skip to content

Commit d5163b7

Browse files
author
Daniel Kroening
committed
let_exprt can now do multiple bindings
This matches what the SMT-LIB standard does. It also matches what our own binding_exprt can do, i.e., let_exprt can be re-written into a lambda binding plus a function application in the standard way.
1 parent 9a3ffde commit d5163b7

File tree

2 files changed

+90
-12
lines changed

2 files changed

+90
-12
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.h

Lines changed: 89 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4283,47 +4283,109 @@ class infinity_exprt : public nullary_exprt
42834283
};
42844284

42854285
/// \brief A let expression
4286-
class let_exprt : public ternary_exprt
4286+
class let_exprt : public binary_exprt
42874287
{
42884288
public:
4289-
let_exprt(symbol_exprt symbol, exprt value, const exprt &where)
4290-
: ternary_exprt(
4289+
class let_binding_exprt : public binary_exprt
4290+
{
4291+
public:
4292+
let_binding_exprt(symbol_exprt symbol, exprt value)
4293+
: binary_exprt(
4294+
std::move(symbol),
4295+
ID_let,
4296+
std::move(value),
4297+
typet(ID_tuple))
4298+
{
4299+
}
4300+
4301+
const symbol_exprt &symbol() const
4302+
{
4303+
return static_cast<const symbol_exprt &>(op0());
4304+
}
4305+
4306+
symbol_exprt &symbol()
4307+
{
4308+
return static_cast<symbol_exprt &>(op0());
4309+
}
4310+
4311+
const exprt &value() const
4312+
{
4313+
return op1();
4314+
}
4315+
4316+
exprt &value()
4317+
{
4318+
return op1();
4319+
}
4320+
};
4321+
4322+
using bindingst = std::vector<let_binding_exprt>;
4323+
4324+
let_exprt(const bindingst &bindings, const exprt &where)
4325+
: binary_exprt(
4326+
multi_ary_exprt(ID_tuple, (const operandst &)bindings, typet(ID_tuple)),
42914327
ID_let,
4292-
std::move(symbol),
4293-
std::move(value),
42944328
where,
42954329
where.type())
42964330
{
42974331
}
42984332

4333+
/// convenience constructor for the case of a single binding
4334+
let_exprt(symbol_exprt symbol, exprt value, const exprt &where)
4335+
: let_exprt({ let_binding_exprt(std::move(symbol), std::move(value)) }, where)
4336+
{
4337+
}
4338+
4339+
bindingst &bindings()
4340+
{
4341+
return (bindingst &)op0().operands();
4342+
}
4343+
4344+
const bindingst &bindings() const
4345+
{
4346+
return (bindingst &)op0().operands();
4347+
}
4348+
4349+
/// convenience accessor for the symbol of a single binding
42994350
symbol_exprt &symbol()
43004351
{
4301-
return static_cast<symbol_exprt &>(op0());
4352+
auto &bindings = this->bindings();
4353+
PRECONDITION(bindings.size() == 1);
4354+
return bindings.front().symbol();
43024355
}
43034356

4357+
/// convenience accessor for the symbol of a single binding
43044358
const symbol_exprt &symbol() const
43054359
{
4306-
return static_cast<const symbol_exprt &>(op0());
4360+
const auto &bindings = this->bindings();
4361+
PRECONDITION(bindings.size() == 1);
4362+
return bindings.front().symbol();
43074363
}
43084364

4365+
/// convenience accessor for the value of a single binding
43094366
exprt &value()
43104367
{
4311-
return op1();
4368+
auto &bindings = this->bindings();
4369+
PRECONDITION(bindings.size() == 1);
4370+
return bindings.front().value();
43124371
}
43134372

4373+
/// convenience accessor for the value of a single binding
43144374
const exprt &value() const
43154375
{
4316-
return op1();
4376+
const auto &bindings = this->bindings();
4377+
PRECONDITION(bindings.size() == 1);
4378+
return bindings.front().value();
43174379
}
43184380

43194381
exprt &where()
43204382
{
4321-
return op2();
4383+
return op1();
43224384
}
43234385

43244386
const exprt &where() const
43254387
{
4326-
return op2();
4388+
return op1();
43274389
}
43284390
};
43294391

@@ -4335,7 +4397,22 @@ inline bool can_cast_expr<let_exprt>(const exprt &base)
43354397

43364398
inline void validate_expr(const let_exprt &value)
43374399
{
4338-
validate_operands(value, 3, "Let must have three operands");
4400+
validate_operands(value, 2, "Let must have two operands");
4401+
4402+
// symbols and assignments alternate
4403+
for(const auto &binding : value.bindings())
4404+
{
4405+
DATA_INVARIANT(
4406+
binding.id() == ID_let_binding, "let bindings must have correct id");
4407+
4408+
DATA_INVARIANT(
4409+
binding.symbol().id() == ID_symbol,
4410+
"let binding symbols must be symbols");
4411+
4412+
DATA_INVARIANT(
4413+
binding.symbol().type() == binding.value().type(),
4414+
"let bindings must be type consistent");
4415+
}
43394416
}
43404417

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

0 commit comments

Comments
 (0)