Skip to content

Commit 5f0808c

Browse files
author
Daniel Kroening
committed
added lambda_exprt
1 parent 7834994 commit 5f0808c

File tree

6 files changed

+159
-5
lines changed

6 files changed

+159
-5
lines changed

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,13 +289,12 @@ void c_typecheck_baset::typecheck_expr_main(exprt &expr)
289289
// already fine, just set some type
290290
expr.type()=void_type();
291291
}
292-
else if(expr.id()==ID_forall ||
293-
expr.id()==ID_exists)
292+
else if(
293+
expr.id() == ID_forall || expr.id() == ID_exists || expr.id() == ID_lambda)
294294
{
295295
// op0 is a declaration,
296296
// op1 the bound expression
297297
assert(expr.operands().size()==2);
298-
expr.type()=bool_typet();
299298

300299
if(expr.op0().get(ID_statement)!=ID_decl)
301300
{
@@ -315,7 +314,16 @@ void c_typecheck_baset::typecheck_expr_main(exprt &expr)
315314
symbol_exprt bound=to_symbol_expr(expr.op0().op0());
316315
expr.op0().swap(bound);
317316

318-
implicit_typecast_bool(expr.op1());
317+
if(expr.id() == ID_lambda)
318+
{
319+
expr.type() =
320+
mathematical_function_typet({expr.op0().type()}, expr.op1().type());
321+
}
322+
else
323+
{
324+
expr.type() = bool_typet();
325+
implicit_typecast_bool(expr.op1());
326+
}
319327
}
320328
else if(expr.id()==ID_label)
321329
{
@@ -736,7 +744,8 @@ void c_typecheck_baset::typecheck_expr_operands(exprt &expr)
736744
{
737745
typecheck_code(to_code(expr.op0()));
738746
}
739-
else if(expr.id()==ID_forall || expr.id()==ID_exists)
747+
else if(
748+
expr.id() == ID_forall || expr.id() == ID_exists || expr.id() == ID_lambda)
740749
{
741750
assert(expr.operands().size()==2);
742751

src/ansi-c/parser.y

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ extern char *yyansi_ctext;
187187
%token TOK_EXISTS "exists"
188188
%token TOK_ACSL_FORALL "\\forall"
189189
%token TOK_ACSL_EXISTS "\\exists"
190+
%token TOK_ACSL_LAMBDA "\\lambda"
190191
%token TOK_ACSL_LET "\\let"
191192
%token TOK_ARRAY_OF "array_of"
192193
%token TOK_CPROVER_BITVECTOR "__CPROVER_bitvector"
@@ -500,6 +501,16 @@ quantifier_expression:
500501
mto($$, $4);
501502
PARSER.pop_scope();
502503
}
504+
| TOK_ACSL_LAMBDA compound_scope declaration primary_expression
505+
{
506+
// The precedence of this operator is too high; it is meant
507+
// to bind only very weakly.
508+
$$=$1;
509+
set($$, ID_lambda);
510+
mto($$, $3);
511+
mto($$, $4);
512+
PARSER.pop_scope();
513+
}
503514
;
504515

505516
loop_invariant_opt:

src/ansi-c/scanner.l

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,6 +1287,10 @@ __decltype { if(PARSER.cpp98 &&
12871287
loc(); return TOK_ACSL_EXISTS;
12881288
}
12891289

1290+
"\\lambda" { /* Non-standard, obviously. Found in ACSL syntax. */
1291+
loc(); return TOK_ACSL_LAMBDA;
1292+
}
1293+
12901294
"\\let" { /* Non-standard, obviously. Found in ACSL syntax. */
12911295
loc(); return TOK_ACSL_LET;
12921296
}

src/util/format_expr.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,17 +287,43 @@ std::ostream &format_rec(std::ostream &os, const exprt &expr)
287287
else if(id == ID_type)
288288
return format_rec(os, expr.type());
289289
else if(id == ID_forall)
290+
{
290291
return os << u8"\u2200 " << format(to_quantifier_expr(expr).symbol())
291292
<< " : " << format(to_quantifier_expr(expr).symbol().type())
292293
<< " . " << format(to_quantifier_expr(expr).where());
294+
}
293295
else if(id == ID_exists)
296+
{
294297
return os << u8"\u2203 " << format(to_quantifier_expr(expr).symbol())
295298
<< " : " << format(to_quantifier_expr(expr).symbol().type())
296299
<< " . " << format(to_quantifier_expr(expr).where());
300+
}
297301
else if(id == ID_let)
302+
{
298303
return os << "LET " << format(to_let_expr(expr).symbol()) << " = "
299304
<< format(to_let_expr(expr).value()) << " IN "
300305
<< format(to_let_expr(expr).where());
306+
}
307+
else if(id == ID_lambda)
308+
{
309+
const auto &lambda_expr = to_lambda_expr(expr);
310+
311+
os << u8"\u1d706 ";
312+
313+
bool first = true;
314+
315+
for(auto &v : lambda_expr.variables())
316+
{
317+
if(first)
318+
first = false;
319+
else
320+
os << ", ";
321+
322+
os << format(v);
323+
}
324+
325+
return os << " . " << format(lambda_expr.where());
326+
}
301327
else if(id == ID_array || id == ID_struct)
302328
{
303329
os << "{ ";

src/util/mathematical_expr.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,25 @@ function_application_exprt::function_application_exprt(
2121
const auto &domain = to_mathematical_function_type(_function.type()).domain();
2222
PRECONDITION(domain.size() == arguments().size());
2323
}
24+
25+
static mathematical_function_typet
26+
lambda_type(const lambda_exprt::variablest &variables, exprt where)
27+
{
28+
mathematical_function_typet::domaint domain;
29+
30+
domain.reserve(variables.size());
31+
32+
for(const auto &v : variables)
33+
domain.push_back(v.type());
34+
35+
return mathematical_function_typet(std::move(domain), where.type());
36+
}
37+
38+
lambda_exprt::lambda_exprt(const variablest &_variables, exprt _where)
39+
: binary_exprt(
40+
tuple_exprt((const operandst &)_variables),
41+
ID_lambda,
42+
_where,
43+
lambda_type(_variables, _where))
44+
{
45+
}

src/util/mathematical_expr.h

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212
/// \file util/mathematical_expr.h
1313
/// API to expression classes for 'mathematical' expressions
1414

15+
#include "mathematical_types.h"
1516
#include "std_expr.h"
1617

1718
/// Transition system, consisting of state invariant, initial state predicate,
@@ -392,4 +393,85 @@ inline exists_exprt &to_exists_expr(exprt &expr)
392393
return ret;
393394
}
394395

396+
/// \brief A (mathematical) lambda expression (an "abstraction" in lambda
397+
/// calculus terminology)
398+
class lambda_exprt : public binary_exprt
399+
{
400+
public:
401+
using variablest = std::vector<symbol_exprt>;
402+
403+
/// construct the lambda expression -- the type is derived from
404+
/// the types of the variables and the expression
405+
lambda_exprt(const variablest &_variables, exprt _where);
406+
407+
mathematical_function_typet &type()
408+
{
409+
return static_cast<mathematical_function_typet &>(binary_exprt::type());
410+
}
411+
412+
const mathematical_function_typet &type() const
413+
{
414+
return static_cast<const mathematical_function_typet &>(
415+
binary_exprt::type());
416+
}
417+
418+
variablest &variables()
419+
{
420+
return (variablest &)static_cast<tuple_exprt &>(op0()).operands();
421+
}
422+
423+
const variablest &variables() const
424+
{
425+
return (variablest &)static_cast<const tuple_exprt &>(op0()).operands();
426+
}
427+
428+
exprt &where()
429+
{
430+
return op1();
431+
}
432+
433+
const exprt &where() const
434+
{
435+
return op1();
436+
}
437+
};
438+
439+
/// \brief Cast an exprt to a \ref lambda_exprt
440+
///
441+
/// \a expr must be known to be \ref lambda_exprt.
442+
///
443+
/// \param expr: Source expression
444+
/// \return Object of type \ref lambda_exprt
445+
inline const lambda_exprt &to_lambda_expr(const exprt &expr)
446+
{
447+
PRECONDITION(expr.id() == ID_lambda);
448+
DATA_INVARIANT(expr.operands().size() == 2, "lambda must have two operands");
449+
DATA_INVARIANT(
450+
expr.type().id() == ID_mathematical_function,
451+
"lambda must have right type");
452+
return static_cast<const lambda_exprt &>(expr);
453+
}
454+
455+
/// \copydoc to_lambda_expr(const exprt &)
456+
inline lambda_exprt &to_lambda_expr(exprt &expr)
457+
{
458+
PRECONDITION(expr.id() == ID_lambda);
459+
DATA_INVARIANT(expr.operands().size() == 2, "lambda must have two operands");
460+
DATA_INVARIANT(
461+
expr.type().id() == ID_mathematical_function,
462+
"lambda must have right type");
463+
return static_cast<lambda_exprt &>(expr);
464+
}
465+
466+
template <>
467+
inline bool can_cast_expr<lambda_exprt>(const exprt &base)
468+
{
469+
return base.id() == ID_lambda;
470+
}
471+
472+
inline void validate_expr(const lambda_exprt &value)
473+
{
474+
validate_operands(value, 2, "lambda must have two operands");
475+
}
476+
395477
#endif // CPROVER_UTIL_MATHEMATICAL_EXPR_H

0 commit comments

Comments
 (0)