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 #include <minizinc/ast.hh>
13 #include <minizinc/astexception.hh>
14 #include <minizinc/astiterator.hh>
15 #include <minizinc/flatten_internal.hh>
16 #include <minizinc/hash.hh>
17 #include <minizinc/iter.hh>
18 #include <minizinc/model.hh>
19 #include <minizinc/prettyprinter.hh>
20
21 #include <limits>
22
23 namespace MiniZinc {
24
a(const ASTString & filename,unsigned int first_line,unsigned int first_column,unsigned int last_line,unsigned int last_column)25 Location::LocVec* Location::LocVec::a(const ASTString& filename, unsigned int first_line,
26 unsigned int first_column, unsigned int last_line,
27 unsigned int last_column) {
28 static const unsigned int pointerBits = sizeof(void*) * 8;
29 if (pointerBits <= 32) {
30 if (first_line < (1 << 8) && last_line - first_line < (1 << 7) && first_column < (1 << 6) &&
31 last_column < (1 << 7)) {
32 long long int combined = first_line;
33 combined |= (last_line - first_line) << 8;
34 combined |= (first_column) << (8 + 7);
35 combined |= (last_column) << (8 + 7 + 6);
36 auto* v = static_cast<LocVec*>(alloc(2));
37 new (v) LocVec(filename, combined);
38 return v;
39 }
40 } else if (pointerBits >= 64) {
41 if (first_line < (1 << 20) && last_line - first_line < (1 << 20) && first_column < (1 << 10) &&
42 last_column < (1 << 10)) {
43 long long int combined = first_line;
44 combined |= (static_cast<long long int>(last_line - first_line)) << 20;
45 combined |= (static_cast<long long int>(first_column)) << (20 + 20);
46 combined |= (static_cast<long long int>(last_column)) << (20 + 20 + 10);
47 auto* v = static_cast<LocVec*>(alloc(2));
48 new (v) LocVec(filename, combined);
49 return v;
50 }
51 }
52
53 auto* v = static_cast<LocVec*>(alloc(5));
54 new (v) LocVec(filename, first_line, first_column, last_line, last_column);
55 return v;
56 }
57
LocVec(const ASTString & filename,IntVal combined)58 Location::LocVec::LocVec(const ASTString& filename, IntVal combined) : ASTVec(2) {
59 *(_data + 0) = filename.aststr();
60 *(_data + 1) = IntLit::a(combined);
61 }
62
LocVec(const ASTString & filename,unsigned int first_line,unsigned int first_column,unsigned int last_line,unsigned int last_column)63 Location::LocVec::LocVec(const ASTString& filename, unsigned int first_line,
64 unsigned int first_column, unsigned int last_line,
65 unsigned int last_column)
66 : ASTVec(5) {
67 *(_data + 0) = filename.aststr();
68 *(_data + 1) = IntLit::a(first_line);
69 *(_data + 2) = IntLit::a(last_line);
70 *(_data + 3) = IntLit::a(first_column);
71 *(_data + 4) = IntLit::a(last_column);
72 }
73
74 Location Location::nonalloc;
75
76 Type Type::unboxedint = Type::parint();
77 Type Type::unboxedfloat = Type::parfloat();
78
79 Annotation Annotation::empty;
80
toString() const81 std::string Location::toString() const {
82 std::ostringstream oss;
83 oss << filename() << ":" << firstLine() << "." << firstColumn();
84 return oss.str();
85 }
86
mark() const87 void Location::mark() const {
88 if (lv() != nullptr) {
89 lv()->mark();
90 }
91 }
92
introduce() const93 Location Location::introduce() const {
94 Location l = *this;
95 if (l._locInfo.lv != nullptr) {
96 l._locInfo.t |= 1;
97 }
98 return l;
99 }
100
addAnnotation(Expression * ann)101 void Expression::addAnnotation(Expression* ann) {
102 if (!isUnboxedVal()) {
103 _ann.add(ann);
104 }
105 }
addAnnotations(const std::vector<Expression * > & ann)106 void Expression::addAnnotations(const std::vector<Expression*>& ann) {
107 if (!isUnboxedVal()) {
108 for (const auto& i : ann) {
109 if (i != nullptr) {
110 _ann.add(i);
111 }
112 }
113 }
114 }
115
116 #define pushstack(e) \
117 do { \
118 if ((e) != nullptr) { \
119 stack.push_back(e); \
120 } \
121 } while (0)
122 #define pushall(v) \
123 do { \
124 (v).mark(); \
125 for (unsigned int i = 0; i < (v).size(); i++) \
126 if ((v)[i] != nullptr) { \
127 stack.push_back((v)[i]); \
128 } \
129 } while (0)
130 #define pushann(a) \
131 do { \
132 for (ExpressionSetIter it = (a).begin(); it != (a).end(); ++it) { \
133 pushstack(*it); \
134 } \
135 } while (0)
mark(Expression * e)136 void Expression::mark(Expression* e) {
137 if (e == nullptr || e->isUnboxedVal()) {
138 return;
139 }
140 std::vector<const Expression*> stack;
141 stack.reserve(1000);
142 stack.push_back(e);
143 while (!stack.empty()) {
144 const Expression* cur = stack.back();
145 stack.pop_back();
146 if (!cur->isUnboxedVal() && cur->_gcMark == 0U) {
147 cur->_gcMark = 1U;
148 cur->loc().mark();
149 pushann(cur->ann());
150 switch (cur->eid()) {
151 case Expression::E_INTLIT:
152 case Expression::E_FLOATLIT:
153 case Expression::E_BOOLLIT:
154 case Expression::E_ANON:
155 break;
156 case Expression::E_SETLIT:
157 if (cur->cast<SetLit>()->isv() != nullptr) {
158 cur->cast<SetLit>()->isv()->mark();
159 } else if (cur->cast<SetLit>()->fsv() != nullptr) {
160 cur->cast<SetLit>()->fsv()->mark();
161 } else {
162 pushall(cur->cast<SetLit>()->v());
163 }
164 break;
165 case Expression::E_STRINGLIT:
166 cur->cast<StringLit>()->v().mark();
167 break;
168 case Expression::E_ID:
169 if (cur->cast<Id>()->idn() == -1) {
170 cur->cast<Id>()->v().mark();
171 }
172 pushstack(cur->cast<Id>()->decl());
173 break;
174 case Expression::E_ARRAYLIT:
175 if (cur->_flag2) {
176 pushstack(cur->cast<ArrayLit>()->_u.al);
177 } else {
178 pushall(ASTExprVec<Expression>(cur->cast<ArrayLit>()->_u.v));
179 }
180 cur->cast<ArrayLit>()->_dims.mark();
181 break;
182 case Expression::E_ARRAYACCESS:
183 pushstack(cur->cast<ArrayAccess>()->v());
184 pushall(cur->cast<ArrayAccess>()->idx());
185 break;
186 case Expression::E_COMP:
187 pushstack(cur->cast<Comprehension>()->_e);
188 pushall(cur->cast<Comprehension>()->_g);
189 cur->cast<Comprehension>()->_gIndex.mark();
190 break;
191 case Expression::E_ITE:
192 pushstack(cur->cast<ITE>()->elseExpr());
193 pushall(cur->cast<ITE>()->_eIfThen);
194 break;
195 case Expression::E_BINOP:
196 pushstack(cur->cast<BinOp>()->lhs());
197 pushstack(cur->cast<BinOp>()->rhs());
198 break;
199 case Expression::E_UNOP:
200 pushstack(cur->cast<UnOp>()->e());
201 break;
202 case Expression::E_CALL:
203 cur->cast<Call>()->id().mark();
204 for (unsigned int i = cur->cast<Call>()->argCount(); (i--) != 0U;) {
205 pushstack(cur->cast<Call>()->arg(i));
206 }
207 if (!cur->cast<Call>()->_u.oneArg->isUnboxedVal() &&
208 !cur->cast<Call>()->_u.oneArg->isTagged()) {
209 cur->cast<Call>()->_u.args->mark();
210 }
211 if (FunctionI* fi = cur->cast<Call>()->decl()) {
212 Item::mark(fi);
213 }
214 break;
215 case Expression::E_VARDECL:
216 pushstack(cur->cast<VarDecl>()->ti());
217 pushstack(cur->cast<VarDecl>()->e());
218 pushstack(cur->cast<VarDecl>()->id());
219 break;
220 case Expression::E_LET:
221 pushall(cur->cast<Let>()->let());
222 pushall(cur->cast<Let>()->_letOrig);
223 pushstack(cur->cast<Let>()->in());
224 break;
225 case Expression::E_TI:
226 pushstack(cur->cast<TypeInst>()->domain());
227 pushall(cur->cast<TypeInst>()->ranges());
228 break;
229 case Expression::E_TIID:
230 cur->cast<TIId>()->v().mark();
231 break;
232 }
233 }
234 }
235 }
236 #undef pushstack
237 #undef pushall
238
rehash()239 void IntLit::rehash() {
240 initHash();
241 std::hash<IntVal> h;
242 combineHash(h(_v));
243 }
244
rehash()245 void FloatLit::rehash() {
246 initHash();
247 std::hash<FloatVal> h;
248 combineHash(h(_v));
249 }
250
rehash()251 void SetLit::rehash() {
252 initHash();
253 if (isv() != nullptr) {
254 std::hash<IntVal> h;
255 for (IntSetRanges r0(isv()); r0(); ++r0) {
256 combineHash(h(r0.min()));
257 combineHash(h(r0.max()));
258 }
259 } else if (fsv() != nullptr) {
260 std::hash<FloatVal> h;
261 for (FloatSetRanges r0(fsv()); r0(); ++r0) {
262 combineHash(h(r0.min()));
263 combineHash(h(r0.max()));
264 }
265 } else {
266 for (unsigned int i = v().size(); (i--) != 0U;) {
267 combineHash(Expression::hash(_v[i]));
268 }
269 }
270 }
271
rehash()272 void BoolLit::rehash() {
273 initHash();
274 std::hash<bool> h;
275 combineHash(h(_v));
276 }
277
rehash()278 void StringLit::rehash() {
279 initHash();
280 combineHash(_v.hash());
281 }
282
rehash()283 void Id::rehash() {
284 initHash();
285 std::hash<long long int> h;
286 if (idn() == -1) {
287 combineHash(v().hash());
288 } else {
289 combineHash(h(idn()));
290 }
291 }
292
levenshteinDistance(Id * other) const293 int Id::levenshteinDistance(Id* other) const {
294 if (idn() != -1 || other->idn() != -1) {
295 return std::numeric_limits<int>::max();
296 }
297 return v().levenshteinDistance(other->v());
298 }
299
str() const300 ASTString Id::str() const {
301 if (idn() == -1) {
302 return v();
303 }
304 std::ostringstream oss;
305 oss << "X_INTRODUCED_" << idn() << "_";
306 return oss.str();
307 }
308
rehash()309 void TIId::rehash() {
310 initHash();
311 combineHash(_v.hash());
312 }
313
rehash()314 void AnonVar::rehash() { initHash(); }
315
dims() const316 unsigned int ArrayLit::dims() const {
317 return _flag2 ? ((_dims.size() - 2 * _u.al->dims()) / 2)
318 : (_dims.size() == 0 ? 1 : _dims.size() / 2);
319 }
min(unsigned int i) const320 int ArrayLit::min(unsigned int i) const {
321 if (_dims.size() == 0) {
322 assert(i == 0);
323 return 1;
324 }
325 return _dims[2 * i];
326 }
max(unsigned int i) const327 int ArrayLit::max(unsigned int i) const {
328 if (_dims.size() == 0) {
329 assert(i == 0);
330 return static_cast<int>(_u.v->size());
331 }
332 return _dims[2 * i + 1];
333 }
length() const334 unsigned int ArrayLit::length() const {
335 if (dims() == 0) {
336 return 0;
337 }
338 unsigned int l = max(0) - min(0) + 1;
339 for (int i = 1; i < dims(); i++) {
340 l *= (max(i) - min(i) + 1);
341 }
342 return l;
343 }
make1d()344 void ArrayLit::make1d() {
345 if (_dims.size() != 0) {
346 GCLock lock;
347 if (_flag2) {
348 std::vector<int> d(2 + _u.al->dims() * 2);
349 unsigned int dimOffset = dims() * 2;
350 d[0] = 1;
351 d[1] = length();
352 for (unsigned int i = 2; i < d.size(); i++) {
353 d[i] = _dims[dimOffset + i];
354 }
355 _dims = ASTIntVec(d);
356 } else {
357 std::vector<int> d(2);
358 d[0] = 1;
359 d[1] = length();
360 _dims = ASTIntVec(d);
361 }
362 }
363 }
364
origIdx(unsigned int i) const365 unsigned int ArrayLit::origIdx(unsigned int i) const {
366 assert(_flag2);
367 unsigned int curIdx = i;
368 int multiplyer = 1;
369 unsigned int oIdx = 0;
370 unsigned int sliceOffset = dims() * 2;
371 for (int curDim = static_cast<int>(_u.al->dims()) - 1; curDim >= 0; curDim--) {
372 oIdx +=
373 multiplyer *
374 ((curIdx % (_dims[sliceOffset + curDim * 2 + 1] - _dims[sliceOffset + curDim * 2] + 1)) +
375 (_dims[sliceOffset + curDim * 2] - _u.al->min(curDim)));
376 curIdx = curIdx / (_dims[sliceOffset + curDim * 2 + 1] - _dims[sliceOffset + curDim * 2] + 1);
377 multiplyer *= (_u.al->max(curDim) - _u.al->min(curDim) + 1);
378 }
379 return oIdx;
380 }
381
getSlice(unsigned int i) const382 Expression* ArrayLit::getSlice(unsigned int i) const {
383 if (!_flag2) {
384 assert(_u.v->flag());
385 int off = static_cast<int>(length()) - static_cast<int>(_u.v->size());
386 return i <= off ? (*_u.v)[0] : (*_u.v)[i - off];
387 }
388 assert(_flag2);
389 return (*_u.al)[origIdx(i)];
390 }
391
setSlice(unsigned int i,Expression * e)392 void ArrayLit::setSlice(unsigned int i, Expression* e) {
393 if (!_flag2) {
394 assert(_u.v->flag());
395 int off = static_cast<int>(length()) - static_cast<int>(_u.v->size());
396 if (i <= off) {
397 (*_u.v)[0] = e;
398 } else {
399 (*_u.v)[i - off] = e;
400 }
401 } else {
402 assert(_flag2);
403 _u.al->set(origIdx(i), e);
404 }
405 }
406
ArrayLit(const Location & loc,ArrayLit * v,const std::vector<std::pair<int,int>> & dims,const std::vector<std::pair<int,int>> & slice)407 ArrayLit::ArrayLit(const Location& loc, ArrayLit* v, const std::vector<std::pair<int, int> >& dims,
408 const std::vector<std::pair<int, int> >& slice)
409 : Expression(loc, E_ARRAYLIT, Type()) {
410 _flag1 = false;
411 _flag2 = true;
412 _u.al = v;
413 assert(slice.size() == v->dims());
414 std::vector<int> d(dims.size() * 2 + 2 * slice.size());
415 for (auto i = static_cast<unsigned int>(dims.size()); (i--) != 0U;) {
416 d[i * 2] = dims[i].first;
417 d[i * 2 + 1] = dims[i].second;
418 }
419 int sliceOffset = static_cast<int>(2 * dims.size());
420 for (auto i = static_cast<unsigned int>(slice.size()); (i--) != 0U;) {
421 d[sliceOffset + i * 2] = slice[i].first;
422 d[sliceOffset + i * 2 + 1] = slice[i].second;
423 }
424 _dims = ASTIntVec(d);
425 }
426
compress(const std::vector<Expression * > & v,const std::vector<int> & dims)427 void ArrayLit::compress(const std::vector<Expression*>& v, const std::vector<int>& dims) {
428 if (v.size() >= 4 && Expression::equal(v[0], v[1]) && Expression::equal(v[1], v[2]) &&
429 Expression::equal(v[2], v[3])) {
430 std::vector<Expression*> compress(v.size());
431 compress[0] = v[0];
432 int k = 4;
433 while (k < v.size() && Expression::equal(v[k], v[0])) {
434 k++;
435 }
436 int i = 1;
437 for (; k < v.size(); k++) {
438 compress[i++] = v[k];
439 }
440 compress.resize(i);
441 _u.v = ASTExprVec<Expression>(compress).vec();
442 _u.v->flag(true);
443 _dims = ASTIntVec(dims);
444 } else {
445 _u.v = ASTExprVec<Expression>(v).vec();
446 if (dims.size() != 2 || dims[0] != 1) {
447 // only allocate dims vector if it is not a 1d array indexed from 1
448 _dims = ASTIntVec(dims);
449 }
450 }
451 }
452
ArrayLit(const Location & loc,const std::vector<Expression * > & v,const std::vector<std::pair<int,int>> & dims)453 ArrayLit::ArrayLit(const Location& loc, const std::vector<Expression*>& v,
454 const std::vector<std::pair<int, int> >& dims)
455 : Expression(loc, E_ARRAYLIT, Type()) {
456 _flag1 = false;
457 _flag2 = false;
458 std::vector<int> d(dims.size() * 2);
459 for (auto i = static_cast<unsigned int>(dims.size()); (i--) != 0U;) {
460 d[i * 2] = dims[i].first;
461 d[i * 2 + 1] = dims[i].second;
462 }
463 compress(v, d);
464 rehash();
465 }
466
rehash()467 void ArrayLit::rehash() {
468 initHash();
469 std::hash<int> h;
470 for (int _dim : _dims) {
471 combineHash(h(_dim));
472 }
473 if (_flag2) {
474 combineHash(Expression::hash(_u.al));
475 } else {
476 for (unsigned int i = _u.v->size(); (i--) != 0U;) {
477 combineHash(h(static_cast<int>(i)));
478 combineHash(Expression::hash((*_u.v)[i]));
479 }
480 }
481 }
482
rehash()483 void ArrayAccess::rehash() {
484 initHash();
485 combineHash(Expression::hash(_v));
486 std::hash<unsigned int> h;
487 combineHash(h(_idx.size()));
488 for (unsigned int i = _idx.size(); (i--) != 0U;) {
489 combineHash(Expression::hash(_idx[i]));
490 }
491 }
492
Generator(const std::vector<ASTString> & v,Expression * in,Expression * where)493 Generator::Generator(const std::vector<ASTString>& v, Expression* in, Expression* where) {
494 std::vector<VarDecl*> vd;
495 Location loc = in == nullptr ? where->loc() : in->loc();
496 for (auto i : v) {
497 auto* nvd = new VarDecl(loc, new TypeInst(loc, Type::parint()), i);
498 nvd->toplevel(false);
499 vd.push_back(nvd);
500 }
501 _v = vd;
502 _in = in;
503 _where = where;
504 }
Generator(const std::vector<Id * > & v,Expression * in,Expression * where)505 Generator::Generator(const std::vector<Id*>& v, Expression* in, Expression* where) {
506 std::vector<VarDecl*> vd;
507 for (auto* i : v) {
508 auto* nvd = new VarDecl(i->loc(), new TypeInst(i->loc(), Type::parint()), i->v());
509 nvd->toplevel(false);
510 vd.push_back(nvd);
511 }
512 _v = vd;
513 _in = in;
514 _where = where;
515 }
Generator(const std::vector<std::string> & v,Expression * in,Expression * where)516 Generator::Generator(const std::vector<std::string>& v, Expression* in, Expression* where) {
517 std::vector<VarDecl*> vd;
518 Location loc = in == nullptr ? where->loc() : in->loc();
519 for (const auto& i : v) {
520 auto* nvd = new VarDecl(loc, new TypeInst(loc, Type::parint()), ASTString(i));
521 nvd->toplevel(false);
522 vd.push_back(nvd);
523 }
524 _v = vd;
525 _in = in;
526 _where = where;
527 }
Generator(const std::vector<VarDecl * > & v,Expression * in,Expression * where)528 Generator::Generator(const std::vector<VarDecl*>& v, Expression* in, Expression* where) {
529 _v = v;
530 _in = in;
531 _where = where;
532 }
Generator(int pos,Expression * where)533 Generator::Generator(int pos, Expression* where) {
534 std::vector<VarDecl*> vd;
535 std::ostringstream oss;
536 oss << "__dummy" << pos;
537 auto* nvd =
538 new VarDecl(Location().introduce(), new TypeInst(Location().introduce(), Type::parint()),
539 ASTString(oss.str()));
540 nvd->toplevel(false);
541 vd.push_back(nvd);
542 _v = vd;
543 _in = new ArrayLit(Location().introduce(), std::vector<Expression*>({IntLit::a(0)}));
544 _where = where;
545 }
546
set() const547 bool Comprehension::set() const { return _flag1; }
rehash()548 void Comprehension::rehash() {
549 initHash();
550 std::hash<unsigned int> h;
551 combineHash(h(static_cast<unsigned int>(set())));
552 combineHash(Expression::hash(_e));
553 combineHash(h(_gIndex.size()));
554 for (unsigned int i = _gIndex.size(); (i--) != 0U;) {
555 combineHash(h(_gIndex[i]));
556 }
557 combineHash(h(_g.size()));
558 for (unsigned int i = _g.size(); (i--) != 0U;) {
559 combineHash(Expression::hash(_g[i]));
560 }
561 }
562
numberOfGenerators() const563 unsigned int Comprehension::numberOfGenerators() const { return _gIndex.size() - 1; }
in(unsigned int i)564 Expression* Comprehension::in(unsigned int i) { return _g[_gIndex[i]]; }
in(unsigned int i) const565 const Expression* Comprehension::in(unsigned int i) const { return _g[_gIndex[i]]; }
where(unsigned int i) const566 const Expression* Comprehension::where(unsigned int i) const { return _g[_gIndex[i] + 1]; }
where(unsigned int i)567 Expression* Comprehension::where(unsigned int i) { return _g[_gIndex[i] + 1]; }
568
numberOfDecls(unsigned int i) const569 unsigned int Comprehension::numberOfDecls(unsigned int i) const {
570 return _gIndex[i + 1] - _gIndex[i] - 2;
571 }
decl(unsigned int gen,unsigned int i)572 VarDecl* Comprehension::decl(unsigned int gen, unsigned int i) {
573 return _g[_gIndex[gen] + 2 + i]->cast<VarDecl>();
574 }
decl(unsigned int gen,unsigned int i) const575 const VarDecl* Comprehension::decl(unsigned int gen, unsigned int i) const {
576 return _g[_gIndex[gen] + 2 + i]->cast<VarDecl>();
577 }
578
containsBoundVariable(Expression * e)579 bool Comprehension::containsBoundVariable(Expression* e) {
580 std::unordered_set<VarDecl*> decls;
581 for (unsigned int i = 0; i < numberOfGenerators(); i++) {
582 for (unsigned int j = 0; j < numberOfDecls(i); j++) {
583 decls.insert(decl(i, j));
584 }
585 }
586 class FindVar : public EVisitor {
587 std::unordered_set<VarDecl*>& _decls;
588 bool _found;
589
590 public:
591 FindVar(std::unordered_set<VarDecl*>& decls) : _decls(decls), _found(false) {}
592 bool enter(Expression* /*e*/) const { return !_found; }
593 void vId(Id& ident) {
594 if (_decls.find(ident.decl()) != _decls.end()) {
595 _found = true;
596 }
597 }
598 bool found() const { return _found; }
599 } _fv(decls);
600 top_down(_fv, e);
601 return _fv.found();
602 }
603
rehash()604 void ITE::rehash() {
605 initHash();
606 std::hash<unsigned int> h;
607 combineHash(h(_eIfThen.size()));
608 for (unsigned int i = _eIfThen.size(); (i--) != 0U;) {
609 combineHash(Expression::hash(_eIfThen[i]));
610 }
611 combineHash(Expression::hash(elseExpr()));
612 }
613
op() const614 BinOpType BinOp::op() const { return static_cast<BinOpType>(_secondaryId); }
rehash()615 void BinOp::rehash() {
616 initHash();
617 std::hash<int> h;
618 combineHash(h(static_cast<int>(op())));
619 combineHash(Expression::hash(_e0));
620 combineHash(Expression::hash(_e1));
621 }
622
morph(const ASTString & ident,const std::vector<Expression * > & args)623 Call* BinOp::morph(const ASTString& ident, const std::vector<Expression*>& args) {
624 _id = Call::eid;
625 _flag1 = true;
626 Call* c = cast<Call>();
627 c->id(ident);
628 c->args(args);
629 return c;
630 }
631
632 namespace {
633
634 class OpToString : public GCMarker {
635 public:
636 Id* sBOT_PLUS; // NOLINT(readability-identifier-naming)
637 Id* sBOT_MINUS; // NOLINT(readability-identifier-naming)
638 Id* sBOT_MULT; // NOLINT(readability-identifier-naming)
639 Id* sBOT_DIV; // NOLINT(readability-identifier-naming)
640 Id* sBOT_IDIV; // NOLINT(readability-identifier-naming)
641 Id* sBOT_MOD; // NOLINT(readability-identifier-naming)
642 Id* sBOT_POW; // NOLINT(readability-identifier-naming)
643 Id* sBOT_LE; // NOLINT(readability-identifier-naming)
644 Id* sBOT_LQ; // NOLINT(readability-identifier-naming)
645 Id* sBOT_GR; // NOLINT(readability-identifier-naming)
646 Id* sBOT_GQ; // NOLINT(readability-identifier-naming)
647 Id* sBOT_EQ; // NOLINT(readability-identifier-naming)
648 Id* sBOT_NQ; // NOLINT(readability-identifier-naming)
649 Id* sBOT_IN; // NOLINT(readability-identifier-naming)
650 Id* sBOT_SUBSET; // NOLINT(readability-identifier-naming)
651 Id* sBOT_SUPERSET; // NOLINT(readability-identifier-naming)
652 Id* sBOT_UNION; // NOLINT(readability-identifier-naming)
653 Id* sBOT_DIFF; // NOLINT(readability-identifier-naming)
654 Id* sBOT_SYMDIFF; // NOLINT(readability-identifier-naming)
655 Id* sBOT_INTERSECT; // NOLINT(readability-identifier-naming)
656 Id* sBOT_PLUSPLUS; // NOLINT(readability-identifier-naming)
657 Id* sBOT_EQUIV; // NOLINT(readability-identifier-naming)
658 Id* sBOT_IMPL; // NOLINT(readability-identifier-naming)
659 Id* sBOT_RIMPL; // NOLINT(readability-identifier-naming)
660 Id* sBOT_OR; // NOLINT(readability-identifier-naming)
661 Id* sBOT_AND; // NOLINT(readability-identifier-naming)
662 Id* sBOT_XOR; // NOLINT(readability-identifier-naming)
663 Id* sBOT_DOTDOT; // NOLINT(readability-identifier-naming)
664 Id* sBOT_NOT; // NOLINT(readability-identifier-naming)
665
OpToString()666 OpToString() {
667 GCLock lock;
668
669 sBOT_PLUS = new Id(Location(), "'+'", nullptr);
670 sBOT_MINUS = new Id(Location(), "'-'", nullptr);
671 sBOT_MULT = new Id(Location(), "'*'", nullptr);
672 sBOT_DIV = new Id(Location(), "'/'", nullptr);
673 sBOT_IDIV = new Id(Location(), "'div'", nullptr);
674 sBOT_MOD = new Id(Location(), "'mod'", nullptr);
675 sBOT_POW = new Id(Location(), "'^'", nullptr);
676 sBOT_LE = new Id(Location(), "'<'", nullptr);
677 sBOT_LQ = new Id(Location(), "'<='", nullptr);
678 sBOT_GR = new Id(Location(), "'>'", nullptr);
679 sBOT_GQ = new Id(Location(), "'>='", nullptr);
680 sBOT_EQ = new Id(Location(), "'='", nullptr);
681 sBOT_NQ = new Id(Location(), "'!='", nullptr);
682 sBOT_IN = new Id(Location(), "'in'", nullptr);
683 sBOT_SUBSET = new Id(Location(), "'subset'", nullptr);
684 sBOT_SUPERSET = new Id(Location(), "'superset'", nullptr);
685 sBOT_UNION = new Id(Location(), "'union'", nullptr);
686 sBOT_DIFF = new Id(Location(), "'diff'", nullptr);
687 sBOT_SYMDIFF = new Id(Location(), "'symdiff'", nullptr);
688 sBOT_INTERSECT = new Id(Location(), "'intersect'", nullptr);
689 sBOT_PLUSPLUS = new Id(Location(), "'++'", nullptr);
690 sBOT_EQUIV = new Id(Location(), "'<->'", nullptr);
691 sBOT_IMPL = new Id(Location(), "'->'", nullptr);
692 sBOT_RIMPL = new Id(Location(), "'<-'", nullptr);
693 sBOT_OR = new Id(Location(), "'\\/'", nullptr);
694 sBOT_AND = new Id(Location(), "'/\\'", nullptr);
695 sBOT_XOR = new Id(Location(), "'xor'", nullptr);
696 sBOT_DOTDOT = new Id(Location(), "'..'", nullptr);
697 sBOT_NOT = new Id(Location(), "'not'", nullptr);
698 }
699
o()700 static OpToString& o() {
701 static OpToString _o;
702 return _o;
703 }
704
mark(MINIZINC_GC_STAT_ARGS)705 void mark(MINIZINC_GC_STAT_ARGS) override {
706 Expression::mark(sBOT_PLUS);
707 Expression::mark(sBOT_MINUS);
708 Expression::mark(sBOT_MULT);
709 Expression::mark(sBOT_DIV);
710 Expression::mark(sBOT_IDIV);
711 Expression::mark(sBOT_MOD);
712 Expression::mark(sBOT_POW);
713 Expression::mark(sBOT_LE);
714 Expression::mark(sBOT_LQ);
715 Expression::mark(sBOT_GR);
716 Expression::mark(sBOT_GQ);
717 Expression::mark(sBOT_EQ);
718 Expression::mark(sBOT_NQ);
719 Expression::mark(sBOT_IN);
720 Expression::mark(sBOT_SUBSET);
721 Expression::mark(sBOT_SUPERSET);
722 Expression::mark(sBOT_UNION);
723 Expression::mark(sBOT_DIFF);
724 Expression::mark(sBOT_SYMDIFF);
725 Expression::mark(sBOT_INTERSECT);
726 Expression::mark(sBOT_PLUSPLUS);
727 Expression::mark(sBOT_EQUIV);
728 Expression::mark(sBOT_IMPL);
729 Expression::mark(sBOT_RIMPL);
730 Expression::mark(sBOT_OR);
731 Expression::mark(sBOT_AND);
732 Expression::mark(sBOT_XOR);
733 Expression::mark(sBOT_DOTDOT);
734 Expression::mark(sBOT_NOT);
735 }
736 };
737 } // namespace
738
opToString() const739 ASTString BinOp::opToString() const {
740 switch (op()) {
741 case BOT_PLUS:
742 return OpToString::o().sBOT_PLUS->v();
743 case BOT_MINUS:
744 return OpToString::o().sBOT_MINUS->v();
745 case BOT_MULT:
746 return OpToString::o().sBOT_MULT->v();
747 case BOT_DIV:
748 return OpToString::o().sBOT_DIV->v();
749 case BOT_IDIV:
750 return OpToString::o().sBOT_IDIV->v();
751 case BOT_MOD:
752 return OpToString::o().sBOT_MOD->v();
753 case BOT_POW:
754 return OpToString::o().sBOT_POW->v();
755 case BOT_LE:
756 return OpToString::o().sBOT_LE->v();
757 case BOT_LQ:
758 return OpToString::o().sBOT_LQ->v();
759 case BOT_GR:
760 return OpToString::o().sBOT_GR->v();
761 case BOT_GQ:
762 return OpToString::o().sBOT_GQ->v();
763 case BOT_EQ:
764 return OpToString::o().sBOT_EQ->v();
765 case BOT_NQ:
766 return OpToString::o().sBOT_NQ->v();
767 case BOT_IN:
768 return OpToString::o().sBOT_IN->v();
769 case BOT_SUBSET:
770 return OpToString::o().sBOT_SUBSET->v();
771 case BOT_SUPERSET:
772 return OpToString::o().sBOT_SUPERSET->v();
773 case BOT_UNION:
774 return OpToString::o().sBOT_UNION->v();
775 case BOT_DIFF:
776 return OpToString::o().sBOT_DIFF->v();
777 case BOT_SYMDIFF:
778 return OpToString::o().sBOT_SYMDIFF->v();
779 case BOT_INTERSECT:
780 return OpToString::o().sBOT_INTERSECT->v();
781 case BOT_PLUSPLUS:
782 return OpToString::o().sBOT_PLUSPLUS->v();
783 case BOT_EQUIV:
784 return OpToString::o().sBOT_EQUIV->v();
785 case BOT_IMPL:
786 return OpToString::o().sBOT_IMPL->v();
787 case BOT_RIMPL:
788 return OpToString::o().sBOT_RIMPL->v();
789 case BOT_OR:
790 return OpToString::o().sBOT_OR->v();
791 case BOT_AND:
792 return OpToString::o().sBOT_AND->v();
793 case BOT_XOR:
794 return OpToString::o().sBOT_XOR->v();
795 case BOT_DOTDOT:
796 return OpToString::o().sBOT_DOTDOT->v();
797 default:
798 assert(false);
799 return ASTString("");
800 }
801 }
802
op() const803 UnOpType UnOp::op() const { return static_cast<UnOpType>(_secondaryId); }
rehash()804 void UnOp::rehash() {
805 initHash();
806 std::hash<int> h;
807 combineHash(h(static_cast<int>(_secondaryId)));
808 combineHash(Expression::hash(_e0));
809 }
810
opToString() const811 ASTString UnOp::opToString() const {
812 switch (op()) {
813 case UOT_PLUS:
814 return OpToString::o().sBOT_PLUS->v();
815 case UOT_MINUS:
816 return OpToString::o().sBOT_MINUS->v();
817 case UOT_NOT:
818 return OpToString::o().sBOT_NOT->v();
819 default:
820 assert(false);
821 return ASTString("");
822 }
823 }
824
rehash()825 void Call::rehash() {
826 initHash();
827 combineHash(id().hash());
828 std::hash<FunctionI*> hf;
829 combineHash(hf(decl()));
830 std::hash<unsigned int> hu;
831 combineHash(hu(argCount()));
832 for (unsigned int i = 0; i < argCount(); i++) {
833 combineHash(Expression::hash(arg(i)));
834 }
835 }
836
trail()837 void VarDecl::trail() {
838 GC::trail(&_e, e());
839 if (_ti->ranges().size() > 0) {
840 GC::trail(reinterpret_cast<Expression**>(&_ti), _ti);
841 }
842 }
843
rehash()844 void VarDecl::rehash() {
845 initHash();
846 combineHash(Expression::hash(_ti));
847 combineHash(_id->hash());
848 combineHash(Expression::hash(_e));
849 }
850
rehash()851 void Let::rehash() {
852 initHash();
853 combineHash(Expression::hash(_in));
854 std::hash<unsigned int> h;
855 combineHash(h(_let.size()));
856 for (unsigned int i = _let.size(); (i--) != 0U;) {
857 combineHash(Expression::hash(_let[i]));
858 }
859 }
860
Let(const Location & loc,const std::vector<Expression * > & let,Expression * in)861 Let::Let(const Location& loc, const std::vector<Expression*>& let, Expression* in)
862 : Expression(loc, E_LET, Type()) {
863 _let = ASTExprVec<Expression>(let);
864 std::vector<Expression*> vde;
865 for (auto* i : let) {
866 if (auto* vd = Expression::dynamicCast<VarDecl>(i)) {
867 vde.push_back(vd->e());
868 for (unsigned int i = 0; i < vd->ti()->ranges().size(); i++) {
869 vde.push_back(vd->ti()->ranges()[i]->domain());
870 }
871 }
872 }
873 _letOrig = ASTExprVec<Expression>(vde);
874 _in = in;
875 rehash();
876 }
877
pushbindings()878 void Let::pushbindings() {
879 GC::mark();
880 for (unsigned int i = 0, j = 0; i < _let.size(); i++) {
881 if (auto* vd = _let[i]->dynamicCast<VarDecl>()) {
882 vd->trail();
883 vd->e(_letOrig[j++]);
884 for (unsigned int k = 0; k < vd->ti()->ranges().size(); k++) {
885 vd->ti()->ranges()[k]->domain(_letOrig[j++]);
886 }
887 }
888 }
889 }
890 // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
popbindings()891 void Let::popbindings() { GC::untrail(); }
892
rehash()893 void TypeInst::rehash() {
894 initHash();
895 std::hash<unsigned int> h;
896 unsigned int rsize = _ranges.size();
897 combineHash(h(rsize));
898 for (unsigned int i = rsize; (i--) != 0U;) {
899 combineHash(Expression::hash(_ranges[i]));
900 }
901 combineHash(Expression::hash(domain()));
902 }
903
setRanges(const std::vector<TypeInst * > & ranges)904 void TypeInst::setRanges(const std::vector<TypeInst*>& ranges) {
905 _ranges = ASTExprVec<TypeInst>(ranges);
906 if (ranges.size() == 1 && (ranges[0] != nullptr) && ranges[0]->isa<TypeInst>() &&
907 (ranges[0]->cast<TypeInst>()->domain() != nullptr) &&
908 ranges[0]->cast<TypeInst>()->domain()->isa<TIId>() &&
909 !ranges[0]->cast<TypeInst>()->domain()->cast<TIId>()->v().beginsWith("$")) {
910 _type.dim(-1);
911 } else {
912 _type.dim(static_cast<int>(ranges.size()));
913 }
914 rehash();
915 }
916
hasTiVariable() const917 bool TypeInst::hasTiVariable() const {
918 if ((domain() != nullptr) && domain()->isa<TIId>()) {
919 return true;
920 }
921 for (unsigned int i = _ranges.size(); (i--) != 0U;) {
922 if (_ranges[i]->isa<TIId>()) {
923 return true;
924 }
925 }
926 return false;
927 }
928
929 namespace {
get_type(Expression * e)930 Type get_type(Expression* e) { return e->type(); }
get_type(const Type & t)931 Type get_type(const Type& t) { return t; }
get_loc(Expression * e,FunctionI *)932 const Location& get_loc(Expression* e, FunctionI* /*fi*/) { return e->loc(); }
get_loc(const Type &,FunctionI * fi)933 const Location& get_loc(const Type& /*t*/, FunctionI* fi) { return fi->loc(); }
934
isa_tiid(Expression * e)935 bool isa_tiid(Expression* e) {
936 if (TIId* t = Expression::dynamicCast<TIId>(e)) {
937 return !t->v().beginsWith("$");
938 }
939 return false;
940 }
isa_enum_tiid(Expression * e)941 bool isa_enum_tiid(Expression* e) {
942 if (TIId* t = Expression::dynamicCast<TIId>(e)) {
943 return t->v().beginsWith("$");
944 }
945 return false;
946 }
947
948 template <class T>
return_type(EnvI & env,FunctionI * fi,const std::vector<T> & ta,bool strictEnum)949 Type return_type(EnvI& env, FunctionI* fi, const std::vector<T>& ta, bool strictEnum) {
950 if (fi->id() == constants().varRedef->id()) {
951 return Type::varbool();
952 }
953 Type ret = fi->ti()->type();
954 ASTString dh;
955 if (fi->ti()->domain() && fi->ti()->domain()->isa<TIId>()) {
956 dh = fi->ti()->domain()->cast<TIId>()->v();
957 }
958 ASTString rh;
959 if (fi->ti()->ranges().size() == 1 && isa_tiid(fi->ti()->ranges()[0]->domain())) {
960 rh = fi->ti()->ranges()[0]->domain()->cast<TIId>()->v();
961 }
962
963 ASTStringMap<Type> tmap;
964 for (unsigned int i = 0; i < ta.size(); i++) {
965 TypeInst* tii = fi->params()[i]->ti();
966 if (tii->domain() && tii->domain()->isa<TIId>()) {
967 ASTString tiid = tii->domain()->cast<TIId>()->v();
968 Type tiit = get_type(ta[i]);
969 if (tiit.enumId() != 0 && tiit.dim() > 0) {
970 const std::vector<unsigned int>& enumIds = env.getArrayEnum(tiit.enumId());
971 tiit.enumId(enumIds[enumIds.size() - 1]);
972 }
973 tiit.dim(0);
974 if (tii->type().st() == Type::ST_SET) {
975 tiit.st(Type::ST_PLAIN);
976 }
977 if (isa_enum_tiid(tii->domain())) {
978 tiit.st(Type::ST_SET);
979 }
980 auto it = tmap.find(tiid);
981 if (it == tmap.end()) {
982 tmap.insert(std::pair<ASTString, Type>(tiid, tiit));
983 } else {
984 if (it->second.dim() > 0) {
985 std::ostringstream ss;
986 ss << "type-inst variable $" << tiid << " used in both array and non-array position";
987 throw TypeError(env, get_loc(ta[i], fi), ss.str());
988 }
989 Type tiit_par = tiit;
990 tiit_par.ti(Type::TI_PAR);
991 tiit_par.ot(Type::OT_PRESENT);
992 Type its_par = it->second;
993 its_par.ti(Type::TI_PAR);
994 its_par.ot(Type::OT_PRESENT);
995 if (tiit_par.bt() == Type::BT_TOP || tiit_par.bt() == Type::BT_BOT) {
996 tiit_par.bt(its_par.bt());
997 }
998 if (its_par.bt() == Type::BT_TOP || its_par.bt() == Type::BT_BOT) {
999 its_par.bt(tiit_par.bt());
1000 }
1001 if (env.isSubtype(tiit_par, its_par, strictEnum)) {
1002 if (it->second.bt() == Type::BT_TOP) {
1003 it->second.bt(tiit.bt());
1004 }
1005 } else if (env.isSubtype(its_par, tiit_par, strictEnum)) {
1006 it->second = tiit_par;
1007 } else {
1008 std::ostringstream ss;
1009 ss << "type-inst variable $" << tiid << " instantiated with different types ("
1010 << tiit.toString(env) << " vs " << it->second.toString(env) << ")";
1011 throw TypeError(env, get_loc(ta[i], fi), ss.str());
1012 }
1013 }
1014 }
1015 if (tii->ranges().size() == 1 && isa_tiid(tii->ranges()[0]->domain())) {
1016 ASTString tiid = tii->ranges()[0]->domain()->cast<TIId>()->v();
1017 Type orig_tiit = get_type(ta[i]);
1018 if (orig_tiit.dim() == 0) {
1019 std::ostringstream ss;
1020 ss << "type-inst variable $" << tiid << " must be an array index";
1021 throw TypeError(env, get_loc(ta[i], fi), ss.str());
1022 }
1023 Type tiit = Type::top(orig_tiit.dim());
1024 if (orig_tiit.enumId() != 0) {
1025 std::vector<unsigned int> enumIds(tiit.dim() + 1);
1026 const std::vector<unsigned int>& orig_enumIds = env.getArrayEnum(orig_tiit.enumId());
1027 for (unsigned int i = 0; i < enumIds.size() - 1; i++) {
1028 enumIds[i] = orig_enumIds[i];
1029 }
1030 enumIds[enumIds.size() - 1] = 0;
1031 tiit.enumId(env.registerArrayEnum(enumIds));
1032 }
1033 auto it = tmap.find(tiid);
1034 if (it == tmap.end()) {
1035 tmap.insert(std::pair<ASTString, Type>(tiid, tiit));
1036 } else {
1037 if (it->second.dim() == 0) {
1038 std::ostringstream ss;
1039 ss << "type-inst variable $" << tiid << " used in both array and non-array position";
1040 throw TypeError(env, get_loc(ta[i], fi), ss.str());
1041 }
1042 if (it->second != tiit) {
1043 std::ostringstream ss;
1044 ss << "type-inst variable $" << tiid << " instantiated with different types ("
1045 << tiit.toString(env) + " vs " << it->second.toString(env) << ")";
1046 throw TypeError(env, get_loc(ta[i], fi), ss.str());
1047 }
1048 }
1049 } else if (tii->ranges().size() > 0) {
1050 for (unsigned int j = 0; j < tii->ranges().size(); j++) {
1051 if (isa_enum_tiid(tii->ranges()[j]->domain())) {
1052 ASTString enumTIId = tii->ranges()[j]->domain()->cast<TIId>()->v();
1053 Type tiit = get_type(ta[i]);
1054 Type enumIdT;
1055 if (tiit.enumId() != 0) {
1056 unsigned int enumId = env.getArrayEnum(tiit.enumId())[j];
1057 enumIdT = Type::parsetenum(enumId);
1058 } else {
1059 enumIdT = Type::parsetint();
1060 }
1061 auto it = tmap.find(enumTIId);
1062 // TODO: this may clash if the same enum TIId is used for different types
1063 // but the same enum
1064 if (it == tmap.end()) {
1065 tmap.insert(std::pair<ASTString, Type>(enumTIId, enumIdT));
1066 } else if (strictEnum && it->second.enumId() != enumIdT.enumId()) {
1067 std::ostringstream ss;
1068 ss << "type-inst variable $" << enumTIId << " used for different enum types";
1069 throw TypeError(env, get_loc(ta[i], fi), ss.str());
1070 }
1071 }
1072 }
1073 }
1074 }
1075 if (dh.size() != 0) {
1076 auto it = tmap.find(dh);
1077 if (it == tmap.end()) {
1078 std::ostringstream ss;
1079 ss << "type-inst variable $" << dh << " used but not defined";
1080 throw TypeError(env, fi->loc(), ss.str());
1081 }
1082 if (dh.beginsWith("$")) {
1083 // this is an enum
1084 ret.bt(Type::BT_INT);
1085 } else {
1086 ret.bt(it->second.bt());
1087 if (ret.st() == Type::ST_PLAIN) {
1088 ret.st(it->second.st());
1089 }
1090 }
1091 if (fi->ti()->ranges().size() > 0 && it->second.enumId() != 0) {
1092 std::vector<unsigned int> enumIds(fi->ti()->ranges().size() + 1);
1093 for (unsigned int i = 0; i < fi->ti()->ranges().size(); i++) {
1094 enumIds[i] = 0;
1095 }
1096 enumIds[enumIds.size() - 1] = it->second.enumId();
1097 ret.enumId(env.registerArrayEnum(enumIds));
1098 } else {
1099 ret.enumId(it->second.enumId());
1100 }
1101 }
1102 if (rh.size() != 0) {
1103 auto it = tmap.find(rh);
1104 if (it == tmap.end()) {
1105 std::ostringstream ss;
1106 ss << "type-inst variable $" << rh << " used but not defined";
1107 throw TypeError(env, fi->loc(), ss.str());
1108 }
1109 ret.dim(it->second.dim());
1110 if (it->second.enumId() != 0) {
1111 std::vector<unsigned int> enumIds(it->second.dim() + 1);
1112 const std::vector<unsigned int>& orig_enumIds = env.getArrayEnum(it->second.enumId());
1113 for (unsigned int i = 0; i < enumIds.size() - 1; i++) {
1114 enumIds[i] = orig_enumIds[i];
1115 }
1116 enumIds[enumIds.size() - 1] =
1117 ret.enumId() == 0 ? 0 : env.getArrayEnum(ret.enumId())[enumIds.size() - 1];
1118 ret.enumId(env.registerArrayEnum(enumIds));
1119 }
1120
1121 } else if (fi->ti()->ranges().size() > 0) {
1122 std::vector<unsigned int> enumIds(fi->ti()->ranges().size() + 1);
1123 bool hadRealEnum = false;
1124 if (ret.enumId() == 0) {
1125 enumIds[enumIds.size() - 1] = 0;
1126 } else {
1127 enumIds[enumIds.size() - 1] = env.getArrayEnum(ret.enumId())[enumIds.size() - 1];
1128 hadRealEnum = true;
1129 }
1130
1131 for (unsigned int i = 0; i < fi->ti()->ranges().size(); i++) {
1132 if (isa_enum_tiid(fi->ti()->ranges()[i]->domain())) {
1133 ASTString enumTIId = fi->ti()->ranges()[i]->domain()->cast<TIId>()->v();
1134 auto it = tmap.find(enumTIId);
1135 if (it == tmap.end()) {
1136 std::ostringstream ss;
1137 ss << "type-inst variable $" << enumTIId << " used but not defined";
1138 throw TypeError(env, fi->loc(), ss.str());
1139 }
1140 enumIds[i] = it->second.enumId();
1141 hadRealEnum |= (enumIds[i] != 0);
1142 } else {
1143 enumIds[i] = 0;
1144 }
1145 }
1146 if (hadRealEnum) {
1147 ret.enumId(env.registerArrayEnum(enumIds));
1148 }
1149 }
1150 return ret;
1151 }
1152 } // namespace
1153
1154 #if defined(MINIZINC_GC_STATS)
mark(Item * item,MINIZINC_GC_STAT_ARGS)1155 void Item::mark(Item* item, MINIZINC_GC_STAT_ARGS) {
1156 #else
1157 void Item::mark(Item* item) {
1158 #endif
1159 if (item->hasMark()) {
1160 return;
1161 }
1162 item->_gcMark = 1;
1163 item->loc().mark();
1164 switch (item->iid()) {
1165 case Item::II_INC:
1166 item->cast<IncludeI>()->f().mark();
1167 break;
1168 case Item::II_VD:
1169 Expression::mark(item->cast<VarDeclI>()->e());
1170 #if defined(MINIZINC_GC_STATS)
1171 gc_stats[item->cast<VarDeclI>()->e()->Expression::eid()].inmodel++;
1172 #endif
1173 break;
1174 case Item::II_ASN:
1175 item->cast<AssignI>()->id().mark();
1176 Expression::mark(item->cast<AssignI>()->e());
1177 Expression::mark(item->cast<AssignI>()->decl());
1178 break;
1179 case Item::II_CON:
1180 Expression::mark(item->cast<ConstraintI>()->e());
1181 #if defined(MINIZINC_GC_STATS)
1182 gc_stats[item->cast<ConstraintI>()->e()->Expression::eid()].inmodel++;
1183 #endif
1184 break;
1185 case Item::II_SOL: {
1186 auto* si = item->cast<SolveI>();
1187 for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) {
1188 Expression::mark(*it);
1189 }
1190 }
1191 Expression::mark(item->cast<SolveI>()->e());
1192 break;
1193 case Item::II_OUT:
1194 Expression::mark(item->cast<OutputI>()->e());
1195 break;
1196 case Item::II_FUN: {
1197 auto* fi = item->cast<FunctionI>();
1198 fi->id().mark();
1199 Expression::mark(fi->ti());
1200 for (ExpressionSetIter it = fi->ann().begin(); it != fi->ann().end(); ++it) {
1201 Expression::mark(*it);
1202 }
1203 Expression::mark(fi->e());
1204 fi->params().mark();
1205 for (unsigned int k = 0; k < fi->params().size(); k++) {
1206 Expression::mark(fi->params()[k]);
1207 }
1208 } break;
1209 }
1210 }
1211
1212 Type FunctionI::rtype(EnvI& env, const std::vector<Expression*>& ta, bool strictEnums) {
1213 return return_type(env, this, ta, strictEnums);
1214 }
1215
1216 Type FunctionI::rtype(EnvI& env, const std::vector<Type>& ta, bool strictEnums) {
1217 return return_type(env, this, ta, strictEnums);
1218 }
1219
1220 Type FunctionI::argtype(EnvI& env, const std::vector<Expression*>& ta, unsigned int n) const {
1221 TypeInst* tii = params()[n]->ti();
1222 if ((tii->domain() != nullptr) && tii->domain()->isa<TIId>()) {
1223 Type ty = ta[n]->type();
1224 ty.st(tii->type().st());
1225 ty.dim(tii->type().dim());
1226 ASTString tv = tii->domain()->cast<TIId>()->v();
1227 for (unsigned int i = 0; i < params().size(); i++) {
1228 if ((params()[i]->ti()->domain() != nullptr) && params()[i]->ti()->domain()->isa<TIId>() &&
1229 params()[i]->ti()->domain()->cast<TIId>()->v() == tv) {
1230 Type toCheck = ta[i]->type();
1231 toCheck.st(tii->type().st());
1232 toCheck.dim(tii->type().dim());
1233 if (toCheck != ty) {
1234 if (env.isSubtype(ty, toCheck, true)) {
1235 ty = toCheck;
1236 } else {
1237 Type ty_par = ty;
1238 ty_par.ti(Type::TI_PAR);
1239 Type toCheck_par = toCheck;
1240 toCheck_par.ti(Type::TI_PAR);
1241 if (env.isSubtype(ty_par, toCheck_par, true)) {
1242 ty.bt(toCheck.bt());
1243 }
1244 }
1245 }
1246 }
1247 }
1248 return ty;
1249 }
1250 return tii->type();
1251 }
1252
1253 bool Expression::equalInternal(const Expression* e0, const Expression* e1) {
1254 switch (e0->eid()) {
1255 case Expression::E_INTLIT:
1256 return e0->cast<IntLit>()->v() == e1->cast<IntLit>()->v();
1257 case Expression::E_FLOATLIT:
1258 return e0->cast<FloatLit>()->v() == e1->cast<FloatLit>()->v();
1259 case Expression::E_SETLIT: {
1260 const auto* s0 = e0->cast<SetLit>();
1261 const auto* s1 = e1->cast<SetLit>();
1262 if (s0->isv() != nullptr) {
1263 if (s1->isv() != nullptr) {
1264 IntSetRanges r0(s0->isv());
1265 IntSetRanges r1(s1->isv());
1266 return Ranges::equal(r0, r1);
1267 }
1268 return false;
1269 }
1270 if (s0->fsv() != nullptr) {
1271 if (s1->fsv() != nullptr) {
1272 FloatSetRanges r0(s0->fsv());
1273 FloatSetRanges r1(s1->fsv());
1274 return Ranges::equal(r0, r1);
1275 }
1276 return false;
1277 }
1278 if ((s1->isv() != nullptr) || (s1->fsv() != nullptr)) {
1279 return false;
1280 }
1281 if (s0->v().size() != s1->v().size()) {
1282 return false;
1283 }
1284 for (unsigned int i = 0; i < s0->v().size(); i++) {
1285 if (!Expression::equal(s0->v()[i], s1->v()[i])) {
1286 return false;
1287 }
1288 }
1289 return true;
1290 }
1291 case Expression::E_BOOLLIT:
1292 return e0->cast<BoolLit>()->v() == e1->cast<BoolLit>()->v();
1293 case Expression::E_STRINGLIT:
1294 return e0->cast<StringLit>()->v() == e1->cast<StringLit>()->v();
1295 case Expression::E_ID: {
1296 const Id* id0 = e0->cast<Id>();
1297 const Id* id1 = e1->cast<Id>();
1298 if (id0->decl() == nullptr || id1->decl() == nullptr) {
1299 return id0->v() == id1->v() && id0->idn() == id1->idn();
1300 }
1301 return id0->decl() == id1->decl() ||
1302 (id0->decl()->flat() != nullptr && id0->decl()->flat() == id1->decl()->flat());
1303 }
1304 case Expression::E_ANON:
1305 return false;
1306 case Expression::E_ARRAYLIT: {
1307 const auto* a0 = e0->cast<ArrayLit>();
1308 const auto* a1 = e1->cast<ArrayLit>();
1309 if (a0->size() != a1->size()) {
1310 return false;
1311 }
1312 if (a0->_dims.size() != a1->_dims.size()) {
1313 return false;
1314 }
1315 for (unsigned int i = 0; i < a0->_dims.size(); i++) {
1316 if (a0->_dims[i] != a1->_dims[i]) {
1317 return false;
1318 }
1319 }
1320 for (unsigned int i = 0; i < a0->size(); i++) {
1321 if (!Expression::equal((*a0)[i], (*a1)[i])) {
1322 return false;
1323 }
1324 }
1325 return true;
1326 }
1327 case Expression::E_ARRAYACCESS: {
1328 const auto* a0 = e0->cast<ArrayAccess>();
1329 const auto* a1 = e1->cast<ArrayAccess>();
1330 if (!Expression::equal(a0->v(), a1->v())) {
1331 return false;
1332 }
1333 if (a0->idx().size() != a1->idx().size()) {
1334 return false;
1335 }
1336 for (unsigned int i = 0; i < a0->idx().size(); i++) {
1337 if (!Expression::equal(a0->idx()[i], a1->idx()[i])) {
1338 return false;
1339 }
1340 }
1341 return true;
1342 }
1343 case Expression::E_COMP: {
1344 const auto* c0 = e0->cast<Comprehension>();
1345 const auto* c1 = e1->cast<Comprehension>();
1346 if (c0->set() != c1->set()) {
1347 return false;
1348 }
1349 if (!Expression::equal(c0->_e, c1->_e)) {
1350 return false;
1351 }
1352 if (c0->_g.size() != c1->_g.size()) {
1353 return false;
1354 }
1355 for (unsigned int i = 0; i < c0->_g.size(); i++) {
1356 if (!Expression::equal(c0->_g[i], c1->_g[i])) {
1357 return false;
1358 }
1359 }
1360 for (unsigned int i = 0; i < c0->_gIndex.size(); i++) {
1361 if (c0->_gIndex[i] != c1->_gIndex[i]) {
1362 return false;
1363 }
1364 }
1365 return true;
1366 }
1367 case Expression::E_ITE: {
1368 const ITE* i0 = e0->cast<ITE>();
1369 const ITE* i1 = e1->cast<ITE>();
1370 if (i0->_eIfThen.size() != i1->_eIfThen.size()) {
1371 return false;
1372 }
1373 for (unsigned int i = i0->_eIfThen.size(); (i--) != 0U;) {
1374 if (!Expression::equal(i0->_eIfThen[i], i1->_eIfThen[i])) {
1375 return false;
1376 }
1377 }
1378 return Expression::equal(i0->elseExpr(), i1->elseExpr());
1379 }
1380 case Expression::E_BINOP: {
1381 const auto* b0 = e0->cast<BinOp>();
1382 const auto* b1 = e1->cast<BinOp>();
1383 if (b0->op() != b1->op()) {
1384 return false;
1385 }
1386 if (!Expression::equal(b0->lhs(), b1->lhs())) {
1387 return false;
1388 }
1389 if (!Expression::equal(b0->rhs(), b1->rhs())) {
1390 return false;
1391 }
1392 return true;
1393 }
1394 case Expression::E_UNOP: {
1395 const UnOp* b0 = e0->cast<UnOp>();
1396 const UnOp* b1 = e1->cast<UnOp>();
1397 if (b0->op() != b1->op()) {
1398 return false;
1399 }
1400 if (!Expression::equal(b0->e(), b1->e())) {
1401 return false;
1402 }
1403 return true;
1404 }
1405 case Expression::E_CALL: {
1406 const Call* c0 = e0->cast<Call>();
1407 const Call* c1 = e1->cast<Call>();
1408 if (c0->id() != c1->id()) {
1409 return false;
1410 }
1411 if (c0->decl() != c1->decl()) {
1412 return false;
1413 }
1414 if (c0->argCount() != c1->argCount()) {
1415 return false;
1416 }
1417 for (unsigned int i = 0; i < c0->argCount(); i++) {
1418 if (!Expression::equal(c0->arg(i), c1->arg(i))) {
1419 return false;
1420 }
1421 }
1422 return true;
1423 }
1424 case Expression::E_VARDECL: {
1425 const auto* v0 = e0->cast<VarDecl>();
1426 const auto* v1 = e1->cast<VarDecl>();
1427 if (!Expression::equal(v0->ti(), v1->ti())) {
1428 return false;
1429 }
1430 if (!Expression::equal(v0->id(), v1->id())) {
1431 return false;
1432 }
1433 if (!Expression::equal(v0->e(), v1->e())) {
1434 return false;
1435 }
1436 return true;
1437 }
1438 case Expression::E_LET: {
1439 const Let* l0 = e0->cast<Let>();
1440 const Let* l1 = e1->cast<Let>();
1441 if (!Expression::equal(l0->in(), l1->in())) {
1442 return false;
1443 }
1444 if (l0->let().size() != l1->let().size()) {
1445 return false;
1446 }
1447 for (unsigned int i = l0->let().size(); (i--) != 0U;) {
1448 if (!Expression::equal(l0->let()[i], l1->let()[i])) {
1449 return false;
1450 }
1451 }
1452 return true;
1453 }
1454 case Expression::E_TI: {
1455 const auto* t0 = e0->cast<TypeInst>();
1456 const auto* t1 = e1->cast<TypeInst>();
1457 if (t0->ranges().size() != t1->ranges().size()) {
1458 return false;
1459 }
1460 for (unsigned int i = t0->ranges().size(); (i--) != 0U;) {
1461 if (!Expression::equal(t0->ranges()[i], t1->ranges()[i])) {
1462 return false;
1463 }
1464 }
1465 return Expression::equal(t0->domain(), t1->domain());
1466 }
1467 case Expression::E_TIID:
1468 return false;
1469 default:
1470 assert(false);
1471 return false;
1472 }
1473 }
1474
1475 Constants::Constants() {
1476 GCLock lock;
1477 auto* ti = new TypeInst(Location(), Type::parbool());
1478 literalTrue = new BoolLit(Location(), true);
1479 varTrue = new VarDecl(Location(), ti, "_bool_true", literalTrue);
1480 literalFalse = new BoolLit(Location(), false);
1481 varFalse = new VarDecl(Location(), ti, "_bool_false", literalFalse);
1482 varIgnore = new VarDecl(Location(), ti, "_bool_ignore");
1483 absent = new Id(Location(), "_absent", nullptr);
1484 varRedef = new FunctionI(Location(), "__internal_varRedef",
1485 new TypeInst(Location(), Type::varbool()), std::vector<VarDecl*>());
1486 Type absent_t;
1487 absent_t.bt(Type::BT_BOT);
1488 absent_t.dim(0);
1489 absent_t.st(Type::ST_PLAIN);
1490 absent_t.ot(Type::OT_OPTIONAL);
1491 absent->type(absent_t);
1492
1493 IntSetVal* isv_infty = IntSetVal::a(-IntVal::infinity(), IntVal::infinity());
1494 infinity = new SetLit(Location(), isv_infty);
1495
1496 ids.forall = ASTString("forall");
1497 ids.forallReif = ASTString("forallReif");
1498 ids.exists = ASTString("exists");
1499 ids.clause = ASTString("clause");
1500 ids.bool2int = ASTString("bool2int");
1501 ids.int2float = ASTString("int2float");
1502 ids.bool2float = ASTString("bool2float");
1503 ids.assert = ASTString("assert");
1504 ids.mzn_deprecate = ASTString("mzn_deprecate");
1505 ids.mzn_symmetry_breaking_constraint = ASTString("mzn_symmetry_breaking_constraint");
1506 ids.mzn_redundant_constraint = ASTString("mzn_redundant_constraint");
1507 ids.trace = ASTString("trace");
1508
1509 ids.sum = ASTString("sum");
1510 ids.lin_exp = ASTString("lin_exp");
1511 ids.element = ASTString("element");
1512
1513 ids.show = ASTString("show");
1514 ids.output = ASTString("output");
1515 ids.fix = ASTString("fix");
1516
1517 ids.int_.lin_eq = ASTString("int_lin_eq");
1518 ids.int_.lin_le = ASTString("int_lin_le");
1519 ids.int_.lin_ne = ASTString("int_lin_ne");
1520 ids.int_.plus = ASTString("int_plus");
1521 ids.int_.minus = ASTString("int_minus");
1522 ids.int_.times = ASTString("int_times");
1523 ids.int_.div = ASTString("int_div");
1524 ids.int_.mod = ASTString("int_mod");
1525 ids.int_.lt = ASTString("int_lt");
1526 ids.int_.le = ASTString("int_le");
1527 ids.int_.gt = ASTString("int_gt");
1528 ids.int_.ge = ASTString("int_ge");
1529 ids.int_.eq = ASTString("int_eq");
1530 ids.int_.ne = ASTString("int_ne");
1531
1532 ids.int_reif.lin_eq = ASTString("int_lin_eq_reif");
1533 ids.int_reif.lin_le = ASTString("int_lin_le_reif");
1534 ids.int_reif.lin_ne = ASTString("int_lin_ne_reif");
1535 ids.int_reif.plus = ASTString("int_plus_reif");
1536 ids.int_reif.minus = ASTString("int_minus_reif");
1537 ids.int_reif.times = ASTString("int_times_reif");
1538 ids.int_reif.div = ASTString("int_div_reif");
1539 ids.int_reif.mod = ASTString("int_mod_reif");
1540 ids.int_reif.lt = ASTString("int_lt_reif");
1541 ids.int_reif.le = ASTString("int_le_reif");
1542 ids.int_reif.gt = ASTString("int_gt_reif");
1543 ids.int_reif.ge = ASTString("int_ge_reif");
1544 ids.int_reif.eq = ASTString("int_eq_reif");
1545 ids.int_reif.ne = ASTString("int_ne_reif");
1546
1547 ids.float_.lin_eq = ASTString("float_lin_eq");
1548 ids.float_.lin_le = ASTString("float_lin_le");
1549 ids.float_.lin_lt = ASTString("float_lin_lt");
1550 ids.float_.lin_ne = ASTString("float_lin_ne");
1551 ids.float_.plus = ASTString("float_plus");
1552 ids.float_.minus = ASTString("float_minus");
1553 ids.float_.times = ASTString("float_times");
1554 ids.float_.div = ASTString("float_div");
1555 ids.float_.mod = ASTString("float_mod");
1556 ids.float_.lt = ASTString("float_lt");
1557 ids.float_.le = ASTString("float_le");
1558 ids.float_.gt = ASTString("float_gt");
1559 ids.float_.ge = ASTString("float_ge");
1560 ids.float_.eq = ASTString("float_eq");
1561 ids.float_.ne = ASTString("float_ne");
1562 ids.float_.in = ASTString("float_in");
1563 ids.float_.dom = ASTString("float_dom");
1564
1565 ids.float_reif.lin_eq = ASTString("float_lin_eq_reif");
1566 ids.float_reif.lin_le = ASTString("float_lin_le_reif");
1567 ids.float_reif.lin_lt = ASTString("float_lin_lt_reif");
1568 ids.float_reif.lin_ne = ASTString("float_lin_ne_reif");
1569 ids.float_reif.plus = ASTString("float_plus_reif");
1570 ids.float_reif.minus = ASTString("float_minus_reif");
1571 ids.float_reif.times = ASTString("float_times_reif");
1572 ids.float_reif.div = ASTString("float_div_reif");
1573 ids.float_reif.mod = ASTString("float_mod_reif");
1574 ids.float_reif.lt = ASTString("float_lt_reif");
1575 ids.float_reif.le = ASTString("float_le_reif");
1576 ids.float_reif.gt = ASTString("float_gt_reif");
1577 ids.float_reif.ge = ASTString("float_ge_reif");
1578 ids.float_reif.eq = ASTString("float_eq_reif");
1579 ids.float_reif.ne = ASTString("float_ne_reif");
1580 ids.float_reif.in = ASTString("float_in_reif");
1581
1582 ids.bool_eq = ASTString("bool_eq");
1583 ids.bool_eq_reif = ASTString("bool_eq_reif");
1584 ids.bool_not = ASTString("bool_not");
1585 ids.bool_clause = ASTString("bool_clause");
1586 ids.bool_clause_reif = ASTString("bool_clause_reif");
1587 ids.bool_xor = ASTString("bool_xor");
1588 ids.array_bool_or = ASTString("array_bool_or");
1589 ids.array_bool_and = ASTString("array_bool_and");
1590 ids.set_eq = ASTString("set_eq");
1591 ids.set_in = ASTString("set_in");
1592 ids.set_subset = ASTString("set_subset");
1593 ids.set_card = ASTString("set_card");
1594 ids.pow = ASTString("pow");
1595 ids.mzn_set_in_internal = ASTString("mzn_set_in_internal");
1596
1597 ids.introduced_var = ASTString("__INTRODUCED");
1598 ids.anonEnumFromStrings = ASTString("anon_enum");
1599
1600 ctx.root = new Id(Location(), ASTString("ctx_root"), nullptr);
1601 ctx.root->type(Type::ann());
1602 ctx.pos = new Id(Location(), ASTString("ctx_pos"), nullptr);
1603 ctx.pos->type(Type::ann());
1604 ctx.neg = new Id(Location(), ASTString("ctx_neg"), nullptr);
1605 ctx.neg->type(Type::ann());
1606 ctx.mix = new Id(Location(), ASTString("ctx_mix"), nullptr);
1607 ctx.mix->type(Type::ann());
1608
1609 ann.output_var = new Id(Location(), ASTString("output_var"), nullptr);
1610 ann.output_var->type(Type::ann());
1611 ann.output_only = new Id(Location(), ASTString("output_only"), nullptr);
1612 ann.output_only->type(Type::ann());
1613 ann.output_array = ASTString("output_array");
1614 ann.add_to_output = new Id(Location(), ASTString("add_to_output"), nullptr);
1615 ann.add_to_output->type(Type::ann());
1616 ann.mzn_check_var = new Id(Location(), ASTString("mzn_check_var"), nullptr);
1617 ann.mzn_check_var->type(Type::ann());
1618 ann.mzn_check_enum_var = ASTString("mzn_check_enum_var");
1619 ann.is_defined_var = new Id(Location(), ASTString("is_defined_var"), nullptr);
1620 ann.is_defined_var->type(Type::ann());
1621 ann.defines_var = ASTString("defines_var");
1622 ann.is_reverse_map = new Id(Location(), ASTString("is_reverse_map"), nullptr);
1623 ann.is_reverse_map->type(Type::ann());
1624 ann.promise_total = new Id(Location(), ASTString("promise_total"), nullptr);
1625 ann.promise_total->type(Type::ann());
1626 ann.maybe_partial = new Id(Location(), ASTString("maybe_partial"), nullptr);
1627 ann.maybe_partial->type(Type::ann());
1628 ann.doc_comment = ASTString("doc_comment");
1629 ann.mzn_path = ASTString("mzn_path");
1630 ann.is_introduced = ASTString("is_introduced");
1631 ann.user_cut = new Id(Location(), ASTString("user_cut"), nullptr);
1632 ann.user_cut->type(Type::ann());
1633 ann.lazy_constraint = new Id(Location(), ASTString("lazy_constraint"), nullptr);
1634 ann.lazy_constraint->type(Type::ann());
1635 #ifndef NDEBUG
1636 ann.mzn_break_here = new Id(Location(), ASTString("mzn_break_here"), nullptr);
1637 ann.mzn_break_here->type(Type::ann());
1638 #endif
1639 ann.rhs_from_assignment = new Id(Location(), ASTString("mzn_rhs_from_assignment"), nullptr);
1640 ann.rhs_from_assignment->type(Type::ann());
1641 ann.domain_change_constraint = new Id(Location(), ASTString("domain_change_constraint"), nullptr);
1642 ann.domain_change_constraint->type(Type::ann());
1643 ann.mzn_deprecated = ASTString("mzn_deprecated");
1644 ann.mzn_was_undefined = new Id(Location(), ASTString("mzn_was_undefined"), nullptr);
1645 ann.mzn_was_undefined->type(Type::ann());
1646 ann.array_check_form = new Id(Location(), ASTString("array_check_form"), nullptr);
1647 ann.array_check_form->type(Type::ann());
1648
1649 cli.cmdlineData_short_str = ASTString("-D");
1650 cli.cmdlineData_str = ASTString("--cmdline-data");
1651 cli.datafile_str = ASTString("--data");
1652 cli.datafile_short_str = ASTString("-d");
1653 cli.globalsDir_str = ASTString("--globals-dir");
1654 cli.globalsDir_alt_str = ASTString("--mzn-globals-dir");
1655 cli.globalsDir_short_str = ASTString("-G");
1656 cli.help_str = ASTString("--help");
1657 cli.help_short_str = ASTString("-h");
1658 cli.ignoreStdlib_str = ASTString("--ignore-stdlib");
1659 cli.include_str = ASTString("-I");
1660 cli.inputFromStdin_str = ASTString("--input-from-stdin");
1661 cli.instanceCheckOnly_str = ASTString("--instance-check-only");
1662 cli.newfzn_str = ASTString("--newfzn");
1663 cli.no_optimize_str = ASTString("--no-optimize");
1664 cli.no_optimize_alt_str = ASTString("--no-optimise");
1665 cli.no_outputOzn_str = ASTString("--no-output-ozn");
1666 cli.no_outputOzn_short_str = ASTString("-O-");
1667 cli.no_typecheck_str = ASTString("--no-typecheck");
1668 cli.outputBase_str = ASTString("--output-base");
1669 cli.outputFznToStdout_str = ASTString("--output-to-stdout");
1670 cli.outputFznToStdout_alt_str = ASTString("--output-fzn-to-stdout");
1671 cli.outputOznToFile_str = ASTString("--output-ozn-to-file");
1672 cli.outputOznToStdout_str = ASTString("--output-ozn-to-stdout");
1673 cli.outputFznToFile_alt_str = ASTString("--output-fzn-to-file");
1674 cli.outputFznToFile_short_str = ASTString("-o");
1675 cli.outputFznToFile_str = ASTString("--output-to-file");
1676 cli.rangeDomainsOnly_str = ASTString("--only-range-domains");
1677 cli.statistics_str = ASTString("--statistics");
1678 cli.statistics_short_str = ASTString("-s");
1679 cli.stdlib_str = ASTString("--stdlib-dir");
1680 cli.verbose_str = ASTString("--verbose");
1681 cli.verbose_short_str = ASTString("-v");
1682 cli.version_str = ASTString("--version");
1683 cli.werror_str = ASTString("-Werror");
1684
1685 cli.solver.all_sols_str = ASTString("-a");
1686 cli.solver.fzn_solver_str = ASTString("--solver");
1687
1688 opts.cmdlineData = ASTString("cmdlineData");
1689 opts.datafile = ASTString("datafile");
1690 opts.datafiles = ASTString("datafiles");
1691 opts.fznToFile = ASTString("fznToFile");
1692 opts.fznToStdout = ASTString("fznToStdout");
1693 opts.globalsDir = ASTString("globalsDir");
1694 opts.ignoreStdlib = ASTString("ignoreStdlib");
1695 opts.includeDir = ASTString("includeDir");
1696 opts.includePaths = ASTString("includePaths");
1697 opts.inputFromStdin = ASTString("inputStdin");
1698 opts.instanceCheckOnly = ASTString("instanceCheckOnly");
1699 opts.model = ASTString("model");
1700 opts.newfzn = ASTString("newfzn");
1701 opts.noOznOutput = ASTString("noOznOutput");
1702 opts.optimize = ASTString("optimize");
1703 opts.outputBase = ASTString("outputBase");
1704 opts.oznToFile = ASTString("oznToFile");
1705 opts.oznToStdout = ASTString("oznToStdout");
1706 opts.rangeDomainsOnly = ASTString("rangeDomainsOnly");
1707 opts.statistics = ASTString("statistics");
1708 opts.stdlib = ASTString("stdlib");
1709 opts.typecheck = ASTString("typecheck");
1710 opts.verbose = ASTString("verbose");
1711 opts.werror = ASTString("werror");
1712
1713 opts.solver.allSols = ASTString("allSols");
1714 opts.solver.numSols = ASTString("numSols");
1715 opts.solver.threads = ASTString("threads");
1716 opts.solver.fzn_solver = ASTString("fznsolver");
1717 opts.solver.fzn_flags = ASTString("fzn_flags");
1718 opts.solver.fzn_flag = ASTString("fzn_flag");
1719 opts.solver.fzn_time_limit_ms = ASTString("fzn_time_limit_ms");
1720 opts.solver.fzn_sigint = ASTString("fzn_sigint");
1721
1722 cli_cat.general = ASTString("General Options");
1723 cli_cat.io = ASTString("Input/Output Options");
1724 cli_cat.solver = ASTString("Solver Options");
1725 cli_cat.translation = ASTString("Translation Options");
1726 };
1727
1728 void Constants::mark(MINIZINC_GC_STAT_ARGS) {
1729 Expression::mark(literalTrue);
1730 Expression::mark(varTrue);
1731 Expression::mark(literalFalse);
1732 Expression::mark(varFalse);
1733 Expression::mark(varIgnore);
1734 #if defined(MINIZINC_GC_STATS)
1735 Item::mark(varRedef, gc_stats);
1736 #else
1737 Item::mark(varRedef);
1738 #endif
1739 Expression::mark(absent);
1740 Expression::mark(infinity);
1741
1742 ids.forall.mark();
1743 ids.exists.mark();
1744 ids.clause.mark();
1745 ids.bool2int.mark();
1746 ids.int2float.mark();
1747 ids.bool2float.mark();
1748 ids.sum.mark();
1749 ids.lin_exp.mark();
1750 ids.element.mark();
1751 ids.show.mark();
1752 ids.output.mark();
1753 ids.fix.mark();
1754
1755 ids.int_.lin_eq.mark();
1756 ids.int_.lin_le.mark();
1757 ids.int_.lin_ne.mark();
1758 ids.int_.plus.mark();
1759 ids.int_.minus.mark();
1760 ids.int_.times.mark();
1761 ids.int_.div.mark();
1762 ids.int_.mod.mark();
1763 ids.int_.lt.mark();
1764 ids.int_.le.mark();
1765 ids.int_.gt.mark();
1766 ids.int_.ge.mark();
1767 ids.int_.eq.mark();
1768 ids.int_.ne.mark();
1769
1770 ids.int_reif.lin_eq.mark();
1771 ids.int_reif.lin_le.mark();
1772 ids.int_reif.lin_ne.mark();
1773 ids.int_reif.plus.mark();
1774 ids.int_reif.minus.mark();
1775 ids.int_reif.times.mark();
1776 ids.int_reif.div.mark();
1777 ids.int_reif.mod.mark();
1778 ids.int_reif.lt.mark();
1779 ids.int_reif.le.mark();
1780 ids.int_reif.gt.mark();
1781 ids.int_reif.ge.mark();
1782 ids.int_reif.eq.mark();
1783 ids.int_reif.ne.mark();
1784
1785 ids.float_.lin_eq.mark();
1786 ids.float_.lin_le.mark();
1787 ids.float_.lin_lt.mark();
1788 ids.float_.lin_ne.mark();
1789 ids.float_.plus.mark();
1790 ids.float_.minus.mark();
1791 ids.float_.times.mark();
1792 ids.float_.div.mark();
1793 ids.float_.mod.mark();
1794 ids.float_.lt.mark();
1795 ids.float_.le.mark();
1796 ids.float_.gt.mark();
1797 ids.float_.ge.mark();
1798 ids.float_.eq.mark();
1799 ids.float_.ne.mark();
1800 ids.float_.in.mark();
1801 ids.float_.dom.mark();
1802
1803 ids.float_reif.lin_eq.mark();
1804 ids.float_reif.lin_le.mark();
1805 ids.float_reif.lin_lt.mark();
1806 ids.float_reif.lin_ne.mark();
1807 ids.float_reif.plus.mark();
1808 ids.float_reif.minus.mark();
1809 ids.float_reif.times.mark();
1810 ids.float_reif.div.mark();
1811 ids.float_reif.mod.mark();
1812 ids.float_reif.lt.mark();
1813 ids.float_reif.le.mark();
1814 ids.float_reif.gt.mark();
1815 ids.float_reif.ge.mark();
1816 ids.float_reif.eq.mark();
1817 ids.float_reif.ne.mark();
1818 ids.float_reif.in.mark();
1819
1820 ids.bool_eq.mark();
1821 ids.bool_eq_reif.mark();
1822 ids.bool_not.mark();
1823 ids.bool_clause.mark();
1824 ids.bool_clause_reif.mark();
1825 ids.bool_xor.mark();
1826 ids.array_bool_or.mark();
1827 ids.array_bool_and.mark();
1828 ids.set_eq.mark();
1829 ids.set_in.mark();
1830 ids.set_subset.mark();
1831 ids.set_card.mark();
1832 ids.pow.mark();
1833 ids.mzn_set_in_internal.mark();
1834
1835 ids.assert.mark();
1836 ids.mzn_deprecate.mark();
1837 ids.trace.mark();
1838 ids.mzn_symmetry_breaking_constraint.mark();
1839 ids.mzn_redundant_constraint.mark();
1840 ids.introduced_var.mark();
1841 ids.anonEnumFromStrings.mark();
1842 Expression::mark(ctx.root);
1843 Expression::mark(ctx.pos);
1844 Expression::mark(ctx.neg);
1845 Expression::mark(ctx.mix);
1846 Expression::mark(ann.output_var);
1847 Expression::mark(ann.output_only);
1848 Expression::mark(ann.add_to_output);
1849 Expression::mark(ann.mzn_check_var);
1850 ann.mzn_check_enum_var.mark();
1851 ann.output_array.mark();
1852 Expression::mark(ann.is_defined_var);
1853 ann.defines_var.mark();
1854 Expression::mark(ann.is_reverse_map);
1855 Expression::mark(ann.promise_total);
1856 Expression::mark(ann.maybe_partial);
1857 ann.doc_comment.mark();
1858 ann.mzn_path.mark();
1859 ann.is_introduced.mark();
1860 Expression::mark(ann.user_cut);
1861 Expression::mark(ann.lazy_constraint);
1862 #ifndef NDEBUG
1863 Expression::mark(ann.mzn_break_here);
1864 #endif
1865 Expression::mark(ann.rhs_from_assignment);
1866 Expression::mark(ann.domain_change_constraint);
1867 ann.mzn_deprecated.mark();
1868 Expression::mark(ann.mzn_was_undefined);
1869 Expression::mark(ann.array_check_form);
1870
1871 cli.cmdlineData_short_str.mark();
1872 cli.cmdlineData_str.mark();
1873 cli.datafile_short_str.mark();
1874 cli.datafile_str.mark();
1875 cli.globalsDir_alt_str.mark();
1876 cli.globalsDir_short_str.mark();
1877 cli.globalsDir_str.mark();
1878 cli.help_short_str.mark();
1879 cli.help_str.mark();
1880 cli.ignoreStdlib_str.mark();
1881 cli.include_str.mark();
1882 cli.inputFromStdin_str.mark();
1883 cli.instanceCheckOnly_str.mark();
1884 cli.newfzn_str.mark();
1885 cli.no_optimize_alt_str.mark();
1886 cli.no_optimize_str.mark();
1887 cli.no_outputOzn_short_str.mark();
1888 cli.no_outputOzn_str.mark();
1889 cli.no_typecheck_str.mark();
1890 cli.outputBase_str.mark();
1891 cli.outputFznToStdout_alt_str.mark();
1892 cli.outputFznToStdout_str.mark();
1893 cli.outputOznToFile_str.mark();
1894 cli.outputOznToStdout_str.mark();
1895 cli.outputFznToFile_alt_str.mark();
1896 cli.outputFznToFile_short_str.mark();
1897 cli.outputFznToFile_str.mark();
1898 cli.rangeDomainsOnly_str.mark();
1899 cli.statistics_short_str.mark();
1900 cli.statistics_str.mark();
1901 cli.stdlib_str.mark();
1902 cli.verbose_short_str.mark();
1903 cli.verbose_str.mark();
1904 cli.version_str.mark();
1905 cli.werror_str.mark();
1906
1907 cli.solver.all_sols_str.mark();
1908 cli.solver.fzn_solver_str.mark();
1909
1910 opts.cmdlineData.mark();
1911 opts.datafile.mark();
1912 opts.datafiles.mark();
1913 opts.fznToFile.mark();
1914 opts.fznToStdout.mark();
1915 opts.globalsDir.mark();
1916 opts.ignoreStdlib.mark();
1917 opts.includePaths.mark();
1918 opts.includeDir.mark();
1919 opts.inputFromStdin.mark();
1920 opts.instanceCheckOnly.mark();
1921 opts.model.mark();
1922 opts.newfzn.mark();
1923 opts.noOznOutput.mark();
1924 opts.optimize.mark();
1925 opts.outputBase.mark();
1926 opts.oznToFile.mark();
1927 opts.oznToStdout.mark();
1928 opts.rangeDomainsOnly.mark();
1929 opts.statistics.mark();
1930 opts.stdlib.mark();
1931 opts.typecheck.mark();
1932 opts.verbose.mark();
1933 opts.werror.mark();
1934
1935 opts.solver.allSols.mark();
1936 opts.solver.numSols.mark();
1937 opts.solver.threads.mark();
1938 opts.solver.fzn_solver.mark();
1939 opts.solver.fzn_flags.mark();
1940 opts.solver.fzn_flag.mark();
1941 opts.solver.fzn_time_limit_ms.mark();
1942 opts.solver.fzn_sigint.mark();
1943
1944 cli_cat.general.mark();
1945 cli_cat.io.mark();
1946 cli_cat.solver.mark();
1947 cli_cat.translation.mark();
1948 }
1949
1950 const int Constants::max_array_size;
1951
1952 Constants& constants() {
1953 static Constants _c;
1954 return _c;
1955 }
1956
1957 Annotation::~Annotation() { delete _s; }
1958
1959 bool Annotation::contains(Expression* e) const { return (_s != nullptr) && _s->contains(e); }
1960
1961 bool Annotation::isEmpty() const { return _s == nullptr || _s->isEmpty(); }
1962
1963 ExpressionSetIter Annotation::begin() const {
1964 return _s == nullptr ? ExpressionSetIter(true) : _s->begin();
1965 }
1966
1967 ExpressionSetIter Annotation::end() const {
1968 return _s == nullptr ? ExpressionSetIter(true) : _s->end();
1969 }
1970
1971 void Annotation::add(Expression* e) {
1972 if (_s == nullptr) {
1973 _s = new ExpressionSet;
1974 }
1975 if (e != nullptr) {
1976 _s->insert(e);
1977 }
1978 }
1979
1980 void Annotation::add(std::vector<Expression*> e) {
1981 if (_s == nullptr) {
1982 _s = new ExpressionSet;
1983 }
1984 for (auto i = static_cast<unsigned int>(e.size()); (i--) != 0U;) {
1985 if (e[i] != nullptr) {
1986 _s->insert(e[i]);
1987 }
1988 }
1989 }
1990
1991 void Annotation::remove(Expression* e) {
1992 if ((_s != nullptr) && (e != nullptr)) {
1993 _s->remove(e);
1994 }
1995 }
1996
1997 void Annotation::removeCall(const ASTString& id) {
1998 if (_s == nullptr) {
1999 return;
2000 }
2001 std::vector<Expression*> toRemove;
2002 for (ExpressionSetIter it = _s->begin(); it != _s->end(); ++it) {
2003 if (Call* c = (*it)->dynamicCast<Call>()) {
2004 if (c->id() == id) {
2005 toRemove.push_back(*it);
2006 }
2007 }
2008 }
2009 for (auto i = static_cast<unsigned int>(toRemove.size()); (i--) != 0U;) {
2010 _s->remove(toRemove[i]);
2011 }
2012 }
2013
2014 Call* Annotation::getCall(const ASTString& id) const {
2015 if (_s == nullptr) {
2016 return nullptr;
2017 }
2018 for (ExpressionSetIter it = _s->begin(); it != _s->end(); ++it) {
2019 if (Call* c = (*it)->dynamicCast<Call>()) {
2020 if (c->id() == id) {
2021 return c;
2022 }
2023 }
2024 }
2025 return nullptr;
2026 }
2027
2028 bool Annotation::containsCall(const MiniZinc::ASTString& id) const {
2029 if (_s == nullptr) {
2030 return false;
2031 }
2032 for (ExpressionSetIter it = _s->begin(); it != _s->end(); ++it) {
2033 if (Call* c = (*it)->dynamicCast<Call>()) {
2034 if (c->id() == id) {
2035 return true;
2036 }
2037 }
2038 }
2039 return false;
2040 }
2041
2042 void Annotation::clear() {
2043 if (_s != nullptr) {
2044 _s->clear();
2045 }
2046 }
2047
2048 void Annotation::merge(const Annotation& ann) {
2049 if (ann._s == nullptr) {
2050 return;
2051 }
2052 if (_s == nullptr) {
2053 _s = new ExpressionSet;
2054 }
2055 for (ExpressionSetIter it = ann.begin(); it != ann.end(); ++it) {
2056 _s->insert(*it);
2057 }
2058 }
2059
2060 Expression* get_annotation(const Annotation& ann, const std::string& str) {
2061 for (ExpressionSetIter i = ann.begin(); i != ann.end(); ++i) {
2062 Expression* e = *i;
2063 if ((e->isa<Id>() && e->cast<Id>()->str() == str) ||
2064 (e->isa<Call>() && e->cast<Call>()->id() == str)) {
2065 return e;
2066 }
2067 }
2068 return nullptr;
2069 }
2070 Expression* get_annotation(const Annotation& ann, const ASTString& str) {
2071 for (ExpressionSetIter i = ann.begin(); i != ann.end(); ++i) {
2072 Expression* e = *i;
2073 if ((e->isa<Id>() && e->cast<Id>()->str() == str) ||
2074 (e->isa<Call>() && e->cast<Call>()->id() == str)) {
2075 return e;
2076 }
2077 }
2078 return nullptr;
2079 }
2080 } // namespace MiniZinc
2081