@@ -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{
43124356public:
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
43544462template <>
@@ -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