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