1 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3 /* 4 * Main authors: 5 * Guido Tack <guido.tack@monash.edu> 6 */ 7 8 /* This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 11 12 #pragma once 13 14 #include <cassert> 15 #include <sstream> 16 #include <string> 17 18 namespace MiniZinc { 19 20 class EnvI; 21 22 /// Type of a MiniZinc expression 23 class Type { 24 public: 25 /// Type-inst 26 enum TypeInst { TI_PAR, TI_VAR }; 27 /// Basic type 28 enum BaseType { BT_BOOL, BT_INT, BT_FLOAT, BT_STRING, BT_ANN, BT_TOP, BT_BOT, BT_UNKNOWN }; 29 /// Whether the expression is plain or set 30 enum SetType { ST_PLAIN, ST_SET }; 31 /// Whether the expression is normal or optional 32 enum OptType { OT_PRESENT, OT_OPTIONAL }; 33 /// Whether the par expression contains a var argument 34 enum ContainsVarType { CV_NO, CV_YES }; 35 36 private: 37 unsigned int _ti : 1; 38 unsigned int _bt : 4; 39 unsigned int _st : 1; 40 unsigned int _ot : 1; 41 unsigned int _cv : 1; 42 /** \brief Enumerated type identifier 43 * This is an index into a table in the Env. It is currently limited to 44 * 4095 different enumerated type identifiers. 45 * For a non-array type, this maps directly to the identity of the enum. 46 * For an array type, it maps to a tuple of enum identities. 47 */ 48 unsigned int _enumId : 12; 49 /// Number of array dimensions 50 signed int _dim : 7; 51 52 public: 53 /// Default constructor Type()54 Type() 55 : _ti(TI_PAR), 56 _bt(BT_UNKNOWN), 57 _st(ST_PLAIN), 58 _ot(OT_PRESENT), 59 _cv(CV_NO), 60 _enumId(0), 61 _dim(0) {} 62 63 /// Access type-inst ti() const64 TypeInst ti() const { return static_cast<TypeInst>(_ti); } 65 /// Set type-inst ti(const TypeInst & t)66 void ti(const TypeInst& t) { 67 _ti = t; 68 if (t == TI_VAR) { 69 _cv = CV_YES; 70 } 71 } 72 73 /// Access basic type bt() const74 BaseType bt() const { return static_cast<BaseType>(_bt); } 75 /// Set basic type bt(const BaseType & b)76 void bt(const BaseType& b) { _bt = b; } 77 78 /// Access set type st() const79 SetType st() const { return static_cast<SetType>(_st); } 80 /// Set set type st(const SetType & s)81 void st(const SetType& s) { _st = s; } 82 83 /// Access opt type ot() const84 OptType ot() const { return static_cast<OptType>(_ot); } 85 /// Set opt type ot(const OptType & o)86 void ot(const OptType& o) { _ot = o; } 87 88 /// Access var-in-par type cv() const89 bool cv() const { return static_cast<ContainsVarType>(_cv) == CV_YES; } 90 /// Set var-in-par type cv(bool b)91 void cv(bool b) { _cv = b ? CV_YES : CV_NO; } 92 93 /// Access enum identifier enumId() const94 unsigned int enumId() const { return _enumId; } 95 /// Set enum identifier enumId(unsigned int eid)96 void enumId(unsigned int eid) { _enumId = eid; } 97 98 /// Access dimensions dim() const99 int dim() const { return _dim; } 100 /// Set dimensions dim(int d)101 void dim(int d) { 102 _dim = d; 103 assert(_dim == d); 104 } 105 106 protected: 107 /// Constructor Type(const TypeInst & ti,const BaseType & bt,const SetType & st,unsigned int enumId,int dim)108 Type(const TypeInst& ti, const BaseType& bt, const SetType& st, unsigned int enumId, int dim) 109 : _ti(ti), 110 _bt(bt), 111 _st(st), 112 _ot(OT_PRESENT), 113 _cv(ti == TI_VAR ? CV_YES : CV_NO), 114 _enumId(enumId), 115 _dim(dim) {} 116 117 public: parint(int dim=0)118 static Type parint(int dim = 0) { return Type(TI_PAR, BT_INT, ST_PLAIN, 0, dim); } parenum(unsigned int enumId,int dim=0)119 static Type parenum(unsigned int enumId, int dim = 0) { 120 return Type(TI_PAR, BT_INT, ST_PLAIN, enumId, dim); 121 } parbool(int dim=0)122 static Type parbool(int dim = 0) { return Type(TI_PAR, BT_BOOL, ST_PLAIN, 0, dim); } parfloat(int dim=0)123 static Type parfloat(int dim = 0) { return Type(TI_PAR, BT_FLOAT, ST_PLAIN, 0, dim); } parstring(int dim=0)124 static Type parstring(int dim = 0) { return Type(TI_PAR, BT_STRING, ST_PLAIN, 0, dim); } partop(int dim=0)125 static Type partop(int dim = 0) { return Type(TI_PAR, BT_TOP, ST_PLAIN, 0, dim); } ann(int dim=0)126 static Type ann(int dim = 0) { return Type(TI_PAR, BT_ANN, ST_PLAIN, 0, dim); } parsetint(int dim=0)127 static Type parsetint(int dim = 0) { return Type(TI_PAR, BT_INT, ST_SET, 0, dim); } parsetenum(unsigned int enumId,int dim=0)128 static Type parsetenum(unsigned int enumId, int dim = 0) { 129 return Type(TI_PAR, BT_INT, ST_SET, enumId, dim); 130 } parsetbool(int dim=0)131 static Type parsetbool(int dim = 0) { return Type(TI_PAR, BT_BOOL, ST_SET, 0, dim); } parsetfloat(int dim=0)132 static Type parsetfloat(int dim = 0) { return Type(TI_PAR, BT_FLOAT, ST_SET, 0, dim); } parsetstring(int dim=0)133 static Type parsetstring(int dim = 0) { return Type(TI_PAR, BT_STRING, ST_SET, 0, dim); } varint(int dim=0)134 static Type varint(int dim = 0) { return Type(TI_VAR, BT_INT, ST_PLAIN, 0, dim); } varenumint(unsigned int enumId,int dim=0)135 static Type varenumint(unsigned int enumId, int dim = 0) { 136 return Type(TI_VAR, BT_INT, ST_PLAIN, enumId, dim); 137 } varbool(int dim=0)138 static Type varbool(int dim = 0) { return Type(TI_VAR, BT_BOOL, ST_PLAIN, 0, dim); } varfloat(int dim=0)139 static Type varfloat(int dim = 0) { return Type(TI_VAR, BT_FLOAT, ST_PLAIN, 0, dim); } varsetint(int dim=0)140 static Type varsetint(int dim = 0) { return Type(TI_VAR, BT_INT, ST_SET, 0, dim); } varbot(int dim=0)141 static Type varbot(int dim = 0) { return Type(TI_VAR, BT_BOT, ST_PLAIN, 0, dim); } bot(int dim=0)142 static Type bot(int dim = 0) { return Type(TI_PAR, BT_BOT, ST_PLAIN, 0, dim); } top(int dim=0)143 static Type top(int dim = 0) { return Type(TI_PAR, BT_TOP, ST_PLAIN, 0, dim); } vartop(int dim=0)144 static Type vartop(int dim = 0) { return Type(TI_VAR, BT_TOP, ST_PLAIN, 0, dim); } optvartop(int dim=0)145 static Type optvartop(int dim = 0) { 146 Type t(TI_VAR, BT_TOP, ST_PLAIN, 0, dim); 147 t._ot = OT_OPTIONAL; 148 return t; 149 } optpartop(int dim=0)150 static Type optpartop(int dim = 0) { 151 Type t(TI_PAR, BT_TOP, ST_PLAIN, 0, dim); 152 t._ot = OT_OPTIONAL; 153 return t; 154 } 155 156 static Type unboxedint; 157 static Type unboxedfloat; 158 isunknown() const159 bool isunknown() const { return bt() == BT_UNKNOWN; } isplain() const160 bool isplain() const { return _dim == 0 && st() == ST_PLAIN && ot() == OT_PRESENT; } isint() const161 bool isint() const { return _dim == 0 && st() == ST_PLAIN && bt() == BT_INT; } isbot() const162 bool isbot() const { return bt() == BT_BOT; } isfloat() const163 bool isfloat() const { return _dim == 0 && st() == ST_PLAIN && bt() == BT_FLOAT; } isbool() const164 bool isbool() const { return _dim == 0 && st() == ST_PLAIN && bt() == BT_BOOL; } isstring() const165 bool isstring() const { return isplain() && bt() == BT_STRING; } isvar() const166 bool isvar() const { return ti() != TI_PAR; } isvarbool() const167 bool isvarbool() const { 168 return ti() == TI_VAR && _dim == 0 && st() == ST_PLAIN && bt() == BT_BOOL && ot() == OT_PRESENT; 169 } isvarfloat() const170 bool isvarfloat() const { 171 return ti() == TI_VAR && _dim == 0 && st() == ST_PLAIN && bt() == BT_FLOAT && 172 ot() == OT_PRESENT; 173 } isvarint() const174 bool isvarint() const { 175 return ti() == TI_VAR && _dim == 0 && st() == ST_PLAIN && bt() == BT_INT && ot() == OT_PRESENT; 176 } isPar() const177 bool isPar() const { return ti() == TI_PAR; } isOpt() const178 bool isOpt() const { return ot() == OT_OPTIONAL; } isPresent() const179 bool isPresent() const { return ot() == OT_PRESENT; } isSet() const180 bool isSet() const { return _dim == 0 && st() == ST_SET; } isIntSet() const181 bool isIntSet() const { return isSet() && (bt() == BT_INT || bt() == BT_BOT); } isBoolSet() const182 bool isBoolSet() const { return isSet() && (bt() == BT_BOOL || bt() == BT_BOT); } isFloatSet() const183 bool isFloatSet() const { return isSet() && (bt() == BT_FLOAT || bt() == BT_BOT); } isAnn() const184 bool isAnn() const { return isplain() && bt() == BT_ANN; } isIntArray() const185 bool isIntArray() const { 186 return _dim == 1 && st() == ST_PLAIN && ot() == OT_PRESENT && bt() == BT_INT; 187 } isBoolArray() const188 bool isBoolArray() const { 189 return _dim == 1 && st() == ST_PLAIN && ot() == OT_PRESENT && bt() == BT_BOOL; 190 } isIntSetArray() const191 bool isIntSetArray() const { return _dim == 1 && st() == ST_SET && bt() == BT_INT; } 192 operator ==(const Type & t) const193 bool operator==(const Type& t) const { 194 return ti() == t.ti() && bt() == t.bt() && st() == t.st() && ot() == t.ot() && _dim == t._dim; 195 } operator !=(const Type & t) const196 bool operator!=(const Type& t) const { return !this->operator==(t); } 197 // protected: 198 toInt() const199 int toInt() const { 200 return +((1 - static_cast<int>(_st)) << 28) + (static_cast<int>(_bt) << 24) + 201 (static_cast<int>(_ti) << 21) + (static_cast<int>(_ot) << 20) + 202 (static_cast<int>(_enumId) << 8) + (_dim == -1 ? 1 : (_dim == 0 ? 0 : _dim + 1)); 203 } fromInt(int i)204 static Type fromInt(int i) { 205 Type t; 206 t._st = 1 - static_cast<SetType>((i >> 28) & 0x1); 207 t._bt = static_cast<BaseType>((i >> 24) & 0xF); 208 t._ti = static_cast<TypeInst>((i >> 21) & 0x7); 209 t._ot = static_cast<OptType>((i >> 20) & 0x1); 210 t._enumId = static_cast<unsigned int>((i >> 8) & 0xFFF); 211 int dim = (i & 0x7F); 212 t._dim = (dim == 0 ? 0 : (dim == 1 ? -1 : dim - 1)); 213 return t; 214 } 215 std::string toString(EnvI& env) const; 216 std::string nonEnumToString() const; 217 218 /// Check if \a bt0 is a subtype of \a bt1 btSubtype(const Type & t0,const Type & t1,bool strictEnums)219 static bool btSubtype(const Type& t0, const Type& t1, bool strictEnums) { 220 if (t0.bt() == t1.bt() && 221 (!strictEnums || t0.dim() != 0 || (t0.enumId() == t1.enumId() || t1.enumId() == 0))) { 222 return true; 223 } 224 switch (t0.bt()) { 225 case BT_BOOL: 226 return (t1.bt() == BT_INT || t1.bt() == BT_FLOAT); 227 case BT_INT: 228 return t1.bt() == BT_FLOAT; 229 default: 230 return false; 231 } 232 } 233 234 /// Check if this type is a subtype of \a t isSubtypeOf(const Type & t,bool strictEnums) const235 bool isSubtypeOf(const Type& t, bool strictEnums) const { 236 if (_dim == 0 && t._dim != 0 && st() == ST_SET && t.st() == ST_PLAIN && bt() != BT_FLOAT && 237 (bt() == BT_BOT || btSubtype(*this, t, false) || t.bt() == BT_TOP) && ti() == TI_PAR && 238 (ot() == OT_PRESENT || ot() == t.ot())) { 239 return true; 240 } 241 // either same dimension or t has variable dimension 242 if (_dim != t._dim && (_dim == 0 || t._dim != -1)) { 243 return false; 244 } 245 // same type, this is present or both optional 246 if (ti() == t.ti() && btSubtype(*this, t, strictEnums) && st() == t.st()) { 247 return ot() == OT_PRESENT || ot() == t.ot(); 248 } 249 // this is par other than that same type as t 250 if (ti() == TI_PAR && btSubtype(*this, t, strictEnums) && st() == t.st()) { 251 return ot() == OT_PRESENT || ot() == t.ot(); 252 } 253 if (ti() == TI_PAR && t.bt() == BT_BOT) { 254 return true; 255 } 256 if ((ti() == t.ti() || ti() == TI_PAR) && bt() == BT_BOT && 257 (st() == t.st() || st() == ST_PLAIN)) { 258 return ot() == OT_PRESENT || ot() == t.ot(); 259 } 260 if (t.bt() == BT_TOP && (ot() == OT_PRESENT || ot() == t.ot()) && 261 (t.st() == ST_PLAIN || st() == t.st()) && (ti() == TI_PAR || t.ti() == TI_VAR)) { 262 return true; 263 } 264 return false; 265 } 266 267 /// Compare types cmp(const Type & t) const268 int cmp(const Type& t) const { return toInt() < t.toInt() ? -1 : (toInt() > t.toInt() ? 1 : 0); } 269 }; 270 271 }; // namespace MiniZinc 272