The models, scripts, and results of the benchmarks performed for a Half Reification Journal paper
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
23namespace MiniZinc {
24
25Location::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
58Location::LocVec::LocVec(const ASTString& filename, IntVal combined) : ASTVec(2) {
59 *(_data + 0) = filename.aststr();
60 *(_data + 1) = IntLit::a(combined);
61}
62
63Location::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
74Location Location::nonalloc;
75
76Type Type::unboxedint = Type::parint();
77Type Type::unboxedfloat = Type::parfloat();
78
79Annotation Annotation::empty;
80
81std::string Location::toString() const {
82 std::ostringstream oss;
83 oss << filename() << ":" << firstLine() << "." << firstColumn();
84 return oss.str();
85}
86
87void Location::mark() const {
88 if (lv() != nullptr) {
89 lv()->mark();
90 }
91}
92
93Location Location::introduce() const {
94 Location l = *this;
95 if (l._locInfo.lv != nullptr) {
96 l._locInfo.t |= 1;
97 }
98 return l;
99}
100
101void Expression::addAnnotation(Expression* ann) {
102 if (!isUnboxedVal() && !Expression::equal(ann, constants().ann.empty_annotation)) {
103 _ann.add(ann);
104 }
105}
106void 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)
136void 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
239void IntLit::rehash() {
240 initHash();
241 std::hash<IntVal> h;
242 combineHash(h(_v));
243}
244
245void FloatLit::rehash() {
246 initHash();
247 std::hash<FloatVal> h;
248 combineHash(h(_v));
249}
250
251void 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
272void BoolLit::rehash() {
273 initHash();
274 std::hash<bool> h;
275 combineHash(h(_v));
276}
277
278void StringLit::rehash() {
279 initHash();
280 combineHash(_v.hash());
281}
282
283void 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
293int 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
300ASTString 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
309void TIId::rehash() {
310 initHash();
311 combineHash(_v.hash());
312}
313
314void AnonVar::rehash() { initHash(); }
315
316unsigned int ArrayLit::dims() const {
317 return _flag2 ? ((_dims.size() - 2 * _u.al->dims()) / 2)
318 : (_dims.size() == 0 ? 1 : _dims.size() / 2);
319}
320int 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}
327int 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}
334unsigned 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}
344void 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
365unsigned 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
382Expression* 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
392void 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
407ArrayLit::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
427void ArrayLit::compress(const std::vector<Expression*>& v, const std::vector<int>& dims) {
428 bool allFlat = true;
429 for (auto* e : v) {
430 if (!e->isa<IntLit>() && !e->isa<FloatLit>() && !e->isa<BoolLit>() &&
431 !(e->isa<SetLit>() && e->cast<SetLit>()->evaluated()) &&
432 !(e->isa<Id>() && e->cast<Id>()->decl() != nullptr &&
433 e->cast<Id>()->decl()->flat() == e->cast<Id>()->decl())) {
434 allFlat = false;
435 break;
436 }
437 }
438 if (allFlat) {
439 flat(true);
440 }
441 if (v.size() >= 4 && Expression::equal(v[0], v[1]) && Expression::equal(v[1], v[2]) &&
442 Expression::equal(v[2], v[3])) {
443 std::vector<Expression*> compress(v.size());
444 compress[0] = v[0];
445 int k = 4;
446 while (k < v.size() && Expression::equal(v[k], v[0])) {
447 k++;
448 }
449 int i = 1;
450 for (; k < v.size(); k++) {
451 compress[i++] = v[k];
452 }
453 compress.resize(i);
454 _u.v = ASTExprVec<Expression>(compress).vec();
455 _u.v->flag(true);
456 _dims = ASTIntVec(dims);
457 } else {
458 _u.v = ASTExprVec<Expression>(v).vec();
459 if (dims.size() != 2 || dims[0] != 1) {
460 // only allocate dims vector if it is not a 1d array indexed from 1
461 _dims = ASTIntVec(dims);
462 }
463 }
464}
465
466ArrayLit::ArrayLit(const Location& loc, const std::vector<Expression*>& v,
467 const std::vector<std::pair<int, int> >& dims)
468 : Expression(loc, E_ARRAYLIT, Type()) {
469 _flag1 = false;
470 _flag2 = false;
471 std::vector<int> d(dims.size() * 2);
472 for (auto i = static_cast<unsigned int>(dims.size()); (i--) != 0U;) {
473 d[i * 2] = dims[i].first;
474 d[i * 2 + 1] = dims[i].second;
475 }
476 compress(v, d);
477 rehash();
478}
479
480void ArrayLit::rehash() {
481 initHash();
482 std::hash<int> h;
483 for (int _dim : _dims) {
484 combineHash(h(_dim));
485 }
486 if (_flag2) {
487 combineHash(Expression::hash(_u.al));
488 } else {
489 for (unsigned int i = _u.v->size(); (i--) != 0U;) {
490 combineHash(h(static_cast<int>(i)));
491 combineHash(Expression::hash((*_u.v)[i]));
492 }
493 }
494}
495
496void ArrayAccess::rehash() {
497 initHash();
498 combineHash(Expression::hash(_v));
499 std::hash<unsigned int> h;
500 combineHash(h(_idx.size()));
501 for (unsigned int i = _idx.size(); (i--) != 0U;) {
502 combineHash(Expression::hash(_idx[i]));
503 }
504}
505
506Generator::Generator(const std::vector<ASTString>& v, Expression* in, Expression* where) {
507 std::vector<VarDecl*> vd;
508 Location loc = in == nullptr ? where->loc() : in->loc();
509 for (auto i : v) {
510 auto* nvd = new VarDecl(loc, new TypeInst(loc, Type::parint()), i);
511 nvd->toplevel(false);
512 vd.push_back(nvd);
513 }
514 _v = vd;
515 _in = in;
516 _where = where;
517}
518Generator::Generator(const std::vector<Id*>& v, Expression* in, Expression* where) {
519 std::vector<VarDecl*> vd;
520 for (auto* i : v) {
521 auto* nvd = new VarDecl(i->loc(), new TypeInst(i->loc(), Type::parint()), i->v());
522 nvd->toplevel(false);
523 vd.push_back(nvd);
524 }
525 _v = vd;
526 _in = in;
527 _where = where;
528}
529Generator::Generator(const std::vector<std::string>& v, Expression* in, Expression* where) {
530 std::vector<VarDecl*> vd;
531 Location loc = in == nullptr ? where->loc() : in->loc();
532 for (const auto& i : v) {
533 auto* nvd = new VarDecl(loc, new TypeInst(loc, Type::parint()), ASTString(i));
534 nvd->toplevel(false);
535 vd.push_back(nvd);
536 }
537 _v = vd;
538 _in = in;
539 _where = where;
540}
541Generator::Generator(const std::vector<VarDecl*>& v, Expression* in, Expression* where) {
542 _v = v;
543 _in = in;
544 _where = where;
545}
546Generator::Generator(int pos, Expression* where) {
547 std::vector<VarDecl*> vd;
548 std::ostringstream oss;
549 oss << "__dummy" << pos;
550 auto* nvd =
551 new VarDecl(Location().introduce(), new TypeInst(Location().introduce(), Type::parint()),
552 ASTString(oss.str()));
553 nvd->toplevel(false);
554 vd.push_back(nvd);
555 _v = vd;
556 _in = new ArrayLit(Location().introduce(), std::vector<Expression*>({IntLit::a(0)}));
557 _where = where;
558}
559
560bool Comprehension::set() const { return _flag1; }
561void Comprehension::rehash() {
562 initHash();
563 std::hash<unsigned int> h;
564 combineHash(h(static_cast<unsigned int>(set())));
565 combineHash(Expression::hash(_e));
566 combineHash(h(_gIndex.size()));
567 for (unsigned int i = _gIndex.size(); (i--) != 0U;) {
568 combineHash(h(_gIndex[i]));
569 }
570 combineHash(h(_g.size()));
571 for (unsigned int i = _g.size(); (i--) != 0U;) {
572 combineHash(Expression::hash(_g[i]));
573 }
574}
575
576unsigned int Comprehension::numberOfGenerators() const { return _gIndex.size() - 1; }
577Expression* Comprehension::in(unsigned int i) { return _g[_gIndex[i]]; }
578const Expression* Comprehension::in(unsigned int i) const { return _g[_gIndex[i]]; }
579const Expression* Comprehension::where(unsigned int i) const { return _g[_gIndex[i] + 1]; }
580Expression* Comprehension::where(unsigned int i) { return _g[_gIndex[i] + 1]; }
581
582unsigned int Comprehension::numberOfDecls(unsigned int i) const {
583 return _gIndex[i + 1] - _gIndex[i] - 2;
584}
585VarDecl* Comprehension::decl(unsigned int gen, unsigned int i) {
586 return _g[_gIndex[gen] + 2 + i]->cast<VarDecl>();
587}
588const VarDecl* Comprehension::decl(unsigned int gen, unsigned int i) const {
589 return _g[_gIndex[gen] + 2 + i]->cast<VarDecl>();
590}
591
592bool Comprehension::containsBoundVariable(Expression* e) {
593 std::unordered_set<VarDecl*> decls;
594 for (unsigned int i = 0; i < numberOfGenerators(); i++) {
595 for (unsigned int j = 0; j < numberOfDecls(i); j++) {
596 decls.insert(decl(i, j));
597 }
598 }
599 class FindVar : public EVisitor {
600 std::unordered_set<VarDecl*>& _decls;
601 bool _found;
602
603 public:
604 FindVar(std::unordered_set<VarDecl*>& decls) : _decls(decls), _found(false) {}
605 bool enter(Expression* /*e*/) const { return !_found; }
606 void vId(Id& ident) {
607 if (_decls.find(ident.decl()) != _decls.end()) {
608 _found = true;
609 }
610 }
611 bool found() const { return _found; }
612 } _fv(decls);
613 top_down(_fv, e);
614 return _fv.found();
615}
616
617void ITE::rehash() {
618 initHash();
619 std::hash<unsigned int> h;
620 combineHash(h(_eIfThen.size()));
621 for (unsigned int i = _eIfThen.size(); (i--) != 0U;) {
622 combineHash(Expression::hash(_eIfThen[i]));
623 }
624 combineHash(Expression::hash(elseExpr()));
625}
626
627BinOpType BinOp::op() const { return static_cast<BinOpType>(_secondaryId); }
628void BinOp::rehash() {
629 initHash();
630 std::hash<int> h;
631 combineHash(h(static_cast<int>(op())));
632 combineHash(Expression::hash(_e0));
633 combineHash(Expression::hash(_e1));
634}
635
636Call* BinOp::morph(const ASTString& ident, const std::vector<Expression*>& args) {
637 _id = Call::eid;
638 _flag1 = true;
639 Call* c = cast<Call>();
640 c->id(ident);
641 c->args(args);
642 return c;
643}
644
645namespace {
646
647class OpToString : public GCMarker {
648public:
649 Id* sBOT_PLUS; // NOLINT(readability-identifier-naming)
650 Id* sBOT_MINUS; // NOLINT(readability-identifier-naming)
651 Id* sBOT_MULT; // NOLINT(readability-identifier-naming)
652 Id* sBOT_DIV; // NOLINT(readability-identifier-naming)
653 Id* sBOT_IDIV; // NOLINT(readability-identifier-naming)
654 Id* sBOT_MOD; // NOLINT(readability-identifier-naming)
655 Id* sBOT_POW; // NOLINT(readability-identifier-naming)
656 Id* sBOT_LE; // NOLINT(readability-identifier-naming)
657 Id* sBOT_LQ; // NOLINT(readability-identifier-naming)
658 Id* sBOT_GR; // NOLINT(readability-identifier-naming)
659 Id* sBOT_GQ; // NOLINT(readability-identifier-naming)
660 Id* sBOT_EQ; // NOLINT(readability-identifier-naming)
661 Id* sBOT_NQ; // NOLINT(readability-identifier-naming)
662 Id* sBOT_IN; // NOLINT(readability-identifier-naming)
663 Id* sBOT_SUBSET; // NOLINT(readability-identifier-naming)
664 Id* sBOT_SUPERSET; // NOLINT(readability-identifier-naming)
665 Id* sBOT_UNION; // NOLINT(readability-identifier-naming)
666 Id* sBOT_DIFF; // NOLINT(readability-identifier-naming)
667 Id* sBOT_SYMDIFF; // NOLINT(readability-identifier-naming)
668 Id* sBOT_INTERSECT; // NOLINT(readability-identifier-naming)
669 Id* sBOT_PLUSPLUS; // NOLINT(readability-identifier-naming)
670 Id* sBOT_EQUIV; // NOLINT(readability-identifier-naming)
671 Id* sBOT_IMPL; // NOLINT(readability-identifier-naming)
672 Id* sBOT_RIMPL; // NOLINT(readability-identifier-naming)
673 Id* sBOT_OR; // NOLINT(readability-identifier-naming)
674 Id* sBOT_AND; // NOLINT(readability-identifier-naming)
675 Id* sBOT_XOR; // NOLINT(readability-identifier-naming)
676 Id* sBOT_DOTDOT; // NOLINT(readability-identifier-naming)
677 Id* sBOT_NOT; // NOLINT(readability-identifier-naming)
678
679 OpToString() {
680 GCLock lock;
681
682 sBOT_PLUS = new Id(Location(), "'+'", nullptr);
683 sBOT_MINUS = new Id(Location(), "'-'", nullptr);
684 sBOT_MULT = new Id(Location(), "'*'", nullptr);
685 sBOT_DIV = new Id(Location(), "'/'", nullptr);
686 sBOT_IDIV = new Id(Location(), "'div'", nullptr);
687 sBOT_MOD = new Id(Location(), "'mod'", nullptr);
688 sBOT_POW = new Id(Location(), "'^'", nullptr);
689 sBOT_LE = new Id(Location(), "'<'", nullptr);
690 sBOT_LQ = new Id(Location(), "'<='", nullptr);
691 sBOT_GR = new Id(Location(), "'>'", nullptr);
692 sBOT_GQ = new Id(Location(), "'>='", nullptr);
693 sBOT_EQ = new Id(Location(), "'='", nullptr);
694 sBOT_NQ = new Id(Location(), "'!='", nullptr);
695 sBOT_IN = new Id(Location(), "'in'", nullptr);
696 sBOT_SUBSET = new Id(Location(), "'subset'", nullptr);
697 sBOT_SUPERSET = new Id(Location(), "'superset'", nullptr);
698 sBOT_UNION = new Id(Location(), "'union'", nullptr);
699 sBOT_DIFF = new Id(Location(), "'diff'", nullptr);
700 sBOT_SYMDIFF = new Id(Location(), "'symdiff'", nullptr);
701 sBOT_INTERSECT = new Id(Location(), "'intersect'", nullptr);
702 sBOT_PLUSPLUS = new Id(Location(), "'++'", nullptr);
703 sBOT_EQUIV = new Id(Location(), "'<->'", nullptr);
704 sBOT_IMPL = new Id(Location(), "'->'", nullptr);
705 sBOT_RIMPL = new Id(Location(), "'<-'", nullptr);
706 sBOT_OR = new Id(Location(), "'\\/'", nullptr);
707 sBOT_AND = new Id(Location(), "'/\\'", nullptr);
708 sBOT_XOR = new Id(Location(), "'xor'", nullptr);
709 sBOT_DOTDOT = new Id(Location(), "'..'", nullptr);
710 sBOT_NOT = new Id(Location(), "'not'", nullptr);
711 }
712
713 static OpToString& o() {
714 static OpToString _o;
715 return _o;
716 }
717
718 void mark(MINIZINC_GC_STAT_ARGS) override {
719 Expression::mark(sBOT_PLUS);
720 Expression::mark(sBOT_MINUS);
721 Expression::mark(sBOT_MULT);
722 Expression::mark(sBOT_DIV);
723 Expression::mark(sBOT_IDIV);
724 Expression::mark(sBOT_MOD);
725 Expression::mark(sBOT_POW);
726 Expression::mark(sBOT_LE);
727 Expression::mark(sBOT_LQ);
728 Expression::mark(sBOT_GR);
729 Expression::mark(sBOT_GQ);
730 Expression::mark(sBOT_EQ);
731 Expression::mark(sBOT_NQ);
732 Expression::mark(sBOT_IN);
733 Expression::mark(sBOT_SUBSET);
734 Expression::mark(sBOT_SUPERSET);
735 Expression::mark(sBOT_UNION);
736 Expression::mark(sBOT_DIFF);
737 Expression::mark(sBOT_SYMDIFF);
738 Expression::mark(sBOT_INTERSECT);
739 Expression::mark(sBOT_PLUSPLUS);
740 Expression::mark(sBOT_EQUIV);
741 Expression::mark(sBOT_IMPL);
742 Expression::mark(sBOT_RIMPL);
743 Expression::mark(sBOT_OR);
744 Expression::mark(sBOT_AND);
745 Expression::mark(sBOT_XOR);
746 Expression::mark(sBOT_DOTDOT);
747 Expression::mark(sBOT_NOT);
748 }
749};
750} // namespace
751
752ASTString BinOp::opToString() const {
753 switch (op()) {
754 case BOT_PLUS:
755 return OpToString::o().sBOT_PLUS->v();
756 case BOT_MINUS:
757 return OpToString::o().sBOT_MINUS->v();
758 case BOT_MULT:
759 return OpToString::o().sBOT_MULT->v();
760 case BOT_DIV:
761 return OpToString::o().sBOT_DIV->v();
762 case BOT_IDIV:
763 return OpToString::o().sBOT_IDIV->v();
764 case BOT_MOD:
765 return OpToString::o().sBOT_MOD->v();
766 case BOT_POW:
767 return OpToString::o().sBOT_POW->v();
768 case BOT_LE:
769 return OpToString::o().sBOT_LE->v();
770 case BOT_LQ:
771 return OpToString::o().sBOT_LQ->v();
772 case BOT_GR:
773 return OpToString::o().sBOT_GR->v();
774 case BOT_GQ:
775 return OpToString::o().sBOT_GQ->v();
776 case BOT_EQ:
777 return OpToString::o().sBOT_EQ->v();
778 case BOT_NQ:
779 return OpToString::o().sBOT_NQ->v();
780 case BOT_IN:
781 return OpToString::o().sBOT_IN->v();
782 case BOT_SUBSET:
783 return OpToString::o().sBOT_SUBSET->v();
784 case BOT_SUPERSET:
785 return OpToString::o().sBOT_SUPERSET->v();
786 case BOT_UNION:
787 return OpToString::o().sBOT_UNION->v();
788 case BOT_DIFF:
789 return OpToString::o().sBOT_DIFF->v();
790 case BOT_SYMDIFF:
791 return OpToString::o().sBOT_SYMDIFF->v();
792 case BOT_INTERSECT:
793 return OpToString::o().sBOT_INTERSECT->v();
794 case BOT_PLUSPLUS:
795 return OpToString::o().sBOT_PLUSPLUS->v();
796 case BOT_EQUIV:
797 return OpToString::o().sBOT_EQUIV->v();
798 case BOT_IMPL:
799 return OpToString::o().sBOT_IMPL->v();
800 case BOT_RIMPL:
801 return OpToString::o().sBOT_RIMPL->v();
802 case BOT_OR:
803 return OpToString::o().sBOT_OR->v();
804 case BOT_AND:
805 return OpToString::o().sBOT_AND->v();
806 case BOT_XOR:
807 return OpToString::o().sBOT_XOR->v();
808 case BOT_DOTDOT:
809 return OpToString::o().sBOT_DOTDOT->v();
810 default:
811 assert(false);
812 return ASTString("");
813 }
814}
815
816UnOpType UnOp::op() const { return static_cast<UnOpType>(_secondaryId); }
817void UnOp::rehash() {
818 initHash();
819 std::hash<int> h;
820 combineHash(h(static_cast<int>(_secondaryId)));
821 combineHash(Expression::hash(_e0));
822}
823
824ASTString UnOp::opToString() const {
825 switch (op()) {
826 case UOT_PLUS:
827 return OpToString::o().sBOT_PLUS->v();
828 case UOT_MINUS:
829 return OpToString::o().sBOT_MINUS->v();
830 case UOT_NOT:
831 return OpToString::o().sBOT_NOT->v();
832 default:
833 assert(false);
834 return ASTString("");
835 }
836}
837
838void Call::rehash() {
839 initHash();
840 combineHash(id().hash());
841 std::hash<FunctionI*> hf;
842 combineHash(hf(decl()));
843 std::hash<unsigned int> hu;
844 combineHash(hu(argCount()));
845 for (unsigned int i = 0; i < argCount(); i++) {
846 combineHash(Expression::hash(arg(i)));
847 }
848}
849
850void VarDecl::trail() {
851 GC::trail(&_e, e());
852 if (_ti->ranges().size() > 0) {
853 GC::trail(reinterpret_cast<Expression**>(&_ti), _ti);
854 }
855}
856
857void VarDecl::rehash() {
858 initHash();
859 combineHash(Expression::hash(_ti));
860 combineHash(_id->hash());
861 combineHash(Expression::hash(_e));
862}
863
864void Let::rehash() {
865 initHash();
866 combineHash(Expression::hash(_in));
867 std::hash<unsigned int> h;
868 combineHash(h(_let.size()));
869 for (unsigned int i = _let.size(); (i--) != 0U;) {
870 combineHash(Expression::hash(_let[i]));
871 }
872}
873
874Let::Let(const Location& loc, const std::vector<Expression*>& let, Expression* in)
875 : Expression(loc, E_LET, Type()) {
876 _let = ASTExprVec<Expression>(let);
877 std::vector<Expression*> vde;
878 for (auto* i : let) {
879 if (auto* vd = Expression::dynamicCast<VarDecl>(i)) {
880 vde.push_back(vd->e());
881 for (unsigned int i = 0; i < vd->ti()->ranges().size(); i++) {
882 vde.push_back(vd->ti()->ranges()[i]->domain());
883 }
884 }
885 }
886 _letOrig = ASTExprVec<Expression>(vde);
887 _in = in;
888 rehash();
889}
890
891void Let::pushbindings() {
892 GC::mark();
893 for (unsigned int i = 0, j = 0; i < _let.size(); i++) {
894 if (auto* vd = _let[i]->dynamicCast<VarDecl>()) {
895 vd->trail();
896 vd->e(_letOrig[j++]);
897 for (unsigned int k = 0; k < vd->ti()->ranges().size(); k++) {
898 vd->ti()->ranges()[k]->domain(_letOrig[j++]);
899 }
900 }
901 }
902}
903// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
904void Let::popbindings() { GC::untrail(); }
905
906void TypeInst::rehash() {
907 initHash();
908 std::hash<unsigned int> h;
909 unsigned int rsize = _ranges.size();
910 combineHash(h(rsize));
911 for (unsigned int i = rsize; (i--) != 0U;) {
912 combineHash(Expression::hash(_ranges[i]));
913 }
914 combineHash(Expression::hash(domain()));
915}
916
917void TypeInst::setRanges(const std::vector<TypeInst*>& ranges) {
918 _ranges = ASTExprVec<TypeInst>(ranges);
919 if (ranges.size() == 1 && (ranges[0] != nullptr) && ranges[0]->isa<TypeInst>() &&
920 (ranges[0]->cast<TypeInst>()->domain() != nullptr) &&
921 ranges[0]->cast<TypeInst>()->domain()->isa<TIId>() &&
922 !ranges[0]->cast<TypeInst>()->domain()->cast<TIId>()->v().beginsWith("$")) {
923 _type.dim(-1);
924 } else {
925 _type.dim(static_cast<int>(ranges.size()));
926 }
927 rehash();
928}
929
930bool TypeInst::hasTiVariable() const {
931 if ((domain() != nullptr) && domain()->isa<TIId>()) {
932 return true;
933 }
934 for (unsigned int i = _ranges.size(); (i--) != 0U;) {
935 if (_ranges[i]->isa<TIId>()) {
936 return true;
937 }
938 }
939 return false;
940}
941
942namespace {
943Type get_type(Expression* e) { return e->type(); }
944Type get_type(const Type& t) { return t; }
945const Location& get_loc(Expression* e, FunctionI* /*fi*/) { return e->loc(); }
946const Location& get_loc(const Type& /*t*/, FunctionI* fi) { return fi->loc(); }
947
948bool isa_tiid(Expression* e) {
949 if (TIId* t = Expression::dynamicCast<TIId>(e)) {
950 return !t->v().beginsWith("$");
951 }
952 return false;
953}
954bool isa_enum_tiid(Expression* e) {
955 if (TIId* t = Expression::dynamicCast<TIId>(e)) {
956 return t->v().beginsWith("$");
957 }
958 return false;
959}
960
961template <class T>
962Type return_type(EnvI& env, FunctionI* fi, const std::vector<T>& ta, bool strictEnum) {
963 if (fi->id() == constants().varRedef->id()) {
964 return Type::varbool();
965 }
966 Type ret = fi->ti()->type();
967 ASTString dh;
968 if (fi->ti()->domain() && fi->ti()->domain()->isa<TIId>()) {
969 dh = fi->ti()->domain()->cast<TIId>()->v();
970 }
971 ASTString rh;
972 if (fi->ti()->ranges().size() == 1 && isa_tiid(fi->ti()->ranges()[0]->domain())) {
973 rh = fi->ti()->ranges()[0]->domain()->cast<TIId>()->v();
974 }
975
976 ASTStringMap<Type> tmap;
977 for (unsigned int i = 0; i < ta.size(); i++) {
978 TypeInst* tii = fi->param(i)->ti();
979 if (tii->domain() && tii->domain()->isa<TIId>()) {
980 ASTString tiid = tii->domain()->cast<TIId>()->v();
981 Type tiit = get_type(ta[i]);
982 if (tiit.enumId() != 0 && tiit.dim() > 0) {
983 const std::vector<unsigned int>& enumIds = env.getArrayEnum(tiit.enumId());
984 tiit.enumId(enumIds[enumIds.size() - 1]);
985 }
986 tiit.dim(0);
987 if (tii->type().st() == Type::ST_SET) {
988 tiit.st(Type::ST_PLAIN);
989 }
990 if (isa_enum_tiid(tii->domain())) {
991 tiit.st(Type::ST_SET);
992 }
993 auto it = tmap.find(tiid);
994 if (it == tmap.end()) {
995 tmap.insert(std::pair<ASTString, Type>(tiid, tiit));
996 } else {
997 if (it->second.dim() > 0) {
998 std::ostringstream ss;
999 ss << "type-inst variable $" << tiid << " used in both array and non-array position";
1000 throw TypeError(env, get_loc(ta[i], fi), ss.str());
1001 }
1002 Type tiit_par = tiit;
1003 tiit_par.ti(Type::TI_PAR);
1004 tiit_par.ot(Type::OT_PRESENT);
1005 Type its_par = it->second;
1006 its_par.ti(Type::TI_PAR);
1007 its_par.ot(Type::OT_PRESENT);
1008 if (tiit_par.bt() == Type::BT_TOP || tiit_par.bt() == Type::BT_BOT) {
1009 tiit_par.bt(its_par.bt());
1010 }
1011 if (its_par.bt() == Type::BT_TOP || its_par.bt() == Type::BT_BOT) {
1012 its_par.bt(tiit_par.bt());
1013 }
1014 if (env.isSubtype(tiit_par, its_par, strictEnum)) {
1015 if (it->second.bt() == Type::BT_TOP) {
1016 it->second.bt(tiit.bt());
1017 }
1018 } else if (env.isSubtype(its_par, tiit_par, strictEnum)) {
1019 it->second = tiit_par;
1020 } else {
1021 std::ostringstream ss;
1022 ss << "type-inst variable $" << tiid << " instantiated with different types ("
1023 << tiit.toString(env) << " vs " << it->second.toString(env) << ")";
1024 throw TypeError(env, get_loc(ta[i], fi), ss.str());
1025 }
1026 }
1027 }
1028 if (tii->ranges().size() == 1 && isa_tiid(tii->ranges()[0]->domain())) {
1029 ASTString tiid = tii->ranges()[0]->domain()->cast<TIId>()->v();
1030 Type orig_tiit = get_type(ta[i]);
1031 if (orig_tiit.dim() == 0) {
1032 std::ostringstream ss;
1033 ss << "type-inst variable $" << tiid << " must be an array index";
1034 throw TypeError(env, get_loc(ta[i], fi), ss.str());
1035 }
1036 Type tiit = Type::top(orig_tiit.dim());
1037 if (orig_tiit.enumId() != 0) {
1038 std::vector<unsigned int> enumIds(tiit.dim() + 1);
1039 const std::vector<unsigned int>& orig_enumIds = env.getArrayEnum(orig_tiit.enumId());
1040 for (unsigned int i = 0; i < enumIds.size() - 1; i++) {
1041 enumIds[i] = orig_enumIds[i];
1042 }
1043 enumIds[enumIds.size() - 1] = 0;
1044 tiit.enumId(env.registerArrayEnum(enumIds));
1045 }
1046 auto it = tmap.find(tiid);
1047 if (it == tmap.end()) {
1048 tmap.insert(std::pair<ASTString, Type>(tiid, tiit));
1049 } else {
1050 if (it->second.dim() == 0) {
1051 std::ostringstream ss;
1052 ss << "type-inst variable $" << tiid << " used in both array and non-array position";
1053 throw TypeError(env, get_loc(ta[i], fi), ss.str());
1054 }
1055 if (it->second != tiit) {
1056 std::ostringstream ss;
1057 ss << "type-inst variable $" << tiid << " instantiated with different types ("
1058 << tiit.toString(env) + " vs " << it->second.toString(env) << ")";
1059 throw TypeError(env, get_loc(ta[i], fi), ss.str());
1060 }
1061 }
1062 } else if (tii->ranges().size() > 0) {
1063 for (unsigned int j = 0; j < tii->ranges().size(); j++) {
1064 if (isa_enum_tiid(tii->ranges()[j]->domain())) {
1065 ASTString enumTIId = tii->ranges()[j]->domain()->cast<TIId>()->v();
1066 Type tiit = get_type(ta[i]);
1067 Type enumIdT;
1068 if (tiit.enumId() != 0) {
1069 unsigned int enumId = env.getArrayEnum(tiit.enumId())[j];
1070 enumIdT = Type::parsetenum(enumId);
1071 } else {
1072 enumIdT = Type::parsetint();
1073 }
1074 auto it = tmap.find(enumTIId);
1075 // TODO: this may clash if the same enum TIId is used for different types
1076 // but the same enum
1077 if (it == tmap.end()) {
1078 tmap.insert(std::pair<ASTString, Type>(enumTIId, enumIdT));
1079 } else if (strictEnum && it->second.enumId() != enumIdT.enumId()) {
1080 std::ostringstream ss;
1081 ss << "type-inst variable $" << enumTIId << " used for different enum types";
1082 throw TypeError(env, get_loc(ta[i], fi), ss.str());
1083 }
1084 }
1085 }
1086 }
1087 }
1088 if (dh.size() != 0) {
1089 auto it = tmap.find(dh);
1090 if (it == tmap.end()) {
1091 std::ostringstream ss;
1092 ss << "type-inst variable $" << dh << " used but not defined";
1093 throw TypeError(env, fi->loc(), ss.str());
1094 }
1095 if (dh.beginsWith("$")) {
1096 // this is an enum
1097 ret.bt(Type::BT_INT);
1098 } else {
1099 ret.bt(it->second.bt());
1100 if (ret.st() == Type::ST_PLAIN) {
1101 ret.st(it->second.st());
1102 }
1103 }
1104 if (fi->ti()->ranges().size() > 0 && it->second.enumId() != 0) {
1105 std::vector<unsigned int> enumIds(fi->ti()->ranges().size() + 1);
1106 for (unsigned int i = 0; i < fi->ti()->ranges().size(); i++) {
1107 enumIds[i] = 0;
1108 }
1109 enumIds[enumIds.size() - 1] = it->second.enumId();
1110 ret.enumId(env.registerArrayEnum(enumIds));
1111 } else {
1112 ret.enumId(it->second.enumId());
1113 }
1114 }
1115 if (rh.size() != 0) {
1116 auto it = tmap.find(rh);
1117 if (it == tmap.end()) {
1118 std::ostringstream ss;
1119 ss << "type-inst variable $" << rh << " used but not defined";
1120 throw TypeError(env, fi->loc(), ss.str());
1121 }
1122 ret.dim(it->second.dim());
1123 if (it->second.enumId() != 0) {
1124 std::vector<unsigned int> enumIds(it->second.dim() + 1);
1125 const std::vector<unsigned int>& orig_enumIds = env.getArrayEnum(it->second.enumId());
1126 for (unsigned int i = 0; i < enumIds.size() - 1; i++) {
1127 enumIds[i] = orig_enumIds[i];
1128 }
1129 enumIds[enumIds.size() - 1] =
1130 ret.enumId() == 0 ? 0 : env.getArrayEnum(ret.enumId())[enumIds.size() - 1];
1131 ret.enumId(env.registerArrayEnum(enumIds));
1132 }
1133
1134 } else if (fi->ti()->ranges().size() > 0) {
1135 std::vector<unsigned int> enumIds(fi->ti()->ranges().size() + 1);
1136 bool hadRealEnum = false;
1137 if (ret.enumId() == 0) {
1138 enumIds[enumIds.size() - 1] = 0;
1139 } else {
1140 enumIds[enumIds.size() - 1] = env.getArrayEnum(ret.enumId())[enumIds.size() - 1];
1141 hadRealEnum = true;
1142 }
1143
1144 for (unsigned int i = 0; i < fi->ti()->ranges().size(); i++) {
1145 if (isa_enum_tiid(fi->ti()->ranges()[i]->domain())) {
1146 ASTString enumTIId = fi->ti()->ranges()[i]->domain()->cast<TIId>()->v();
1147 auto it = tmap.find(enumTIId);
1148 if (it == tmap.end()) {
1149 std::ostringstream ss;
1150 ss << "type-inst variable $" << enumTIId << " used but not defined";
1151 throw TypeError(env, fi->loc(), ss.str());
1152 }
1153 enumIds[i] = it->second.enumId();
1154 hadRealEnum |= (enumIds[i] != 0);
1155 } else {
1156 enumIds[i] = 0;
1157 }
1158 }
1159 if (hadRealEnum) {
1160 ret.enumId(env.registerArrayEnum(enumIds));
1161 }
1162 }
1163 return ret;
1164}
1165} // namespace
1166
1167#if defined(MINIZINC_GC_STATS)
1168void Item::mark(Item* item, MINIZINC_GC_STAT_ARGS) {
1169#else
1170void Item::mark(Item* item) {
1171#endif
1172 if (item->hasMark()) {
1173 return;
1174 }
1175 item->_gcMark = 1;
1176 item->loc().mark();
1177 switch (item->iid()) {
1178 case Item::II_INC:
1179 item->cast<IncludeI>()->f().mark();
1180 break;
1181 case Item::II_VD:
1182 Expression::mark(item->cast<VarDeclI>()->e());
1183#if defined(MINIZINC_GC_STATS)
1184 gc_stats[item->cast<VarDeclI>()->e()->Expression::eid()].inmodel++;
1185#endif
1186 break;
1187 case Item::II_ASN:
1188 item->cast<AssignI>()->id().mark();
1189 Expression::mark(item->cast<AssignI>()->e());
1190 Expression::mark(item->cast<AssignI>()->decl());
1191 break;
1192 case Item::II_CON:
1193 Expression::mark(item->cast<ConstraintI>()->e());
1194#if defined(MINIZINC_GC_STATS)
1195 gc_stats[item->cast<ConstraintI>()->e()->Expression::eid()].inmodel++;
1196#endif
1197 break;
1198 case Item::II_SOL: {
1199 auto* si = item->cast<SolveI>();
1200 for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) {
1201 Expression::mark(*it);
1202 }
1203 Expression::mark(item->cast<SolveI>()->e());
1204 } break;
1205 case Item::II_OUT: {
1206 auto* oi = item->cast<OutputI>();
1207 Expression::mark(oi->e());
1208 for (ExpressionSetIter it = oi->ann().begin(); it != oi->ann().end(); ++it) {
1209 Expression::mark(*it);
1210 }
1211 } break;
1212 case Item::II_FUN: {
1213 auto* fi = item->cast<FunctionI>();
1214 fi->id().mark();
1215 Expression::mark(fi->ti());
1216 for (ExpressionSetIter it = fi->ann().begin(); it != fi->ann().end(); ++it) {
1217 Expression::mark(*it);
1218 }
1219 Expression::mark(fi->e());
1220 fi->markParams();
1221 } break;
1222 }
1223}
1224
1225Type FunctionI::rtype(EnvI& env, const std::vector<Expression*>& ta, bool strictEnums) {
1226 return return_type(env, this, ta, strictEnums);
1227}
1228
1229Type FunctionI::rtype(EnvI& env, const std::vector<Type>& ta, bool strictEnums) {
1230 return return_type(env, this, ta, strictEnums);
1231}
1232
1233Type FunctionI::argtype(EnvI& env, const std::vector<Expression*>& ta, unsigned int n) const {
1234 TypeInst* tii = param(n)->ti();
1235 if ((tii->domain() != nullptr) && tii->domain()->isa<TIId>()) {
1236 Type ty = ta[n]->type();
1237 ty.st(tii->type().st());
1238 ty.dim(tii->type().dim());
1239 ASTString tv = tii->domain()->cast<TIId>()->v();
1240 for (unsigned int i = 0; i < paramCount(); i++) {
1241 if ((param(i)->ti()->domain() != nullptr) && param(i)->ti()->domain()->isa<TIId>() &&
1242 param(i)->ti()->domain()->cast<TIId>()->v() == tv) {
1243 Type toCheck = ta[i]->type();
1244 toCheck.st(tii->type().st());
1245 toCheck.dim(tii->type().dim());
1246 if (toCheck != ty) {
1247 if (env.isSubtype(ty, toCheck, true)) {
1248 ty = toCheck;
1249 } else {
1250 Type ty_par = ty;
1251 ty_par.ti(Type::TI_PAR);
1252 Type toCheck_par = toCheck;
1253 toCheck_par.ti(Type::TI_PAR);
1254 if (env.isSubtype(ty_par, toCheck_par, true)) {
1255 ty.bt(toCheck.bt());
1256 }
1257 }
1258 }
1259 }
1260 }
1261 return ty;
1262 }
1263 return tii->type();
1264}
1265
1266bool Expression::equalInternal(const Expression* e0, const Expression* e1) {
1267 switch (e0->eid()) {
1268 case Expression::E_INTLIT:
1269 return e0->cast<IntLit>()->v() == e1->cast<IntLit>()->v();
1270 case Expression::E_FLOATLIT:
1271 return e0->cast<FloatLit>()->v() == e1->cast<FloatLit>()->v();
1272 case Expression::E_SETLIT: {
1273 const auto* s0 = e0->cast<SetLit>();
1274 const auto* s1 = e1->cast<SetLit>();
1275 if (s0->isv() != nullptr) {
1276 if (s1->isv() != nullptr) {
1277 IntSetRanges r0(s0->isv());
1278 IntSetRanges r1(s1->isv());
1279 return Ranges::equal(r0, r1);
1280 }
1281 return false;
1282 }
1283 if (s0->fsv() != nullptr) {
1284 if (s1->fsv() != nullptr) {
1285 FloatSetRanges r0(s0->fsv());
1286 FloatSetRanges r1(s1->fsv());
1287 return Ranges::equal(r0, r1);
1288 }
1289 return false;
1290 }
1291 if ((s1->isv() != nullptr) || (s1->fsv() != nullptr)) {
1292 return false;
1293 }
1294 if (s0->v().size() != s1->v().size()) {
1295 return false;
1296 }
1297 for (unsigned int i = 0; i < s0->v().size(); i++) {
1298 if (!Expression::equal(s0->v()[i], s1->v()[i])) {
1299 return false;
1300 }
1301 }
1302 return true;
1303 }
1304 case Expression::E_BOOLLIT:
1305 return e0->cast<BoolLit>()->v() == e1->cast<BoolLit>()->v();
1306 case Expression::E_STRINGLIT:
1307 return e0->cast<StringLit>()->v() == e1->cast<StringLit>()->v();
1308 case Expression::E_ID: {
1309 const Id* id0 = e0->cast<Id>();
1310 const Id* id1 = e1->cast<Id>();
1311 if (id0->decl() == nullptr || id1->decl() == nullptr) {
1312 return id0->v() == id1->v() && id0->idn() == id1->idn();
1313 }
1314 return id0->decl() == id1->decl() ||
1315 (id0->decl()->flat() != nullptr && id0->decl()->flat() == id1->decl()->flat());
1316 }
1317 case Expression::E_ANON:
1318 return false;
1319 case Expression::E_ARRAYLIT: {
1320 const auto* a0 = e0->cast<ArrayLit>();
1321 const auto* a1 = e1->cast<ArrayLit>();
1322 if (a0->size() != a1->size()) {
1323 return false;
1324 }
1325 if (a0->_dims.size() != a1->_dims.size()) {
1326 return false;
1327 }
1328 for (unsigned int i = 0; i < a0->_dims.size(); i++) {
1329 if (a0->_dims[i] != a1->_dims[i]) {
1330 return false;
1331 }
1332 }
1333 for (unsigned int i = 0; i < a0->size(); i++) {
1334 if (!Expression::equal((*a0)[i], (*a1)[i])) {
1335 return false;
1336 }
1337 }
1338 return true;
1339 }
1340 case Expression::E_ARRAYACCESS: {
1341 const auto* a0 = e0->cast<ArrayAccess>();
1342 const auto* a1 = e1->cast<ArrayAccess>();
1343 if (!Expression::equal(a0->v(), a1->v())) {
1344 return false;
1345 }
1346 if (a0->idx().size() != a1->idx().size()) {
1347 return false;
1348 }
1349 for (unsigned int i = 0; i < a0->idx().size(); i++) {
1350 if (!Expression::equal(a0->idx()[i], a1->idx()[i])) {
1351 return false;
1352 }
1353 }
1354 return true;
1355 }
1356 case Expression::E_COMP: {
1357 const auto* c0 = e0->cast<Comprehension>();
1358 const auto* c1 = e1->cast<Comprehension>();
1359 if (c0->set() != c1->set()) {
1360 return false;
1361 }
1362 if (!Expression::equal(c0->_e, c1->_e)) {
1363 return false;
1364 }
1365 if (c0->_g.size() != c1->_g.size()) {
1366 return false;
1367 }
1368 for (unsigned int i = 0; i < c0->_g.size(); i++) {
1369 if (!Expression::equal(c0->_g[i], c1->_g[i])) {
1370 return false;
1371 }
1372 }
1373 for (unsigned int i = 0; i < c0->_gIndex.size(); i++) {
1374 if (c0->_gIndex[i] != c1->_gIndex[i]) {
1375 return false;
1376 }
1377 }
1378 return true;
1379 }
1380 case Expression::E_ITE: {
1381 const ITE* i0 = e0->cast<ITE>();
1382 const ITE* i1 = e1->cast<ITE>();
1383 if (i0->_eIfThen.size() != i1->_eIfThen.size()) {
1384 return false;
1385 }
1386 for (unsigned int i = i0->_eIfThen.size(); (i--) != 0U;) {
1387 if (!Expression::equal(i0->_eIfThen[i], i1->_eIfThen[i])) {
1388 return false;
1389 }
1390 }
1391 return Expression::equal(i0->elseExpr(), i1->elseExpr());
1392 }
1393 case Expression::E_BINOP: {
1394 const auto* b0 = e0->cast<BinOp>();
1395 const auto* b1 = e1->cast<BinOp>();
1396 if (b0->op() != b1->op()) {
1397 return false;
1398 }
1399 if (!Expression::equal(b0->lhs(), b1->lhs())) {
1400 return false;
1401 }
1402 if (!Expression::equal(b0->rhs(), b1->rhs())) {
1403 return false;
1404 }
1405 return true;
1406 }
1407 case Expression::E_UNOP: {
1408 const UnOp* b0 = e0->cast<UnOp>();
1409 const UnOp* b1 = e1->cast<UnOp>();
1410 if (b0->op() != b1->op()) {
1411 return false;
1412 }
1413 if (!Expression::equal(b0->e(), b1->e())) {
1414 return false;
1415 }
1416 return true;
1417 }
1418 case Expression::E_CALL: {
1419 const Call* c0 = e0->cast<Call>();
1420 const Call* c1 = e1->cast<Call>();
1421 if (c0->id() != c1->id()) {
1422 return false;
1423 }
1424 if (c0->decl() != c1->decl()) {
1425 return false;
1426 }
1427 if (c0->argCount() != c1->argCount()) {
1428 return false;
1429 }
1430 for (unsigned int i = 0; i < c0->argCount(); i++) {
1431 if (!Expression::equal(c0->arg(i), c1->arg(i))) {
1432 return false;
1433 }
1434 }
1435 return true;
1436 }
1437 case Expression::E_VARDECL: {
1438 const auto* v0 = e0->cast<VarDecl>();
1439 const auto* v1 = e1->cast<VarDecl>();
1440 if (!Expression::equal(v0->ti(), v1->ti())) {
1441 return false;
1442 }
1443 if (!Expression::equal(v0->id(), v1->id())) {
1444 return false;
1445 }
1446 if (!Expression::equal(v0->e(), v1->e())) {
1447 return false;
1448 }
1449 return true;
1450 }
1451 case Expression::E_LET: {
1452 const Let* l0 = e0->cast<Let>();
1453 const Let* l1 = e1->cast<Let>();
1454 if (!Expression::equal(l0->in(), l1->in())) {
1455 return false;
1456 }
1457 if (l0->let().size() != l1->let().size()) {
1458 return false;
1459 }
1460 for (unsigned int i = l0->let().size(); (i--) != 0U;) {
1461 if (!Expression::equal(l0->let()[i], l1->let()[i])) {
1462 return false;
1463 }
1464 }
1465 return true;
1466 }
1467 case Expression::E_TI: {
1468 const auto* t0 = e0->cast<TypeInst>();
1469 const auto* t1 = e1->cast<TypeInst>();
1470 if (t0->ranges().size() != t1->ranges().size()) {
1471 return false;
1472 }
1473 for (unsigned int i = t0->ranges().size(); (i--) != 0U;) {
1474 if (!Expression::equal(t0->ranges()[i], t1->ranges()[i])) {
1475 return false;
1476 }
1477 }
1478 return Expression::equal(t0->domain(), t1->domain());
1479 }
1480 case Expression::E_TIID:
1481 return false;
1482 default:
1483 assert(false);
1484 return false;
1485 }
1486}
1487
1488Constants::Constants() {
1489 GCLock lock;
1490 auto* ti = new TypeInst(Location(), Type::parbool());
1491 literalTrue = new BoolLit(Location(), true);
1492 varTrue = new VarDecl(Location(), ti, "_bool_true", literalTrue);
1493 literalFalse = new BoolLit(Location(), false);
1494 varFalse = new VarDecl(Location(), ti, "_bool_false", literalFalse);
1495 varIgnore = new VarDecl(Location(), ti, "_bool_ignore");
1496 absent = new Id(Location(), "_absent", nullptr);
1497 varRedef = new FunctionI(Location(), ASTString("__internal_varRedef"),
1498 new TypeInst(Location(), Type::varbool()), std::vector<VarDecl*>());
1499 Type absent_t;
1500 absent_t.bt(Type::BT_BOT);
1501 absent_t.dim(0);
1502 absent_t.st(Type::ST_PLAIN);
1503 absent_t.ot(Type::OT_OPTIONAL);
1504 absent->type(absent_t);
1505
1506 IntSetVal* isv_infty = IntSetVal::a(-IntVal::infinity(), IntVal::infinity());
1507 infinity = new SetLit(Location(), isv_infty);
1508
1509 ids.forall = addString("forall");
1510 ids.forallReif = addString("forallReif");
1511 ids.exists = addString("exists");
1512 ids.clause = addString("clause");
1513 ids.bool2int = addString("bool2int");
1514 ids.int2float = addString("int2float");
1515 ids.bool2float = addString("bool2float");
1516 ids.assert = addString("assert");
1517 ids.mzn_deprecate = addString("mzn_deprecate");
1518 ids.mzn_symmetry_breaking_constraint = addString("mzn_symmetry_breaking_constraint");
1519 ids.mzn_redundant_constraint = addString("mzn_redundant_constraint");
1520 ids.trace = addString("trace");
1521
1522 ids.sum = addString("sum");
1523 ids.lin_exp = addString("lin_exp");
1524 ids.element = addString("element");
1525
1526 ids.show = addString("show");
1527 ids.output = addString("output");
1528 ids.fix = addString("fix");
1529
1530 ids.int_.lin_eq = addString("int_lin_eq");
1531 ids.int_.lin_le = addString("int_lin_le");
1532 ids.int_.lin_ne = addString("int_lin_ne");
1533 ids.int_.plus = addString("int_plus");
1534 ids.int_.minus = addString("int_minus");
1535 ids.int_.times = addString("int_times");
1536 ids.int_.div = addString("int_div");
1537 ids.int_.mod = addString("int_mod");
1538 ids.int_.lt = addString("int_lt");
1539 ids.int_.le = addString("int_le");
1540 ids.int_.gt = addString("int_gt");
1541 ids.int_.ge = addString("int_ge");
1542 ids.int_.eq = addString("int_eq");
1543 ids.int_.ne = addString("int_ne");
1544
1545 ids.int_reif.lin_eq = addString("int_lin_eq_reif");
1546 ids.int_reif.lin_le = addString("int_lin_le_reif");
1547 ids.int_reif.lin_ne = addString("int_lin_ne_reif");
1548 ids.int_reif.plus = addString("int_plus_reif");
1549 ids.int_reif.minus = addString("int_minus_reif");
1550 ids.int_reif.times = addString("int_times_reif");
1551 ids.int_reif.div = addString("int_div_reif");
1552 ids.int_reif.mod = addString("int_mod_reif");
1553 ids.int_reif.lt = addString("int_lt_reif");
1554 ids.int_reif.le = addString("int_le_reif");
1555 ids.int_reif.gt = addString("int_gt_reif");
1556 ids.int_reif.ge = addString("int_ge_reif");
1557 ids.int_reif.eq = addString("int_eq_reif");
1558 ids.int_reif.ne = addString("int_ne_reif");
1559
1560 ids.float_.lin_eq = addString("float_lin_eq");
1561 ids.float_.lin_le = addString("float_lin_le");
1562 ids.float_.lin_lt = addString("float_lin_lt");
1563 ids.float_.lin_ne = addString("float_lin_ne");
1564 ids.float_.plus = addString("float_plus");
1565 ids.float_.minus = addString("float_minus");
1566 ids.float_.times = addString("float_times");
1567 ids.float_.div = addString("float_div");
1568 ids.float_.mod = addString("float_mod");
1569 ids.float_.lt = addString("float_lt");
1570 ids.float_.le = addString("float_le");
1571 ids.float_.gt = addString("float_gt");
1572 ids.float_.ge = addString("float_ge");
1573 ids.float_.eq = addString("float_eq");
1574 ids.float_.ne = addString("float_ne");
1575 ids.float_.in = addString("float_in");
1576 ids.float_.dom = addString("float_dom");
1577
1578 ids.float_reif.lin_eq = addString("float_lin_eq_reif");
1579 ids.float_reif.lin_le = addString("float_lin_le_reif");
1580 ids.float_reif.lin_lt = addString("float_lin_lt_reif");
1581 ids.float_reif.lin_ne = addString("float_lin_ne_reif");
1582 ids.float_reif.plus = addString("float_plus_reif");
1583 ids.float_reif.minus = addString("float_minus_reif");
1584 ids.float_reif.times = addString("float_times_reif");
1585 ids.float_reif.div = addString("float_div_reif");
1586 ids.float_reif.mod = addString("float_mod_reif");
1587 ids.float_reif.lt = addString("float_lt_reif");
1588 ids.float_reif.le = addString("float_le_reif");
1589 ids.float_reif.gt = addString("float_gt_reif");
1590 ids.float_reif.ge = addString("float_ge_reif");
1591 ids.float_reif.eq = addString("float_eq_reif");
1592 ids.float_reif.ne = addString("float_ne_reif");
1593 ids.float_reif.in = addString("float_in_reif");
1594
1595 ids.bool_eq = addString("bool_eq");
1596 ids.bool_eq_reif = addString("bool_eq_reif");
1597 ids.bool_not = addString("bool_not");
1598 ids.bool_clause = addString("bool_clause");
1599 ids.bool_clause_reif = addString("bool_clause_reif");
1600 ids.bool_xor = addString("bool_xor");
1601 ids.array_bool_or = addString("array_bool_or");
1602 ids.array_bool_and = addString("array_bool_and");
1603 ids.set_eq = addString("set_eq");
1604 ids.set_in = addString("set_in");
1605 ids.set_subset = addString("set_subset");
1606 ids.set_card = addString("set_card");
1607 ids.pow = addString("pow");
1608 ids.mzn_set_in_internal = addString("mzn_set_in_internal");
1609
1610 ids.introduced_var = addString("__INTRODUCED");
1611 ids.anonEnumFromStrings = addString("anon_enum");
1612
1613 ctx.root = addId("ctx_root");
1614 ctx.root->type(Type::ann());
1615 ctx.pos = addId("ctx_pos");
1616 ctx.pos->type(Type::ann());
1617 ctx.neg = addId("ctx_neg");
1618 ctx.neg->type(Type::ann());
1619 ctx.mix = addId("ctx_mix");
1620 ctx.mix->type(Type::ann());
1621
1622 ann.empty_annotation = addId("empty_annotation");
1623 ann.empty_annotation->type(Type::ann());
1624 ann.output_var = addId("output_var");
1625
1626 ctx.promise_monotone = addId("promise_ctx_monotone");
1627 ctx.promise_monotone->type(Type::ann());
1628 ctx.promise_antitone = addId("promise_ctx_antitone");
1629 ctx.promise_antitone->type(Type::ann());
1630
1631 ann.output_var->type(Type::ann());
1632 ann.output_only = addId("output_only");
1633 ann.output_only->type(Type::ann());
1634 ann.output_array = addString("output_array");
1635 ann.add_to_output = addId("add_to_output");
1636 ann.add_to_output->type(Type::ann());
1637 ann.mzn_check_var = addId("mzn_check_var");
1638 ann.mzn_check_var->type(Type::ann());
1639 ann.mzn_check_enum_var = addString("mzn_check_enum_var");
1640 ann.is_defined_var = addId("is_defined_var");
1641 ann.is_defined_var->type(Type::ann());
1642 ann.defines_var = addString("defines_var");
1643 ann.is_reverse_map = addId("is_reverse_map");
1644 ann.is_reverse_map->type(Type::ann());
1645 ann.promise_total = addId("promise_total");
1646 ann.promise_total->type(Type::ann());
1647 ann.maybe_partial = addId("maybe_partial");
1648 ann.maybe_partial->type(Type::ann());
1649 ann.doc_comment = addString("doc_comment");
1650 ann.mzn_path = addString("mzn_path");
1651 ann.is_introduced = addString("is_introduced");
1652#ifndef NDEBUG
1653 ann.mzn_break_here = addId("mzn_break_here");
1654 ann.mzn_break_here->type(Type::ann());
1655#endif
1656 ann.rhs_from_assignment = addId("mzn_rhs_from_assignment");
1657 ann.rhs_from_assignment->type(Type::ann());
1658 ann.domain_change_constraint = addId("domain_change_constraint");
1659 ann.domain_change_constraint->type(Type::ann());
1660 ann.mzn_deprecated = addString("mzn_deprecated");
1661 ann.mzn_was_undefined = addId("mzn_was_undefined");
1662 ann.mzn_was_undefined->type(Type::ann());
1663 ann.array_check_form = addId("array_check_form");
1664 ann.array_check_form->type(Type::ann());
1665 ann.annotated_expression = addId("annotated_expression");
1666 ann.annotated_expression->type(Type::ann());
1667 ann.mzn_add_annotated_expression = addString("mzn_add_annotated_expression");
1668
1669 cli.cmdlineData_short_str = addString("-D");
1670 cli.cmdlineData_str = addString("--cmdline-data");
1671 cli.datafile_str = addString("--data");
1672 cli.datafile_short_str = addString("-d");
1673 cli.globalsDir_str = addString("--globals-dir");
1674 cli.globalsDir_alt_str = addString("--mzn-globals-dir");
1675 cli.globalsDir_short_str = addString("-G");
1676 cli.help_str = addString("--help");
1677 cli.help_short_str = addString("-h");
1678 cli.ignoreStdlib_str = addString("--ignore-stdlib");
1679 cli.include_str = addString("-I");
1680 cli.inputFromStdin_str = addString("--input-from-stdin");
1681 cli.instanceCheckOnly_str = addString("--instance-check-only");
1682 cli.newfzn_str = addString("--newfzn");
1683 cli.no_optimize_str = addString("--no-optimize");
1684 cli.no_optimize_alt_str = addString("--no-optimise");
1685 cli.no_outputOzn_str = addString("--no-output-ozn");
1686 cli.no_outputOzn_short_str = addString("-O-");
1687 cli.no_typecheck_str = addString("--no-typecheck");
1688 cli.outputBase_str = addString("--output-base");
1689 cli.outputFznToStdout_str = addString("--output-to-stdout");
1690 cli.outputFznToStdout_alt_str = addString("--output-fzn-to-stdout");
1691 cli.outputOznToFile_str = addString("--output-ozn-to-file");
1692 cli.outputOznToStdout_str = addString("--output-ozn-to-stdout");
1693 cli.outputFznToFile_alt_str = addString("--output-fzn-to-file");
1694 cli.outputFznToFile_short_str = addString("-o");
1695 cli.outputFznToFile_str = addString("--output-to-file");
1696 cli.rangeDomainsOnly_str = addString("--only-range-domains");
1697 cli.statistics_str = addString("--statistics");
1698 cli.statistics_short_str = addString("-s");
1699 cli.stdlib_str = addString("--stdlib-dir");
1700 cli.verbose_str = addString("--verbose");
1701 cli.verbose_short_str = addString("-v");
1702 cli.version_str = addString("--version");
1703 cli.werror_str = addString("-Werror");
1704
1705 cli.solver.all_sols_str = addString("-a");
1706 cli.solver.fzn_solver_str = addString("--solver");
1707
1708 opts.cmdlineData = addString("cmdlineData");
1709 opts.datafile = addString("datafile");
1710 opts.datafiles = addString("datafiles");
1711 opts.fznToFile = addString("fznToFile");
1712 opts.fznToStdout = addString("fznToStdout");
1713 opts.globalsDir = addString("globalsDir");
1714 opts.ignoreStdlib = addString("ignoreStdlib");
1715 opts.includeDir = addString("includeDir");
1716 opts.includePaths = addString("includePaths");
1717 opts.inputFromStdin = addString("inputStdin");
1718 opts.instanceCheckOnly = addString("instanceCheckOnly");
1719 opts.model = addString("model");
1720 opts.newfzn = addString("newfzn");
1721 opts.noOznOutput = addString("noOznOutput");
1722 opts.optimize = addString("optimize");
1723 opts.outputBase = addString("outputBase");
1724 opts.oznToFile = addString("oznToFile");
1725 opts.oznToStdout = addString("oznToStdout");
1726 opts.rangeDomainsOnly = addString("rangeDomainsOnly");
1727 opts.statistics = addString("statistics");
1728 opts.stdlib = addString("stdlib");
1729 opts.typecheck = addString("typecheck");
1730 opts.verbose = addString("verbose");
1731 opts.werror = addString("werror");
1732
1733 opts.solver.allSols = addString("allSols");
1734 opts.solver.numSols = addString("numSols");
1735 opts.solver.threads = addString("threads");
1736 opts.solver.fzn_solver = addString("fznsolver");
1737 opts.solver.fzn_flags = addString("fzn_flags");
1738 opts.solver.fzn_flag = addString("fzn_flag");
1739 opts.solver.fzn_time_limit_ms = addString("fzn_time_limit_ms");
1740 opts.solver.fzn_sigint = addString("fzn_sigint");
1741
1742 cli_cat.general = addString("General Options");
1743 cli_cat.io = addString("Input/Output Options");
1744 cli_cat.solver = addString("Solver Options");
1745 cli_cat.translation = addString("Translation Options");
1746};
1747
1748void Constants::mark(MINIZINC_GC_STAT_ARGS) {
1749 Expression::mark(literalTrue);
1750 Expression::mark(varTrue);
1751 Expression::mark(literalFalse);
1752 Expression::mark(varFalse);
1753 Expression::mark(varIgnore);
1754#if defined(MINIZINC_GC_STATS)
1755 Item::mark(varRedef, gc_stats);
1756#else
1757 Item::mark(varRedef);
1758#endif
1759 Expression::mark(absent);
1760 Expression::mark(infinity);
1761
1762 for (auto* ident : _ids) {
1763 Expression::mark(ident);
1764 }
1765 for (auto& s : _strings) {
1766 s.mark();
1767 }
1768}
1769
1770ASTString Constants::addString(const std::string& s) {
1771 ASTString as(s);
1772 _strings.push_back(as);
1773 return as;
1774}
1775
1776Id* Constants::addId(const std::string& s) {
1777 Id* ident = new Id(Location(), ASTString(s), nullptr);
1778 _ids.push_back(ident);
1779 return ident;
1780}
1781
1782const int Constants::max_array_size;
1783
1784Constants& constants() {
1785 static Constants _c;
1786 return _c;
1787}
1788
1789Annotation::~Annotation() { delete _s; }
1790
1791bool Annotation::contains(Expression* e) const { return (_s != nullptr) && _s->contains(e); }
1792
1793bool Annotation::isEmpty() const { return _s == nullptr || _s->isEmpty(); }
1794
1795ExpressionSetIter Annotation::begin() const {
1796 return _s == nullptr ? ExpressionSetIter(true) : _s->begin();
1797}
1798
1799ExpressionSetIter Annotation::end() const {
1800 return _s == nullptr ? ExpressionSetIter(true) : _s->end();
1801}
1802
1803void Annotation::add(Expression* e) {
1804 if (_s == nullptr) {
1805 _s = new ExpressionSet;
1806 }
1807 if (e != nullptr && !Expression::equal(e, constants().ann.empty_annotation)) {
1808 _s->insert(e);
1809 }
1810}
1811
1812void Annotation::add(std::vector<Expression*> e) {
1813 if (_s == nullptr) {
1814 _s = new ExpressionSet;
1815 }
1816 for (auto i = static_cast<unsigned int>(e.size()); (i--) != 0U;) {
1817 if (e[i] != nullptr && !Expression::equal(e[i], constants().ann.empty_annotation)) {
1818 _s->insert(e[i]);
1819 }
1820 }
1821}
1822
1823void Annotation::remove(Expression* e) {
1824 if ((_s != nullptr) && (e != nullptr)) {
1825 _s->remove(e);
1826 }
1827}
1828
1829void Annotation::removeCall(const ASTString& id) {
1830 if (_s == nullptr) {
1831 return;
1832 }
1833 std::vector<Expression*> toRemove;
1834 for (ExpressionSetIter it = _s->begin(); it != _s->end(); ++it) {
1835 if (Call* c = (*it)->dynamicCast<Call>()) {
1836 if (c->id() == id) {
1837 toRemove.push_back(*it);
1838 }
1839 }
1840 }
1841 for (auto i = static_cast<unsigned int>(toRemove.size()); (i--) != 0U;) {
1842 _s->remove(toRemove[i]);
1843 }
1844}
1845
1846Call* Annotation::getCall(const ASTString& id) const {
1847 if (_s == nullptr) {
1848 return nullptr;
1849 }
1850 for (ExpressionSetIter it = _s->begin(); it != _s->end(); ++it) {
1851 if (Call* c = (*it)->dynamicCast<Call>()) {
1852 if (c->id() == id) {
1853 return c;
1854 }
1855 }
1856 }
1857 return nullptr;
1858}
1859
1860bool Annotation::containsCall(const MiniZinc::ASTString& id) const {
1861 if (_s == nullptr) {
1862 return false;
1863 }
1864 for (ExpressionSetIter it = _s->begin(); it != _s->end(); ++it) {
1865 if (Call* c = (*it)->dynamicCast<Call>()) {
1866 if (c->id() == id) {
1867 return true;
1868 }
1869 }
1870 }
1871 return false;
1872}
1873
1874void Annotation::clear() {
1875 if (_s != nullptr) {
1876 _s->clear();
1877 }
1878}
1879
1880void Annotation::merge(const Annotation& ann) {
1881 if (ann._s == nullptr) {
1882 return;
1883 }
1884 if (_s == nullptr) {
1885 _s = new ExpressionSet;
1886 }
1887 for (ExpressionSetIter it = ann.begin(); it != ann.end(); ++it) {
1888 _s->insert(*it);
1889 }
1890}
1891
1892Expression* get_annotation(const Annotation& ann, const std::string& str) {
1893 for (ExpressionSetIter i = ann.begin(); i != ann.end(); ++i) {
1894 Expression* e = *i;
1895 if ((e->isa<Id>() && e->cast<Id>()->str() == str) ||
1896 (e->isa<Call>() && e->cast<Call>()->id() == str)) {
1897 return e;
1898 }
1899 }
1900 return nullptr;
1901}
1902Expression* get_annotation(const Annotation& ann, const ASTString& str) {
1903 for (ExpressionSetIter i = ann.begin(); i != ann.end(); ++i) {
1904 Expression* e = *i;
1905 if ((e->isa<Id>() && e->cast<Id>()->str() == str) ||
1906 (e->isa<Call>() && e->cast<Call>()->id() == str)) {
1907 return e;
1908 }
1909 }
1910 return nullptr;
1911}
1912} // namespace MiniZinc