Commit 9bd45b6c authored by Botond Baranyi's avatar Botond Baranyi
Browse files

Fixed handling of ASN.1 named bits in type constraints and changed constraint...


Fixed handling of ASN.1 named bits in type constraints and changed constraint validity checks (bug 521417)

Change-Id: Ib23f1488bb82f6c191bb82435d714104f0414ac6
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent ffeb1ece
......@@ -62,12 +62,14 @@ namespace Common {
if (my_type) p_con->set_my_type(my_type);
}
Constraint* Constraints::get_tableconstraint() const
const Constraint* Constraints::get_tableconstraint() const
{
size_t nof_cons = cons.size();
for (size_t i = 0; i < nof_cons; i++) {
Constraint *con = cons[i];
if (con->get_constrtype() == Constraint::CT_TABLE) return con;
if (con->get_constrtype() == Constraint::CT_TABLE) {
return con->get_tableconstraint();
}
}
return 0;
}
......@@ -116,15 +118,18 @@ namespace Common {
extension = 0;
}
if (subtype) {
if (sc->is_subset(subtype)==TFALSE) {
cons[i]->error("Constraint #%lu is %s, this is not a subset of %s",
if (sc->can_intersect(subtype)==TFALSE) {
cons[i]->error("Constraint #%lu is %s, intersecting this with %s "
"results in an empty set (no values satisfy the type's restrictions)",
(unsigned long) (i + 1),
sc->to_string().c_str(),
subtype->to_string().c_str());
break; // stop on error
}
if (sc_ext && (sc_ext->is_subset(subtype)==TFALSE)) {
cons[i]->error("Extension addition of constraint #%lu is %s, this is not a subset of %s",
if (sc_ext && (sc_ext->can_intersect(subtype)==TFALSE)) {
cons[i]->error("Extension addition of constraint #%lu is %s, "
"intersecting this with %s results in an empty set (no values "
"satisfy the type's restrictions)",
(unsigned long) (i + 1),
sc_ext->to_string().c_str(),
subtype->to_string().c_str());
......@@ -218,7 +223,12 @@ namespace Common {
}
return false;
}
const Constraint* Constraint::get_tableconstraint() const
{
FATAL_ERROR("Constraint::get_tableconstraint()");
}
// =================================
// ===== ElementSetSpecsConstraint
// =================================
......@@ -1145,5 +1155,128 @@ namespace Common {
block->set_fullname(p_fullname);
if (constraint) constraint->set_fullname(p_fullname);
}
// =================================
// ===== UndefinedBlockConstraint
// =================================
UndefinedBlockConstraint::UndefinedBlockConstraint(const UndefinedBlockConstraint& p)
: Constraint(p)
{
switch (constrtype) {
case CT_UNDEFINEDBLOCK:
block = p.block->clone();
break;
case CT_SINGLEVALUE:
single = p.single->clone();
break;
case CT_TABLE:
table = p.table->clone();
break;
default:
FATAL_ERROR("UndefinedBlockConstraint::UndefinedBlockConstraint");
}
}
UndefinedBlockConstraint::UndefinedBlockConstraint(Block* p_block)
: Constraint(CT_UNDEFINEDBLOCK), block(p_block)
{
if (p_block == NULL) {
FATAL_ERROR("UndefinedBlockConstraint::UndefinedBlockConstraint()");
}
}
UndefinedBlockConstraint::~UndefinedBlockConstraint()
{
switch (constrtype) {
case CT_UNDEFINEDBLOCK:
delete block;
break;
case CT_SINGLEVALUE:
delete single;
break;
case CT_TABLE:
delete table;
break;
default:
FATAL_ERROR("UndefinedBlockConstraint::~UndefinedBlockConstraint");
}
}
void UndefinedBlockConstraint::chk()
{
if (checked) return;
checked = true;
if (my_parent != NULL && my_parent->get_constrtype() == CT_SETOPERATION) {
single = new SingleValueConstraint(new Value(Value::V_UNDEF_BLOCK, block));
constrtype = CT_SINGLEVALUE;
single->set_my_type(my_type);
single->set_my_scope(my_scope);
single->set_my_parent(my_parent);
single->chk();
extendable = single->is_extendable();
}
else {
table = new Asn::TableConstraint(block, NULL);
constrtype = CT_TABLE;
table->set_my_type(my_type);
table->set_my_scope(my_scope);
table->set_my_parent(my_parent);
table->chk();
extendable = table->is_extendable();
}
}
void UndefinedBlockConstraint::set_fullname(const string& p_fullname)
{
Node::set_fullname(p_fullname);
switch (constrtype) {
case CT_UNDEFINEDBLOCK:
block->set_fullname(p_fullname + ".<block>");
break;
case CT_SINGLEVALUE:
single->set_fullname(p_fullname);
break;
case CT_TABLE:
table->set_fullname(p_fullname);
break;
default:
FATAL_ERROR("UndefinedBlockConstraint::UndefinedBlockConstraint");
}
}
SubtypeConstraint* UndefinedBlockConstraint::get_subtype() const
{
switch (constrtype) {
case CT_SINGLEVALUE:
return single->get_subtype();
case CT_TABLE:
return table->get_subtype();
case CT_UNDEFINEDBLOCK:
default:
FATAL_ERROR("UndefinedBlockConstraint::get_subtype");
}
}
SubtypeConstraint* UndefinedBlockConstraint::get_extension() const
{
switch (constrtype) {
case CT_SINGLEVALUE:
return single->get_extension();
case CT_TABLE:
return table->get_extension();
case CT_UNDEFINEDBLOCK:
default:
FATAL_ERROR("UndefinedBlockConstraint::get_extension");
}
}
const Constraint* UndefinedBlockConstraint::get_tableconstraint() const
{
if (constrtype != CT_TABLE) {
FATAL_ERROR("UndefinedBlockConstraint::get_tableconstraint()");
}
return table;
}
} // namespace Common
......@@ -20,6 +20,7 @@
namespace Asn {
class Block;
class TableConstraint;
}
namespace Common {
......@@ -42,7 +43,7 @@ namespace Common {
class Value;
class SubtypeConstraint;
class Identifier;
using Asn::Block;
/**
......@@ -51,6 +52,7 @@ namespace Common {
class Constraint : public Node, public Location {
public:
enum constrtype_t {
CT_UNDEFINEDBLOCK, /** UndefinedBlockConstraint (turns into CT_TABLE or CT_SINGLEVALUE after semantic analysis) */
CT_ELEMENTSETSPEC, /** ElementSetSpecsConstraint */
CT_IGNORE, /**< Constraint : used if erroneous or not yet supported */
CT_TABLE, /**< TableConstraint */
......@@ -96,9 +98,9 @@ namespace Common {
Constraints* get_my_cons();
virtual void chk() = 0;
/** return the subtype constraint */
SubtypeConstraint* get_subtype() const { return subtype; }
virtual SubtypeConstraint* get_subtype() const { return subtype; }
bool is_extendable() const { return extendable; }
SubtypeConstraint* get_extension() const { return extension; }
virtual SubtypeConstraint* get_extension() const { return extension; }
/** returns the name of this constraint which can be used in error messages */
virtual const char* get_name() const = 0;
/** if this constraint is inside a FROM() constraint then we are in
......@@ -112,6 +114,11 @@ namespace Common {
somehow drop or simplify their constraint, example: (inner subtype) EXCEPT (inner subtype)
*/
virtual bool is_ignored() const { return false; }
/** Returns this (for TableConstraints) or the embedded TableConstraint
* object (for UndefinedBlockConstraints that contain a TableConstraint
* after semantic analysis) */
virtual const Constraint* get_tableconstraint() const;
};
/**
......@@ -135,7 +142,7 @@ namespace Common {
void add_con(Constraint *p_con);
size_t get_nof_cons() const {return cons.size();}
Constraint* get_con_byIndex(size_t p_i) const { return cons[p_i]; }
Constraint* get_tableconstraint() const;
const Constraint* get_tableconstraint() const;
void set_my_type(Type *p_my_type);
Type* get_my_type() const { return my_type; }
void chk(SubtypeConstraint* parent_subtype);
......@@ -488,6 +495,36 @@ namespace Common {
const char* get_name() const { return "inner type constraint"; }
bool is_ignored() const { return true; }
};
// =================================
// ===== UndefinedBlockConstraint
// =================================
/** This class represents a constraint containing a block.
* During semantic analysis the block is parsed and causes this object to act
* as either a SingleValueConstraint or a TableConstraint afterwards. */
class UndefinedBlockConstraint : public Constraint
{
union {
Block* block; // CT_UNDEFINEDBLOCK, before chk()
SingleValueConstraint* single; // CT_SINGLEVALUE, after chk()
Asn::TableConstraint* table; // CT_TABLE, after chk()
};
UndefinedBlockConstraint(const UndefinedBlockConstraint& p);
/// Assignment disabled
UndefinedBlockConstraint& operator=(const UndefinedBlockConstraint& p);
public:
UndefinedBlockConstraint(Block* p_block);
virtual ~UndefinedBlockConstraint();
UndefinedBlockConstraint* clone() const { return new UndefinedBlockConstraint(*this); }
void chk();
const char* get_name() const { return "Undefined block constraint"; }
void set_fullname(const string& p_fullname);
SubtypeConstraint* get_subtype() const;
SubtypeConstraint* get_extension() const;
const Constraint* get_tableconstraint() const;
};
} // namespace Common
......
......@@ -315,7 +315,7 @@ namespace Common {
ttcn3float val_Real;
struct {
string *val_str;
map<size_t, Value> *str_elements;
map<size_t, Value> *str_elements;
} str;
struct {
ustring *val_ustr;
......
......@@ -225,7 +225,7 @@ namespace Asn {
Constraints *t_cons=t_type->get_constraints();
if(!t_cons) break;
t_cons->chk_table();
TableConstraint *t_tc=dynamic_cast<TableConstraint*>
const TableConstraint *t_tc=dynamic_cast<const TableConstraint*>
(t_cons->get_tableconstraint());
if(!t_tc) break;
Type *t_ocft=t_tc->consdtype;
......
......@@ -103,6 +103,7 @@ namespace Asn {
ObjectSet* get_os() const {return os;}
const Identifier* get_oc_fieldname() const {return oc_fieldname;}
const char* get_name() const { return "table constraint"; }
const Constraint* get_tableconstraint() const { return this; }
private:
void parse_blocks();
};
......
......@@ -2780,10 +2780,9 @@ SingleValue:
}
| TOK_Block
{
/** \todo: It would be more straightforward to create an undefined
* constraint here and classify it later on during parsing or semantic
* analysis to SimpleTableConstraint or SingleValue. */
$$ = new TableConstraint($1, 0);
/* Create an undefined constraint for now, and classify it later on during
semantic analysis to TableConstraint or SingleValueConstraint. */
$$ = new UndefinedBlockConstraint($1);
$$->set_location(asn1_infile, @1.first_line);
}
| ReferencedValue_reg
......
......@@ -934,7 +934,7 @@ SubtypeConstraint* SubtypeConstraint::create_asn_size_constraint(
static const int_val_t zero((Int)0);
static const int_limit_t ilt0(zero);
IntegerRangeListConstraint valid_range(ilt0, int_limit_t::maximum);
if (integer_stc->integer_st->is_subset(valid_range)==TFALSE) {
if (integer_stc->integer_st->can_intersect(valid_range)==TFALSE) {
loc->error("Range %s is not a valid range for a size constraint", integer_stc->to_string().c_str());
} else {
bool success = convert_int_to_size(*(integer_stc->integer_st), size_constraint);
......@@ -1707,38 +1707,38 @@ void SubtypeConstraint::intersection(const SubtypeConstraint* other)
}
}
tribool SubtypeConstraint::is_subset(const SubtypeConstraint* other) const
tribool SubtypeConstraint::can_intersect(const SubtypeConstraint* other) const
{
if (other==NULL) return TTRUE;
if (other->subtype!=subtype) FATAL_ERROR("SubtypeConstraint::is_subset()");
if (other->subtype!=subtype) FATAL_ERROR("SubtypeConstraint::can_intersect()");
switch (subtype) {
case ST_INTEGER:
if (other->integer_st==NULL) return TTRUE;
return integer_st ? integer_st->is_subset(*(other->integer_st)) : TTRUE;
return integer_st ? integer_st->can_intersect(*(other->integer_st)) : TTRUE;
case ST_FLOAT:
if (other->float_st==NULL) return TTRUE;
return float_st ? float_st->is_subset(*(other->float_st)) : TTRUE;
return float_st ? float_st->can_intersect(*(other->float_st)) : TTRUE;
case ST_BOOLEAN:
if (other->boolean_st==NULL) return TTRUE;
return boolean_st ? boolean_st->is_subset(*(other->boolean_st)) : TTRUE;
return boolean_st ? boolean_st->can_intersect(*(other->boolean_st)) : TTRUE;
case ST_VERDICTTYPE:
if (other->verdict_st==NULL) return TTRUE;
return verdict_st ? verdict_st->is_subset(*(other->verdict_st)) : TTRUE;
return verdict_st ? verdict_st->can_intersect(*(other->verdict_st)) : TTRUE;
case ST_BITSTRING:
if (other->bitstring_st==NULL) return TTRUE;
return bitstring_st ? bitstring_st->is_subset(*(other->bitstring_st)) : TTRUE;
return bitstring_st ? bitstring_st->can_intersect(*(other->bitstring_st)) : TTRUE;
case ST_HEXSTRING:
if (other->hexstring_st==NULL) return TTRUE;
return hexstring_st ? hexstring_st->is_subset(*(other->hexstring_st)) : TTRUE;
return hexstring_st ? hexstring_st->can_intersect(*(other->hexstring_st)) : TTRUE;
case ST_OCTETSTRING:
if (other->octetstring_st==NULL) return TTRUE;
return octetstring_st ? octetstring_st->is_subset(*(other->octetstring_st)) : TTRUE;
return octetstring_st ? octetstring_st->can_intersect(*(other->octetstring_st)) : TTRUE;
case ST_CHARSTRING:
if (other->charstring_st==NULL) return TTRUE;
return charstring_st ? charstring_st->is_subset(other->charstring_st) : TTRUE;
return charstring_st ? charstring_st->can_intersect(other->charstring_st) : TTRUE;
case ST_UNIVERSAL_CHARSTRING:
if (other->universal_charstring_st==NULL) return TTRUE;
return universal_charstring_st ? universal_charstring_st->is_subset(other->universal_charstring_st) : TTRUE;
return universal_charstring_st ? universal_charstring_st->can_intersect(other->universal_charstring_st) : TTRUE;
case ST_OBJID:
case ST_RECORD:
case ST_SET:
......@@ -1748,13 +1748,13 @@ tribool SubtypeConstraint::is_subset(const SubtypeConstraint* other) const
case ST_ALTSTEP:
case ST_TESTCASE:
if (other->value_st==NULL) return TTRUE;
return value_st ? value_st->is_subset(*(other->value_st)) : TTRUE;
return value_st ? value_st->can_intersect(*(other->value_st)) : TTRUE;
case ST_RECORDOF:
case ST_SETOF:
if (other->recof_st==NULL) return TTRUE;
return recof_st ? recof_st->is_subset(*(other->recof_st)) : TTRUE;
return recof_st ? recof_st->can_intersect(*(other->recof_st)) : TTRUE;
default:
FATAL_ERROR("SubtypeConstraint::is_subset()");
FATAL_ERROR("SubtypeConstraint::can_intersect()");
}
return TUNKNOWN;
}
......@@ -2857,9 +2857,11 @@ void SubType::chk()
if (subtype==ST_ERROR) { checked = STC_YES; return; }
if (parent_subtype) {
if (is_subset(parent_subtype->get_root())==TFALSE) {
my_owner->error("The subtype restriction is not a subset of the restriction on the parent type. "
"Subtype %s is not subset of subtype %s", to_string().c_str(), parent_subtype->get_root()->to_string().c_str());
if (can_intersect(parent_subtype->get_root())==TFALSE) {
my_owner->error("The intersection between the subtype restriction, %s, "
"and the parent type's restriction, %s, is empty. (No values satisfy "
"the type's restrictions.)",
to_string().c_str(), parent_subtype->get_root()->to_string().c_str());
set_to_error();
checked = STC_YES;
return;
......
......@@ -189,7 +189,7 @@ public:
void union_(const SubtypeConstraint* other);
void except(const SubtypeConstraint* other);
tribool is_subset(const SubtypeConstraint* other) const;
tribool can_intersect(const SubtypeConstraint* other) const;
/** special ASN.1 types (NumericString, etc.) have default subtype constraints,
return default constraint or NULL */
......
......@@ -260,7 +260,7 @@ public:
RangeListConstraint operator*(const RangeListConstraint& other) const { return set_operation(other, false); } // intersection
RangeListConstraint operator~() const; // complement
tribool is_subset(const RangeListConstraint& other) const { return (*this*~other).is_empty(); }
tribool can_intersect(const RangeListConstraint& other) const { return !(*this * other).is_empty(); }
RangeListConstraint operator-(const RangeListConstraint& other) const { return ( *this * ~other ); } // except
// will return the minimal value that is part of the interval,
......@@ -616,7 +616,7 @@ public:
RealRangeListConstraint operator*(const RealRangeListConstraint& other) const { return set_operation(other, false); } // intersection
RealRangeListConstraint operator~() const; // complement
tribool is_subset(const RealRangeListConstraint& other) const { return (*this*~other).is_empty(); }
tribool can_intersect(const RealRangeListConstraint& other) const { return !(*this * other).is_empty(); }
RealRangeListConstraint operator-(const RealRangeListConstraint& other) const { return ( *this * ~other ); } // except
tribool is_range_empty() const { return rlc.is_empty(); }
......@@ -656,7 +656,7 @@ public:
BooleanListConstraint operator*(const BooleanListConstraint& other) const { BooleanListConstraint rv; rv.values = values & other.values; return rv; }
BooleanListConstraint operator~() const { BooleanListConstraint rv; rv.values = values ^ BC_ALL; return rv; }
tribool is_subset(const BooleanListConstraint& other) const { return (*this*~other).is_empty(); }
tribool can_intersect(const BooleanListConstraint& other) const { return !(*this * other).is_empty(); }
BooleanListConstraint operator-(const BooleanListConstraint& other) const { return ( *this * ~other ); }
......@@ -695,7 +695,7 @@ public:
VerdicttypeListConstraint operator*(const VerdicttypeListConstraint& other) const { VerdicttypeListConstraint rv; rv.values = values & other.values; return rv; }
VerdicttypeListConstraint operator~() const { VerdicttypeListConstraint rv; rv.values = values ^ VC_ALL; return rv; }
tribool is_subset(const VerdicttypeListConstraint& other) const { return (*this*~other).is_empty(); }
tribool can_intersect(const VerdicttypeListConstraint& other) const { return !(*this * other).is_empty(); }
VerdicttypeListConstraint operator-(const VerdicttypeListConstraint& other) const { return ( *this * ~other ); }
......@@ -745,7 +745,7 @@ public:
StringSizeAndValueListConstraint operator*(const StringSizeAndValueListConstraint& other) const { return set_operation(other, false); } // intersection
StringSizeAndValueListConstraint operator~() const; // complement
tribool is_subset(const StringSizeAndValueListConstraint& other) const { return (*this*~other).is_empty(); }
tribool can_intersect(const StringSizeAndValueListConstraint& other) const { return !(*this * other).is_empty(); }
StringSizeAndValueListConstraint operator-(const StringSizeAndValueListConstraint& other) const { return ( *this * ~other ); } // except
tribool get_size_limit(bool is_upper, size_limit_t& limit) const;
......@@ -1067,7 +1067,7 @@ public:
StringPatternConstraint operator*(const StringPatternConstraint& other) const { return set_operation(other, false); } // intersection
StringPatternConstraint operator~() const { FATAL_ERROR("StringPatternConstraint::operator~(): not implemented"); }
tribool is_subset(const StringPatternConstraint&) const { return TUNKNOWN; }
tribool can_intersect(const StringPatternConstraint&) const { return TUNKNOWN; }
StringPatternConstraint operator-(const StringPatternConstraint& other) const { return ( *this * ~other ); } // except
string to_string() const;
......@@ -1101,7 +1101,7 @@ public:
StringValueConstraint operator+(const StringValueConstraint& other) const { return set_operation(other, true); } // union
StringValueConstraint operator*(const StringValueConstraint& other) const { return set_operation(other, false); } // intersection
tribool is_subset(const StringValueConstraint& other) const { return (*this-other).is_empty(); }
tribool can_intersect(const StringValueConstraint& other) const { return !(*this * other).is_empty(); }
StringValueConstraint operator-(const StringValueConstraint& other) const; // except
// remove strings that are or are not elements of the set defined by the XXX_constraint object,
......@@ -1301,7 +1301,7 @@ public:
tribool is_full() const;
tribool is_equal(const StringSubtypeTreeElement* other) const;
bool is_element(const STRINGTYPE& s) const;
tribool is_subset(const StringSubtypeTreeElement* other) const;
tribool can_intersect(const StringSubtypeTreeElement* other) const;
bool is_single_constraint() const { return ( (elementtype==ET_CONSTRAINT) || (elementtype==ET_NONE) || (elementtype==ET_ALL) ); }
void set_none() { clean_up(); elementtype = ET_NONE; }
......@@ -1803,9 +1803,9 @@ bool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::is_element(const STRING
// if the constraints are ortogonal (e.g. size and alphabet) or just different then return TUNKNOWN
// in case of ortogonal constraints we should return TFALSE (if other is not full set)
// but it seems that the standard wants to ignore such trivial cases, example:
// length(1..4) is_subset ('a'..'z') shall not report an error
// length(1..4) can_intersect ('a'..'z') shall not report an error
template <class STRINGTYPE, class CHARLIMITTYPE>
tribool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::is_subset(const StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>* other) const
tribool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::can_intersect(const StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>* other) const
{
switch (elementtype) {
case ET_NONE:
......@@ -1817,18 +1817,18 @@ tribool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::is_subset(const Stri
if (elementtype!=other->elementtype) return TUNKNOWN;
if (u.cs.constrainttype!=other->u.cs.constrainttype) return TUNKNOWN;
switch (u.cs.constrainttype) {
case CT_SIZE: return u.cs.s->is_subset(*(other->u.cs.s));
case CT_ALPHABET: return u.cs.a.c->is_subset(*(other->u.cs.a.c));
case CT_VALUES: return u.cs.v->is_subset(*(other->u.cs.v));
case CT_PATTERN: return u.cs.p->is_subset(*(other->u.cs.p));
default: FATAL_ERROR("StringSubtypeTreeElement::is_subset()");
case CT_SIZE: return u.cs.s->can_intersect(*(other->u.cs.s));
case CT_ALPHABET: return u.cs.a.c->can_intersect(*(other->u.cs.a.c));
case CT_VALUES: return u.cs.v->can_intersect(*(other->u.cs.v));
case CT_PATTERN: return u.cs.p->can_intersect(*(other->u.cs.p));
default: FATAL_ERROR("StringSubtypeTreeElement::can_intersect()");
}
case ET_INTERSECTION:
case ET_UNION:
case ET_EXCEPT:
return TUNKNOWN;
default:
FATAL_ERROR("StringSubtypeTreeElement::is_subset()");
FATAL_ERROR("StringSubtypeTreeElement::can_intersect()");
}
return TUNKNOWN;
}
......@@ -2197,7 +2197,7 @@ public:
ValueList operator*(const ValueList& other) const { return set_operation(other, false); } // intersection
ValueList operator-(const ValueList& other) const; // except
tribool is_subset(const ValueList& other) const { return (*this-other).is_empty(); }
tribool can_intersect(const ValueList& other) const { return !(*this * other).is_empty(); }
string to_string() const;
};
......@@ -2222,8 +2222,8 @@ public:
ValueListConstraint operator*(const ValueListConstraint& other) const; // intersection
ValueListConstraint operator~() const; // complement
inline tribool is_subset(const ValueListConstraint& other) const
{ return (*this*~other).is_empty(); }
inline tribool can_intersect(const ValueListConstraint& other) const
{ return !(*this * other).is_empty(); }
inline ValueListConstraint operator-(const ValueListConstraint& other) const
{ return ( *this * ~other ); } // except
......@@ -2257,7 +2257,7 @@ public:
inline RecofConstraint operator*(const RecofConstraint& other) const { return set_operation(other, false); } // intersection
RecofConstraint operator~() const; // complement
inline tribool is_subset(const RecofConstraint& other) const { return (*this*~other).is_empty(); }
inline tribool can_intersect(const RecofConstraint& other) const { return !(*this * other).is_empty(); }
inline RecofConstraint operator-(const RecofConstraint& other) const { return ( *this * ~other ); } // except
tribool get_size_limit(bool is_upper, size_limit_t& limit) const;
......
......@@ -6337,7 +6337,7 @@ MyInt3 ::= INTEGER ( SIZE(10) EXCEPT FROM(1..10) )
MyInt4 ::= MyInt2 (MyInt3)
MyInt5 ::= INTEGER ( PATTERN "abc" EXCEPT 5 )
MyInt6 ::= INTEGER ( ALL EXCEPT ((MIN..0) UNION (0..MAX)) )
MyInt7 ::= INTEGER (1..10) (5..15)
MyInt7 ::= INTEGER (1..10) (12..15)
MyInt9 ::= INTEGER (5..6 EXCEPT 1..10)
MyInt10::= INTEGER ( MIN..MAX )
MyInt11::= INTEGER ( INTEGER )
......@@ -6363,7 +6363,7 @@ END
(?im)\berror: The subtype is an empty set
<END_RESULT>
<RESULT COUNT 1>
(?im)\berror: Constraint #2 is \(5..15\), this is not a subset of \(1..10\)
(?im)\berror: Constraint #2 is \(12..15\), intersecting this with \(1..10\) results in an empty set \(no values satisfy the type's restrictions\)
<END_RESULT>
<RESULT COUNT 1>
(?im)\bwarning: The subtype of type `integer' is a full set, it does not constrain the root type.
......@@ -6559,12 +6559,6 @@ END
(?im)\berror: 0 is not a valid value for type `integer' which has subtype \(-100..-11,11..100\)
<END_RESULT>
<RESULT COUNT 1>
(?im)\berror: Constraint #1 is \(-100..100\), this is not a subset of \(-100..-11,11..100\)
<END_RESULT>
<RESULT COUNT 1>
(?im)\berror: Constraint #1 is from\(" ".."6"\), this is not a subset of from\(" ","0".."9"\)
<END_RESULT>
<RESULT COUNT 1>
(?im)\berror: "abc" is not a valid value for type `NumericString' which has subtype from\("3".."9"\)
<END_RESULT>
<RESULT COUNT 1>
......@@ -6583,7 +6577,7 @@ END
(?im)\berror: Cannot determine the value of MAX: the parent subtype has no range
<END_RESULT>
<RESULT COUNT 1>
(?im)\berror: Constraint #2 is \(-INF..INF\), this is not a subset of \(NaN\)
(?im)\berror: Constraint #2 is \(-INF..INF\), intersecting this with \(NaN\) results in an empty set \(no values satisfy the type's restrictions\)
<END_RESULT>
<RESULT COUNT 1>
(?im)\berror: Cannot determine the value of MAX: the parent subtype does not define a maximal size value
......@@ -6591,7 +6585,7 @@ END
<RESULT COUNT 1>
(?im)\berror: Cannot determine the value of MIN: the parent subtype does not define a minimal size value
<END_RESULT>
<RESULT COUNT 11>
<RESULT COUNT 9>
(?is)\berror:
<END_RESULT>
<RESULT COUNT 2>
......