Skip to content

Commit fc0d32f

Browse files
committed
SMV: set type
This fixes typechecking for set literals, assignments from set literals to variables of the element type, and typechecking for the "in" set membership operator.
1 parent b0016ca commit fc0d32f

File tree

7 files changed

+106
-33
lines changed

7 files changed

+106
-33
lines changed

regression/smv/expressions/smv_set2.smv

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ ASSIGN init(x) := {1, 2, 3};
77
next(x) := x;
88

99
SPEC x in my_set;
10+
11+
-- the rhs set can be a singleton
12+
SPEC (x in 1) | (x in 2);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
KNOWNBUG
2+
smv_set3.smv
3+
--bdd
4+
^\[spec1\] x in my_set: PROVED$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring
9+
--
10+
The smv_setin operator is not implemented.

src/hw_cbmc_irep_ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ IREP_ID_ONE(smv_next)
2323
IREP_ID_ONE(smv_iff)
2424
IREP_ID_TWO(C_smv_iff, "#smv_iff")
2525
IREP_ID_ONE(smv_resize)
26+
IREP_ID_ONE(smv_set)
2627
IREP_ID_ONE(smv_setin)
2728
IREP_ID_ONE(smv_setnotin)
2829
IREP_ID_ONE(smv_signed_cast)

src/smvlang/expr2smv.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,10 @@ std::string type2smv(const typet &type, const namespacet &ns)
902902
{
903903
return type.get_string(ID_from) + ".." + type.get_string(ID_to);
904904
}
905+
else if(type.id() == ID_smv_set)
906+
{
907+
return "set";
908+
}
905909
else if(type.id()=="submodule")
906910
{
907911
auto code = type.get_string(ID_identifier);

src/smvlang/parser.y

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ static void new_module(YYSTYPE &module)
176176
%token LTLWFF_Token "LTLWFF"
177177
%token PSLWFF_Token "PSLWFF"
178178
%token COMPWFF_Token "COMPWFF"
179-
%token IN_Token "IN"
180179
%token MIN_Token "MIN"
181180
%token MAX_Token "MAX"
182181
%token MIRROR_Token "MIRROR"
@@ -289,7 +288,7 @@ static void new_module(YYSTYPE &module)
289288
%left EX_Token AX_Token EF_Token AF_Token EG_Token AG_Token E_Token A_Token U_Token R_Token V_Token F_Token G_Token H_Token O_Token S_Token T_Token X_Token Y_Token Z_Token EBF_Token ABF_Token EBG_Token ABG_Token
290289
%left EQUAL_Token NOTEQUAL_Token LT_Token GT_Token LE_Token GE_Token
291290
%left union_Token
292-
%left IN_Token NOTIN_Token
291+
%left in_Token
293292
%left mod_Token /* Precedence from CMU SMV, different from NuSMV */
294293
%left LTLT_Token GTGT_Token
295294
%left PLUS_Token MINUS_Token
@@ -673,7 +672,7 @@ formula : term
673672
term : variable_identifier
674673
| next_Token '(' term ')' { init($$, ID_smv_next); mto($$, $3); }
675674
| '(' formula ')' { $$=$2; }
676-
| '{' formula_list '}' { $$=$2; stack_expr($$).id("smv_nondet_choice"); }
675+
| '{' formula_list '}' { $$=$2; stack_expr($$).id(ID_smv_set); }
677676
| INC_Token '(' term ')' { init($$, "inc"); mto($$, $3); }
678677
| DEC_Token '(' term ')' { init($$, "dec"); mto($$, $3); }
679678
| ADD_Token '(' term ',' term ')' { j_binary($$, $3, ID_plus, $5); }
@@ -709,8 +708,7 @@ term : variable_identifier
709708
| term GT_Token term { binary($$, $1, ID_gt, $3); }
710709
| term GE_Token term { binary($$, $1, ID_ge, $3); }
711710
| term union_Token term { binary($$, $1, ID_smv_union, $3); }
712-
| term IN_Token term { binary($$, $1, ID_smv_setin, $3); }
713-
| term NOTIN_Token term { binary($$, $1, ID_smv_setnotin, $3); }
711+
| term in_Token term { binary($$, $1, ID_smv_setin, $3); }
714712
| extend_Token '(' term ',' term ')' { binary($$, $3, ID_smv_extend, $5); }
715713
| resize_Token '(' term ',' term ')' { binary($$, $3, ID_smv_resize, $5); }
716714
| signed_Token '(' term ')' { init($$, ID_smv_signed_cast); mto($$, $3); }

src/smvlang/scanner.l

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ void newlocation(YYSTYPE &x)
101101
"LTLWFF" token(LTLWFF_Token);
102102
"PSLWFF" token(PSLWFF_Token);
103103
"COMPWFF" token(COMPWFF_Token);
104-
"IN" token(IN_Token);
105104
"MIN" token(MIN_Token);
106105
"MAX" token(MAX_Token);
107106
"MIRROR" token(MIRROR_Token);

src/smvlang/smv_typecheck.cpp

Lines changed: 85 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,7 +1001,26 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode)
10011001
}
10021002
else if(expr.id() == ID_smv_setin)
10031003
{
1004-
expr.type()=bool_typet();
1004+
auto &lhs = to_binary_expr(expr).lhs();
1005+
auto &rhs = to_binary_expr(expr).rhs();
1006+
1007+
typecheck_expr_rec(lhs, mode);
1008+
typecheck_expr_rec(rhs, mode);
1009+
1010+
// The RHS can be a set or a singleton
1011+
if(rhs.type().id() == ID_smv_set)
1012+
{
1013+
}
1014+
else
1015+
{
1016+
typet op_type =
1017+
type_union(lhs.type(), rhs.type(), expr.source_location());
1018+
1019+
convert_expr_to(lhs, op_type);
1020+
convert_expr_to(rhs, op_type);
1021+
}
1022+
1023+
expr.type() = bool_typet();
10051024
}
10061025
else if(expr.id() == ID_smv_setnotin)
10071026
{
@@ -1232,6 +1251,11 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode)
12321251
<< "signed operand must have unsigned word type";
12331252
}
12341253
}
1254+
else if(expr.id() == ID_smv_set)
1255+
{
1256+
// a set literal
1257+
expr.type() = typet{ID_smv_set};
1258+
}
12351259
else
12361260
{
12371261
throw errort().with_location(expr.find_source_location())
@@ -1285,28 +1309,50 @@ Function: smv_typecheckt::convert_expr_to
12851309
12861310
\*******************************************************************/
12871311

1288-
void smv_typecheckt::convert_expr_to(exprt &expr, const typet &type)
1312+
void smv_typecheckt::convert_expr_to(exprt &expr, const typet &dest_type)
12891313
{
1290-
PRECONDITION(type.is_not_nil());
1314+
const auto &src_type = expr.type();
12911315

1292-
if(expr.type() != type)
1316+
PRECONDITION(dest_type.is_not_nil());
1317+
1318+
if(src_type != dest_type)
12931319
{
1294-
if(type.id() == ID_signedbv || type.id() == ID_unsignedbv)
1320+
if(src_type.id() == ID_smv_set && expr.id() == ID_smv_set)
1321+
{
1322+
// sets can be assigned to scalars, which yields a nondeterministic
1323+
// choice
1324+
std::string identifier =
1325+
module + "::var::" + std::to_string(nondet_count++);
1326+
1327+
expr.set(ID_identifier, identifier);
1328+
expr.set("#smv_nondet_choice", true);
1329+
1330+
expr.id(ID_constraint_select_one);
1331+
expr.type() = dest_type;
1332+
1333+
// apply recursively
1334+
for(auto &op : expr.operands())
1335+
convert_expr_to(op, dest_type);
1336+
1337+
return;
1338+
}
1339+
1340+
if(dest_type.id() == ID_signedbv || dest_type.id() == ID_unsignedbv)
12951341
{
12961342
// no implicit conversion
12971343
}
1298-
else if(type.id() == ID_range)
1344+
else if(dest_type.id() == ID_range)
12991345
{
1300-
if(expr.type().id() == ID_range)
1346+
if(src_type.id() == ID_range)
13011347
{
13021348
// range to range
13031349
if(expr.id() == ID_constant)
13041350
{
13051351
// re-type the constant
13061352
auto value = numeric_cast_v<mp_integer>(to_constant_expr(expr));
1307-
if(to_range_type(type).includes(value))
1353+
if(to_range_type(dest_type).includes(value))
13081354
{
1309-
expr = from_integer(value, type);
1355+
expr = from_integer(value, dest_type);
13101356
return;
13111357
}
13121358
}
@@ -1318,26 +1364,40 @@ void smv_typecheckt::convert_expr_to(exprt &expr, const typet &type)
13181364
for(auto &op : expr.operands())
13191365
{
13201366
if(!condition)
1321-
convert_expr_to(op, type);
1367+
convert_expr_to(op, dest_type);
13221368

13231369
condition = !condition;
13241370
}
1325-
expr.type() = type;
1371+
expr.type() = dest_type;
13261372
return;
13271373
}
13281374
else
13291375
{
1330-
expr = typecast_exprt{expr, type};
1376+
expr = typecast_exprt{expr, dest_type};
13311377
return;
13321378
}
13331379
}
1380+
else if(src_type.id() == ID_integer)
1381+
{
1382+
// integer to range
1383+
if(expr.id() == ID_constant)
1384+
{
1385+
// re-type the constant
1386+
auto value = numeric_cast_v<mp_integer>(to_constant_expr(expr));
1387+
if(to_range_type(dest_type).includes(value))
1388+
{
1389+
expr = from_integer(value, dest_type);
1390+
return;
1391+
}
1392+
}
1393+
}
13341394
}
1335-
else if(type.id() == ID_bool)
1395+
else if(dest_type.id() == ID_bool)
13361396
{
13371397
// legacy -- convert 0/1 to false/true
1338-
if(expr.type().id() == ID_range)
1398+
if(src_type.id() == ID_range)
13391399
{
1340-
auto &range_type = to_range_type(expr.type());
1400+
auto &range_type = to_range_type(src_type);
13411401
if(range_type.get_from() == 0 && range_type.get_to() == 0)
13421402
{
13431403
expr = false_exprt{};
@@ -1350,43 +1410,41 @@ void smv_typecheckt::convert_expr_to(exprt &expr, const typet &type)
13501410
}
13511411
}
13521412
}
1353-
else if(type.id() == ID_enumeration)
1413+
else if(dest_type.id() == ID_enumeration)
13541414
{
1355-
auto &e_type = to_enumeration_type(type);
1415+
auto &e_type = to_enumeration_type(dest_type);
13561416

1357-
if(expr.id() == ID_constant && expr.type().id() == ID_enumeration)
1417+
if(expr.id() == ID_constant && src_type.id() == ID_enumeration)
13581418
{
1359-
if(is_contained_in(to_enumeration_type(expr.type()), e_type))
1419+
if(is_contained_in(to_enumeration_type(src_type), e_type))
13601420
{
13611421
// re-type the constant
1362-
expr.type() = type;
1422+
expr.type() = dest_type;
13631423
return;
13641424
}
13651425
else
13661426
{
13671427
throw errort().with_location(expr.find_source_location())
13681428
<< "enum " << to_string(expr) << " not a member of "
1369-
<< to_string(type);
1429+
<< to_string(dest_type);
13701430
}
13711431
}
13721432
else if(expr.id() == ID_typecast)
13731433
{
13741434
// created by type unions
13751435
auto &op = to_typecast_expr(expr).op();
1376-
if(
1377-
expr.type().id() == ID_enumeration &&
1378-
op.type().id() == ID_enumeration)
1436+
if(src_type.id() == ID_enumeration && op.type().id() == ID_enumeration)
13791437
{
1380-
convert_expr_to(op, type);
1438+
convert_expr_to(op, dest_type);
13811439
expr = std::move(op);
13821440
}
13831441
}
13841442
}
13851443

13861444
throw errort().with_location(expr.find_source_location())
1387-
<< "Expected expression of type `" << to_string(type)
1445+
<< "Expected expression of type `" << to_string(dest_type)
13881446
<< "', but got expression `" << to_string(expr) << "', which is of type `"
1389-
<< to_string(expr.type()) << "'";
1447+
<< to_string(src_type) << "'";
13901448
}
13911449
}
13921450

0 commit comments

Comments
 (0)