diff --git a/compiler2/Constraint.cc b/compiler2/Constraint.cc index d56158103f59345e05a858f7b2213bd7d5cf8810..8ab109a61c8aefd7836a3fe87eb107cdf41bc7d4 100644 --- a/compiler2/Constraint.cc +++ b/compiler2/Constraint.cc @@ -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,7 +118,9 @@ namespace Common { extension = 0; } if (subtype) { - if (sc->is_subset(subtype)==TFALSE) { + // for 'ALL EXCEPT ...' constraints it is enough if the intersection is not empty + if ((!cons[i]->is_all_except_constraint() && sc->is_subset(subtype) == TFALSE) || + (cons[i]->is_all_except_constraint() && sc->can_intersect(subtype) == TFALSE)) { cons[i]->error("Constraint #%lu is %s, this is not a subset of %s", (unsigned long) (i + 1), sc->to_string().c_str(), @@ -218,7 +222,12 @@ namespace Common { } return false; } - + + const Constraint* Constraint::get_tableconstraint() const + { + FATAL_ERROR("Constraint::get_tableconstraint()"); + } + // ================================= // ===== ElementSetSpecsConstraint // ================================= @@ -777,6 +786,11 @@ namespace Common { operand_a->set_fullname(p_fullname+".<first_operand>.<"+string(operand_a->get_name())+">"); operand_b->set_fullname(p_fullname+".<second_operand>.<"+string(operand_b->get_name())+">"); } + + bool SetOperationConstraint::is_all_except_constraint() const + { + return operationtype == EXCEPT && operand_a->get_constrtype() == CT_FULLSET; + } // ================================= // ===== FullSetConstraint @@ -1145,5 +1159,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 diff --git a/compiler2/Constraint.hh b/compiler2/Constraint.hh index de70f84c2ada64e7c59500663a2c30c5db2ae35f..a582536255e5515e455b1c0f47c4bb0582dd85be 100644 --- a/compiler2/Constraint.hh +++ b/compiler2/Constraint.hh @@ -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,13 @@ 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; + + virtual bool is_all_except_constraint() const { return false; } }; /** @@ -135,7 +144,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); @@ -349,6 +358,7 @@ namespace Common { void chk(); const char* get_name() const { return get_operationtype_str(); } void set_fullname(const string& p_fullname); + bool is_all_except_constraint() const; }; // ================================= @@ -488,6 +498,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 diff --git a/compiler2/Value.hh b/compiler2/Value.hh index ba7f960456b6f87be00a128027c20d4eca6f6f7b..a886290e8e5785cf7f5c660cf4d0b5682ca04eb4 100644 --- a/compiler2/Value.hh +++ b/compiler2/Value.hh @@ -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; diff --git a/compiler2/asn1/TableConstraint.cc b/compiler2/asn1/TableConstraint.cc index a799bf75b95988760868489d33748dbfb3b74b4f..6228ab539465e10a6f8124ea9068deb4068e1907 100644 --- a/compiler2/asn1/TableConstraint.cc +++ b/compiler2/asn1/TableConstraint.cc @@ -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; diff --git a/compiler2/asn1/TableConstraint.hh b/compiler2/asn1/TableConstraint.hh index d16b3eedbe8ff0ccbb369edadd3cee116b881b48..7ad7233bd17b0fd7afa98a24879161be4d747e26 100644 --- a/compiler2/asn1/TableConstraint.hh +++ b/compiler2/asn1/TableConstraint.hh @@ -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(); }; diff --git a/compiler2/asn1/asn1p.y b/compiler2/asn1/asn1p.y index 8407f8221877de13954c0a67e9b579b1e8e1253a..25e6f654de339c3c4ab03dd95b4b5b5f0b78bf35 100644 --- a/compiler2/asn1/asn1p.y +++ b/compiler2/asn1/asn1p.y @@ -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 diff --git a/compiler2/subtype.cc b/compiler2/subtype.cc index d45497c7f3cfc23f84d7cfe16de2fb0c8b6d870b..485a9eb8cb93c881ea123cd60f1393bd2802728d 100644 --- a/compiler2/subtype.cc +++ b/compiler2/subtype.cc @@ -1759,6 +1759,58 @@ tribool SubtypeConstraint::is_subset(const SubtypeConstraint* other) const return TUNKNOWN; } +tribool SubtypeConstraint::can_intersect(const SubtypeConstraint* other) const +{ + if (other==NULL) return TTRUE; + 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->can_intersect(*(other->integer_st)) : TTRUE; + case ST_FLOAT: + if (other->float_st==NULL) return 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->can_intersect(*(other->boolean_st)) : TTRUE; + case ST_VERDICTTYPE: + if (other->verdict_st==NULL) return 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->can_intersect(*(other->bitstring_st)) : TTRUE; + case ST_HEXSTRING: + if (other->hexstring_st==NULL) return 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->can_intersect(*(other->octetstring_st)) : TTRUE; + case ST_CHARSTRING: + if (other->charstring_st==NULL) return 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->can_intersect(other->universal_charstring_st) : TTRUE; + case ST_OBJID: + case ST_RECORD: + case ST_SET: + case ST_ENUM: + case ST_UNION: + case ST_FUNCTION: + case ST_ALTSTEP: + case ST_TESTCASE: + if (other->value_st==NULL) return 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->can_intersect(*(other->recof_st)) : TTRUE; + default: + FATAL_ERROR("SubtypeConstraint::can_intersect()"); + } + return TUNKNOWN; +} + /******************** class SubType ********************/ diff --git a/compiler2/subtype.hh b/compiler2/subtype.hh index cb1a36221c6764acea3fe2a0dc8ff6a26df525a1..87b2bb352043981e9fa1f16db5b6a73672993dba 100644 --- a/compiler2/subtype.hh +++ b/compiler2/subtype.hh @@ -190,6 +190,7 @@ public: 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 */ diff --git a/compiler2/subtypestuff.hh b/compiler2/subtypestuff.hh index 8c17ad30b11b4a9f5d2f3483df366dc514167279..78e977238b92d1a3722f7b0d0fa63470b533f02f 100644 --- a/compiler2/subtypestuff.hh +++ b/compiler2/subtypestuff.hh @@ -261,6 +261,7 @@ public: 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, @@ -617,6 +618,7 @@ public: 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(); } @@ -657,6 +659,7 @@ public: 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 ); } @@ -696,6 +699,7 @@ public: 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 ); } @@ -746,6 +750,7 @@ public: 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; @@ -1068,6 +1073,7 @@ public: 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; @@ -1102,6 +1108,7 @@ public: 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, @@ -1302,6 +1309,7 @@ public: 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; } @@ -1833,6 +1841,35 @@ tribool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::is_subset(const Stri return TUNKNOWN; } +template <class STRINGTYPE, class CHARLIMITTYPE> +tribool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::can_intersect(const StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>* other) const +{ + switch (elementtype) { + case ET_NONE: + return TTRUE; + case ET_ALL: + if (other->elementtype==ET_ALL) return TTRUE; + else return TUNKNOWN; + case ET_CONSTRAINT: + 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->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::can_intersect()"); + } + return TUNKNOWN; +} + template <class STRINGTYPE, class CHARLIMITTYPE> void StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::evaluate() { @@ -2198,6 +2235,7 @@ public: 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; }; @@ -2224,6 +2262,8 @@ public: 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 @@ -2258,6 +2298,7 @@ public: 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; diff --git a/regression_test/ASN1/parse/Test1.asn b/regression_test/ASN1/parse/Test1.asn index 602f04a4e1a15f32c49c96c51e5278961eb51c82..5d0f29262f1d317de9391018384a4dc6557aeee2 100644 --- a/regression_test/ASN1/parse/Test1.asn +++ b/regression_test/ASN1/parse/Test1.asn @@ -937,6 +937,14 @@ MyElementSetType9-String2 ::= IA5String ( FROM ("A".. "Z" UNION "a".. "z")) MyElementSetType10 ::= INTEGER (0|1|4|6) +MyElementSetType11 ::= BIT STRING { bit0 (0), bit1 (1) } (SIZE (8)) (ALL EXCEPT {}) + +MyElementSetType12 ::= BIT STRING { bit0 (0), bit1 (1) } (SIZE (8)) (ALL EXCEPT { bit0 }) + +MyElementSetType13 ::= BIT STRING { bit0 (0), bit1 (1) } (SIZE (8)) (ALL EXCEPT { bit1 }) + +MyElementSetType14 ::= BIT STRING { bit0 (0), bit1 (1) } (SIZE (8)) (ALL EXCEPT { bit0, bit1 }) + -- 46 SUBTYPE ELEMENTS ******************************************************************* -- to be added later