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 * Pierre Wilke <wilke.pierre@gmail.com>
6 * Guido Tack <guido.tack@monash.edu>
7 */
8
9/* This Source Code Form is subject to the terms of the Mozilla Public
10 * License, v. 2.0. If a copy of the MPL was not distributed with this
11 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
12
13#include <minizinc/astexception.hh>
14#include <minizinc/hash.hh>
15#include <minizinc/iter.hh>
16#include <minizinc/model.hh>
17#include <minizinc/prettyprinter.hh>
18
19#include <iomanip>
20#include <limits>
21#include <map>
22#include <sstream>
23#include <string>
24#include <utility>
25#include <vector>
26
27namespace MiniZinc {
28
29int precedence(const Expression* e) {
30 if (const auto* bo = e->dynamicCast<BinOp>()) {
31 switch (bo->op()) {
32 case BOT_EQUIV:
33 return 1200;
34 case BOT_IMPL:
35 case BOT_RIMPL:
36 return 1100;
37 case BOT_OR:
38 case BOT_XOR:
39 return 1000;
40 case BOT_AND:
41 return 900;
42 case BOT_LE:
43 case BOT_LQ:
44 case BOT_GR:
45 case BOT_GQ:
46 case BOT_EQ:
47 case BOT_NQ:
48 return 800;
49 case BOT_IN:
50 case BOT_SUBSET:
51 case BOT_SUPERSET:
52 return 700;
53 case BOT_UNION:
54 case BOT_DIFF:
55 case BOT_SYMDIFF:
56 return 600;
57 case BOT_DOTDOT:
58 return 500;
59 case BOT_PLUS:
60 case BOT_MINUS:
61 return 400;
62 case BOT_MULT:
63 case BOT_IDIV:
64 case BOT_MOD:
65 case BOT_DIV:
66 case BOT_INTERSECT:
67 return 300;
68 case BOT_POW:
69 case BOT_PLUSPLUS:
70 return 200;
71 default:
72 assert(false);
73 return -1;
74 }
75
76 } else if (e->isa<Let>()) {
77 return 1300;
78
79 } else {
80 return 0;
81 }
82}
83
84enum Assoc { AS_LEFT, AS_RIGHT, AS_NONE };
85
86Assoc assoc(const BinOp* bo) {
87 switch (bo->op()) {
88 case BOT_LE:
89 case BOT_LQ:
90 case BOT_GR:
91 case BOT_GQ:
92 case BOT_NQ:
93 case BOT_EQ:
94 case BOT_IN:
95 case BOT_SUBSET:
96 case BOT_SUPERSET:
97 case BOT_DOTDOT:
98 return AS_NONE;
99 case BOT_PLUSPLUS:
100 return AS_RIGHT;
101 default:
102 return AS_LEFT;
103 }
104}
105
106enum Parentheses { PN_LEFT = 1, PN_RIGHT = 2 };
107
108Parentheses need_parentheses(const BinOp* bo, const Expression* left, const Expression* right) {
109 int pbo = precedence(bo);
110 int pl = precedence(left);
111 int pr = precedence(right);
112 int ret = static_cast<int>((pbo < pl) || (pbo == pl && assoc(bo) != AS_LEFT));
113 ret += 2 * static_cast<int>((pbo < pr) || (pbo == pr && assoc(bo) != AS_RIGHT));
114 return static_cast<Parentheses>(ret);
115}
116
117void pp_floatval(std::ostream& os, const FloatVal& fv, bool hexFloat) {
118 std::ostringstream oss;
119 if (fv.isFinite()) {
120 if (hexFloat) {
121 throw InternalError("disabled due to hexfloat being not supported by g++ 4.9");
122 // std::hexfloat(oss);
123 oss << fv.toDouble();
124 os << oss.str();
125 }
126 oss << std::setprecision(std::numeric_limits<double>::digits10 + 1);
127 oss << fv;
128 if (oss.str().find('e') == std::string::npos && oss.str().find('.') == std::string::npos) {
129 oss << ".0";
130 }
131 os << oss.str();
132
133 } else {
134 if (fv.isPlusInfinity()) {
135 os << "infinity";
136 } else {
137 os << "-infinity";
138 }
139 }
140}
141
142class PlainPrinter {
143private:
144 bool _flatZinc;
145 EnvI* _env;
146 std::ostream& _os;
147
148public:
149 PlainPrinter(std::ostream& os, bool flatZinc, EnvI* env)
150 : _env(env), _os(os), _flatZinc(flatZinc) {}
151
152 void p(const Type& type, const Expression* e) {
153 switch (type.ti()) {
154 case Type::TI_PAR:
155 break;
156 case Type::TI_VAR:
157 _os << "var ";
158 break;
159 }
160 if (type.ot() == Type::OT_OPTIONAL) {
161 _os << "opt ";
162 }
163 if (type.st() == Type::ST_SET) {
164 _os << "set of ";
165 }
166 if (e == nullptr) {
167 switch (type.bt()) {
168 case Type::BT_INT:
169 _os << "int";
170 break;
171 case Type::BT_BOOL:
172 _os << "bool";
173 break;
174 case Type::BT_FLOAT:
175 _os << "float";
176 break;
177 case Type::BT_STRING:
178 _os << "string";
179 break;
180 case Type::BT_ANN:
181 _os << "ann";
182 break;
183 case Type::BT_BOT:
184 _os << "bot";
185 break;
186 case Type::BT_TOP:
187 _os << "top";
188 break;
189 case Type::BT_UNKNOWN:
190 _os << "???";
191 break;
192 }
193 } else {
194 p(e);
195 }
196 }
197
198 void p(const Annotation& ann) {
199 for (ExpressionSetIter it = ann.begin(); it != ann.end(); ++it) {
200 _os << ":: ";
201 p(*it);
202 }
203 }
204
205 void p(const Expression* e) {
206 if (e == nullptr) {
207 return;
208 }
209 switch (e->eid()) {
210 case Expression::E_INTLIT:
211 _os << e->cast<IntLit>()->v();
212 break;
213 case Expression::E_FLOATLIT: {
214 pp_floatval(_os, e->cast<FloatLit>()->v());
215 } break;
216 case Expression::E_SETLIT: {
217 const SetLit& sl = *e->cast<SetLit>();
218 if (sl.isv() != nullptr) {
219 if (sl.type().bt() == Type::BT_BOOL) {
220 if (sl.isv()->size() == 0) {
221 _os << (_flatZinc ? "true..false" : "{}");
222 } else {
223 _os << "{";
224 if (sl.isv()->min() == 0) {
225 if (sl.isv()->max() == 0) {
226 _os << "false";
227 } else {
228 _os << "false,true";
229 }
230 } else {
231 _os << "true";
232 }
233 _os << "}";
234 }
235 } else {
236 if (sl.isv()->size() == 0) {
237 _os << (_flatZinc ? "1..0" : "{}");
238 } else if (sl.isv()->size() == 1) {
239 _os << sl.isv()->min(0) << ".." << sl.isv()->max(0);
240 } else {
241 if (!sl.isv()->min(0).isFinite()) {
242 _os << sl.isv()->min(0) << ".." << sl.isv()->max(0) << " union ";
243 }
244 _os << "{";
245 bool first = true;
246 for (IntSetRanges isr(sl.isv()); isr(); ++isr) {
247 if (isr.min().isFinite() && isr.max().isFinite()) {
248 for (IntVal i = isr.min(); i <= isr.max(); i++) {
249 if (!first) {
250 _os << ",";
251 }
252 first = false;
253 _os << i;
254 }
255 }
256 }
257 _os << "}";
258 if (!sl.isv()->max(sl.isv()->size() - 1).isFinite()) {
259 _os << " union " << sl.isv()->min(sl.isv()->size() - 1) << ".."
260 << sl.isv()->max(sl.isv()->size() - 1);
261 }
262 }
263 }
264 } else if (sl.fsv() != nullptr) {
265 if (sl.fsv()->size() == 0) {
266 _os << (_flatZinc ? "1.0..0.0" : "{}");
267 } else if (sl.fsv()->size() == 1) {
268 pp_floatval(_os, sl.fsv()->min(0));
269 _os << "..";
270 pp_floatval(_os, sl.fsv()->max(0));
271 } else {
272 bool allSingleton = true;
273 for (FloatSetRanges isr(sl.fsv()); isr(); ++isr) {
274 if (isr.min() != isr.max()) {
275 allSingleton = false;
276 break;
277 }
278 }
279 if (allSingleton) {
280 _os << "{";
281 bool first = true;
282 for (FloatSetRanges isr(sl.fsv()); isr(); ++isr) {
283 if (!first) {
284 _os << ",";
285 }
286 first = false;
287 pp_floatval(_os, isr.min());
288 }
289 _os << "}";
290 } else {
291 bool first = true;
292 for (FloatSetRanges isr(sl.fsv()); isr(); ++isr) {
293 if (!first) {
294 _os << " union ";
295 }
296 first = false;
297 pp_floatval(_os, isr.min());
298 _os << "..";
299 pp_floatval(_os, isr.max());
300 }
301 }
302 }
303 } else {
304 _os << "{";
305 for (unsigned int i = 0; i < sl.v().size(); i++) {
306 p(sl.v()[i]);
307 if (i < sl.v().size() - 1) {
308 _os << ",";
309 }
310 }
311 _os << "}";
312 }
313 } break;
314 case Expression::E_BOOLLIT:
315 _os << (e->cast<BoolLit>()->v() ? "true" : "false");
316 break;
317 case Expression::E_STRINGLIT:
318 _os << "\"" << Printer::escapeStringLit(e->cast<StringLit>()->v()) << "\"";
319 break;
320 case Expression::E_ID: {
321 if (e == constants().absent) {
322 _os << "<>";
323 } else {
324 const Id* id = e->cast<Id>();
325 if (id->decl() != nullptr) {
326 id = id->decl()->id();
327 }
328 if (id->idn() == -1) {
329 _os << id->v();
330 } else {
331 _os << "X_INTRODUCED_" << id->idn() << "_";
332 }
333 }
334 } break;
335 case Expression::E_TIID:
336 _os << "$" << e->cast<TIId>()->v();
337 break;
338 case Expression::E_ANON:
339 _os << "_";
340 break;
341 case Expression::E_ARRAYLIT: {
342 const ArrayLit& al = *e->cast<ArrayLit>();
343 unsigned int n = al.dims();
344 if (n == 1 && al.min(0) == 1) {
345 _os << "[";
346 for (unsigned int i = 0; i < al.size(); i++) {
347 p(al[i]);
348 if (i < al.size() - 1) {
349 _os << ",";
350 }
351 }
352 _os << "]";
353 } else if (n == 2 && al.min(0) == 1 && al.min(1) == 1 && al.max(1) != 0) {
354 _os << "[|";
355 for (int i = 0; i < al.max(0); i++) {
356 for (int j = 0; j < al.max(1); j++) {
357 p(al[i * al.max(1) + j]);
358 if (j < al.max(1) - 1) {
359 _os << ",";
360 }
361 }
362 if (i < al.max(0) - 1) {
363 _os << "|";
364 }
365 }
366 _os << "|]";
367 } else {
368 _os << "array" << n << "d(";
369 for (int i = 0; i < al.dims(); i++) {
370 _os << al.min(i) << ".." << al.max(i);
371 _os << ",";
372 }
373 _os << "[";
374 for (unsigned int i = 0; i < al.size(); i++) {
375 p(al[i]);
376 if (i < al.size() - 1) {
377 _os << ",";
378 }
379 }
380 _os << "])";
381 }
382 } break;
383 case Expression::E_ARRAYACCESS: {
384 const ArrayAccess& aa = *e->cast<ArrayAccess>();
385 p(aa.v());
386 _os << "[";
387 for (unsigned int i = 0; i < aa.idx().size(); i++) {
388 p(aa.idx()[i]);
389 if (i < aa.idx().size() - 1) {
390 _os << ",";
391 }
392 }
393 _os << "]";
394 } break;
395 case Expression::E_COMP: {
396 const Comprehension& c = *e->cast<Comprehension>();
397 _os << (c.set() ? "{" : "[");
398 p(c.e());
399 _os << " | ";
400 for (int i = 0; i < c.numberOfGenerators(); i++) {
401 for (int j = 0; j < c.numberOfDecls(i); j++) {
402 auto* ident = c.decl(i, j)->id();
403 if (ident->idn() == -1) {
404 _os << ident->v();
405 } else {
406 _os << "X_INTRODUCED_" << ident->idn() << "_";
407 }
408 if (j < c.numberOfDecls(i) - 1) {
409 _os << ",";
410 }
411 }
412 if (c.in(i) == nullptr) {
413 _os << " = ";
414 p(c.where(i));
415 } else {
416 _os << " in ";
417 p(c.in(i));
418 if (c.where(i) != nullptr) {
419 _os << " where ";
420 p(c.where(i));
421 }
422 }
423 if (i < c.numberOfGenerators()) {
424 _os << ", ";
425 }
426 }
427 _os << (c.set() ? "}" : "]");
428 } break;
429 case Expression::E_ITE: {
430 const ITE& ite = *e->cast<ITE>();
431 for (int i = 0; i < ite.size(); i++) {
432 _os << (i == 0 ? "if " : " elseif ");
433 p(ite.ifExpr(i));
434 _os << " then ";
435 p(ite.thenExpr(i));
436 }
437 if (ite.elseExpr() != nullptr) {
438 _os << " else ";
439 p(ite.elseExpr());
440 }
441 _os << " endif";
442 } break;
443 case Expression::E_BINOP: {
444 const BinOp& bo = *e->cast<BinOp>();
445 Parentheses ps = need_parentheses(&bo, bo.lhs(), bo.rhs());
446 if ((ps & PN_LEFT) != 0) {
447 _os << "(";
448 }
449 p(bo.lhs());
450 if ((ps & PN_LEFT) != 0) {
451 _os << ")";
452 }
453 switch (bo.op()) {
454 case BOT_PLUS:
455 _os << "+";
456 break;
457 case BOT_MINUS:
458 _os << "-";
459 break;
460 case BOT_MULT:
461 _os << "*";
462 break;
463 case BOT_POW:
464 _os << "^";
465 break;
466 case BOT_DIV:
467 _os << "/";
468 break;
469 case BOT_IDIV:
470 _os << " div ";
471 break;
472 case BOT_MOD:
473 _os << " mod ";
474 break;
475 case BOT_LE:
476 _os << " < ";
477 break;
478 case BOT_LQ:
479 _os << "<=";
480 break;
481 case BOT_GR:
482 _os << " > ";
483 break;
484 case BOT_GQ:
485 _os << ">=";
486 break;
487 case BOT_EQ:
488 _os << "==";
489 break;
490 case BOT_NQ:
491 _os << "!=";
492 break;
493 case BOT_IN:
494 _os << " in ";
495 break;
496 case BOT_SUBSET:
497 _os << " subset ";
498 break;
499 case BOT_SUPERSET:
500 _os << " superset ";
501 break;
502 case BOT_UNION:
503 _os << " union ";
504 break;
505 case BOT_DIFF:
506 _os << " diff ";
507 break;
508 case BOT_SYMDIFF:
509 _os << " symdiff ";
510 break;
511 case BOT_INTERSECT:
512 _os << " intersect ";
513 break;
514 case BOT_PLUSPLUS:
515 _os << "++";
516 break;
517 case BOT_EQUIV:
518 _os << " <-> ";
519 break;
520 case BOT_IMPL:
521 _os << " -> ";
522 break;
523 case BOT_RIMPL:
524 _os << " <- ";
525 break;
526 case BOT_OR:
527 _os << " \\/ ";
528 break;
529 case BOT_AND:
530 _os << " /\\ ";
531 break;
532 case BOT_XOR:
533 _os << " xor ";
534 break;
535 case BOT_DOTDOT:
536 _os << "..";
537 break;
538 default:
539 assert(false);
540 break;
541 }
542
543 if ((ps & PN_RIGHT) != 0) {
544 _os << "(";
545 }
546 p(bo.rhs());
547 if ((ps & PN_RIGHT) != 0) {
548 _os << ")";
549 }
550 } break;
551 case Expression::E_UNOP: {
552 const UnOp& uo = *e->cast<UnOp>();
553 switch (uo.op()) {
554 case UOT_NOT:
555 _os << "not ";
556 break;
557 case UOT_PLUS:
558 _os << "+";
559 break;
560 case UOT_MINUS:
561 _os << "-";
562 break;
563 default:
564 assert(false);
565 break;
566 }
567 bool needParen = (uo.e()->isa<BinOp>() || uo.e()->isa<UnOp>() || !uo.ann().isEmpty());
568 if (needParen) {
569 _os << "(";
570 }
571 p(uo.e());
572 if (needParen) {
573 _os << ")";
574 }
575 } break;
576 case Expression::E_CALL: {
577 const Call& c = *e->cast<Call>();
578 _os << c.id() << "(";
579 for (unsigned int i = 0; i < c.argCount(); i++) {
580 p(c.arg(i));
581 if (i < c.argCount() - 1) {
582 _os << ",";
583 }
584 }
585 _os << ")";
586 } break;
587 case Expression::E_VARDECL: {
588 const VarDecl& vd = *e->cast<VarDecl>();
589 p(vd.ti());
590 if (!vd.ti()->isEnum() && (vd.id()->idn() != -1 || vd.id()->v().size() > 0)) {
591 _os << ":";
592 }
593 if (vd.id()->idn() != -1) {
594 _os << " X_INTRODUCED_" << vd.id()->idn() << "_";
595 } else if (vd.id()->v().size() != 0) {
596 _os << " " << vd.id()->v();
597 }
598 if (vd.introduced()) {
599 _os << " ::var_is_introduced ";
600 }
601 p(vd.ann());
602 if (vd.e() != nullptr) {
603 _os << " = ";
604 p(vd.e());
605 }
606 } break;
607 case Expression::E_LET: {
608 const Let& l = *e->cast<Let>();
609 _os << "let {";
610
611 for (unsigned int i = 0; i < l.let().size(); i++) {
612 const Expression* li = l.let()[i];
613 if (!li->isa<VarDecl>()) {
614 _os << "constraint ";
615 }
616 p(li);
617 if (i < l.let().size() - 1) {
618 _os << ", ";
619 }
620 }
621 _os << "} in (";
622 p(l.in());
623 _os << ")";
624 } break;
625 case Expression::E_TI: {
626 const TypeInst& ti = *e->cast<TypeInst>();
627 if (ti.isEnum()) {
628 _os << "enum";
629 } else if (_env != nullptr) {
630 _os << ti.type().toString(*_env);
631 } else {
632 if (ti.isarray()) {
633 _os << "array [";
634 for (unsigned int i = 0; i < ti.ranges().size(); i++) {
635 p(Type::parint(), ti.ranges()[i]);
636 if (i < ti.ranges().size() - 1) {
637 _os << ",";
638 }
639 }
640 _os << "] of ";
641 }
642 p(ti.type(), ti.domain());
643 }
644 }
645 }
646 if (!e->isa<VarDecl>()) {
647 p(e->ann());
648 }
649 }
650
651 void p(const Item* i) {
652 if (i == nullptr) {
653 return;
654 }
655 if (i->removed()) {
656 _os << "% ";
657 }
658 switch (i->iid()) {
659 case Item::II_INC:
660 _os << "include \"" << Printer::escapeStringLit(i->cast<IncludeI>()->f()) << "\"";
661 break;
662 case Item::II_VD:
663 p(i->cast<VarDeclI>()->e());
664 break;
665 case Item::II_ASN:
666 _os << i->cast<AssignI>()->id() << " = ";
667 p(i->cast<AssignI>()->e());
668 break;
669 case Item::II_CON:
670 _os << "constraint ";
671 p(i->cast<ConstraintI>()->e());
672 break;
673 case Item::II_SOL: {
674 const auto* si = i->cast<SolveI>();
675 _os << "solve ";
676 p(si->ann());
677 switch (si->st()) {
678 case SolveI::ST_SAT:
679 _os << " satisfy";
680 break;
681 case SolveI::ST_MIN:
682 _os << " minimize ";
683 p(si->e());
684 break;
685 case SolveI::ST_MAX:
686 _os << " maximize ";
687 p(si->e());
688 break;
689 }
690 } break;
691 case Item::II_OUT: {
692 const OutputI& oi = *i->cast<OutputI>();
693 _os << "output ";
694 for (ExpressionSetIter i = oi.ann().begin(); i != oi.ann().end(); ++i) {
695 Call* c = (*i)->dynamicCast<Call>();
696 if (c != nullptr && c->id() == "mzn_output_section") {
697 _os << ":: ";
698 p(c->arg(0));
699 _os << " ";
700 }
701 }
702 p(oi.e());
703 } break;
704 case Item::II_FUN: {
705 const FunctionI& fi = *i->cast<FunctionI>();
706 if (fi.ti()->type().isAnn() && fi.e() == nullptr) {
707 _os << "annotation ";
708 } else if (fi.ti()->type() == Type::parbool()) {
709 _os << "test ";
710 } else if (fi.ti()->type() == Type::varbool()) {
711 _os << "predicate ";
712 } else {
713 _os << "function ";
714 p(fi.ti());
715 _os << " : ";
716 }
717 _os << fi.id();
718 if (fi.paramCount() > 0) {
719 _os << "(";
720 for (unsigned int j = 0; j < fi.paramCount(); j++) {
721 p(fi.param(j));
722 if (j < fi.paramCount() - 1) {
723 _os << ",";
724 }
725 }
726 _os << ")";
727 }
728 if (fi.capturedAnnotationsVar() != nullptr) {
729 _os << " ann : ";
730 p(fi.capturedAnnotationsVar()->id());
731 _os << " ";
732 }
733 p(fi.ann());
734 if (fi.e() != nullptr) {
735 _os << " = ";
736 p(fi.e());
737 }
738 } break;
739 }
740 _os << ";" << std::endl;
741 }
742};
743
744template <class T>
745class ExpressionMapper {
746protected:
747 T& _t;
748
749public:
750 ExpressionMapper(T& t) : _t(t) {}
751 typename T::ret map(const Expression* e) {
752 switch (e->eid()) {
753 case Expression::E_INTLIT:
754 return _t.mapIntLit(*e->cast<IntLit>());
755 case Expression::E_FLOATLIT:
756 return _t.mapFloatLit(*e->cast<FloatLit>());
757 case Expression::E_SETLIT:
758 return _t.mapSetLit(*e->cast<SetLit>());
759 case Expression::E_BOOLLIT:
760 return _t.mapBoolLit(*e->cast<BoolLit>());
761 case Expression::E_STRINGLIT:
762 return _t.mapStringLit(*e->cast<StringLit>());
763 case Expression::E_ID:
764 return _t.mapId(*e->cast<Id>());
765 case Expression::E_ANON:
766 return _t.mapAnonVar(*e->cast<AnonVar>());
767 case Expression::E_ARRAYLIT:
768 return _t.mapArrayLit(*e->cast<ArrayLit>());
769 case Expression::E_ARRAYACCESS:
770 return _t.mapArrayAccess(*e->cast<ArrayAccess>());
771 case Expression::E_COMP:
772 return _t.mapComprehension(*e->cast<Comprehension>());
773 case Expression::E_ITE:
774 return _t.mapITE(*e->cast<ITE>());
775 case Expression::E_BINOP:
776 return _t.mapBinOp(*e->cast<BinOp>());
777 case Expression::E_UNOP:
778 return _t.mapUnOp(*e->cast<UnOp>());
779 case Expression::E_CALL:
780 return _t.mapCall(*e->cast<Call>());
781 case Expression::E_VARDECL:
782 return _t.mapVarDecl(*e->cast<VarDecl>());
783 case Expression::E_LET:
784 return _t.mapLet(*e->cast<Let>());
785 case Expression::E_TI:
786 return _t.mapTypeInst(*e->cast<TypeInst>());
787 case Expression::E_TIID:
788 return _t.mapTIId(*e->cast<TIId>());
789 default:
790 assert(false);
791 return typename T::ret();
792 break;
793 }
794 }
795};
796
797class Document {
798private:
799 int _level;
800
801public:
802 Document() : _level(0) {}
803 virtual ~Document() {}
804 int getLevel() const { return _level; }
805 // Make this object a child of "d".
806 virtual void setParent(Document* d) { _level = d->_level + 1; }
807};
808
809class BreakPoint : public Document {
810private:
811 bool _dontSimplify;
812
813public:
814 BreakPoint() { _dontSimplify = false; }
815 BreakPoint(bool ds) { _dontSimplify = ds; }
816 ~BreakPoint() override {}
817 void setDontSimplify(bool b) { _dontSimplify = b; }
818 bool getDontSimplify() const { return _dontSimplify; }
819};
820
821class StringDocument : public Document {
822private:
823 std::string _stringDocument;
824
825public:
826 StringDocument() {}
827 ~StringDocument() override {}
828
829 StringDocument(std::string s) : _stringDocument(std::move(s)) {}
830
831 std::string getString() { return _stringDocument; }
832 void setString(std::string s) { _stringDocument = std::move(s); }
833};
834
835class DocumentList : public Document {
836private:
837 std::vector<Document*> _docs;
838 std::string _beginToken;
839 std::string _separator;
840 std::string _endToken;
841 bool _unbreakable;
842 bool _alignment;
843
844public:
845 ~DocumentList() override {
846 std::vector<Document*>::iterator it;
847 for (it = _docs.begin(); it != _docs.end(); it++) {
848 delete *it;
849 }
850 }
851 DocumentList(std::string beginToken = "", std::string separator = "", std::string endToken = "",
852 bool alignment = true);
853
854 void addDocumentToList(Document* d) {
855 _docs.push_back(d);
856 d->setParent(this);
857 }
858
859 void setParent(Document* d) override {
860 Document::setParent(d);
861 std::vector<Document*>::iterator it;
862 for (it = _docs.begin(); it != _docs.end(); it++) {
863 (*it)->setParent(this);
864 }
865 }
866
867 void addStringToList(std::string s) { addDocumentToList(new StringDocument(std::move(s))); }
868
869 void addBreakPoint(bool b = false) { addDocumentToList(new BreakPoint(b)); }
870
871 std::vector<Document*> getDocs() { return _docs; }
872
873 void setList(std::vector<Document*> ld) { _docs = std::move(ld); }
874
875 std::string getBeginToken() { return _beginToken; }
876
877 std::string getEndToken() { return _endToken; }
878
879 std::string getSeparator() { return _separator; }
880
881 bool getUnbreakable() const { return _unbreakable; }
882
883 void setUnbreakable(bool b) { _unbreakable = b; }
884
885 bool getAlignment() const { return _alignment; }
886};
887
888DocumentList::DocumentList(std::string beginToken, std::string separator, std::string endToken,
889 bool alignment) {
890 _beginToken = std::move(beginToken);
891 _separator = std::move(separator);
892 _endToken = std::move(endToken);
893 _alignment = alignment;
894 _unbreakable = false;
895}
896
897class Line {
898private:
899 int _indentation;
900 int _lineLength;
901 std::vector<std::string> _text;
902
903public:
904 Line() : _indentation(0), _lineLength(0), _text(0) {}
905 Line(const Line&) = default;
906 Line(const int indent) : _indentation(indent), _lineLength(0), _text(0) {}
907 Line& operator=(const Line&) = default;
908 bool operator==(const Line& l) { return &l == this; }
909
910 void setIndentation(int i) { _indentation = i; }
911
912 int getLength() const { return _lineLength; }
913 int getIndentation() const { return _indentation; }
914 int getSpaceLeft(int maxwidth) const;
915 void addString(const std::string& s);
916 void concatenateLines(Line& l);
917
918 void print(std::ostream& os) const {
919 for (int i = 0; i < getIndentation(); i++) {
920 os << " ";
921 }
922 std::vector<std::string>::const_iterator it;
923 for (it = _text.begin(); it != _text.end(); it++) {
924 os << (*it);
925 }
926 os << "\n";
927 }
928};
929
930int Line::getSpaceLeft(int maxwidth) const { return maxwidth - _lineLength - _indentation; }
931void Line::addString(const std::string& s) {
932 _lineLength += static_cast<int>(s.size());
933 _text.push_back(s);
934}
935void Line::concatenateLines(Line& l) {
936 _text.insert(_text.end(), l._text.begin(), l._text.end());
937 _lineLength += l._lineLength;
938}
939
940class LinesToSimplify {
941private:
942 std::map<int, std::vector<int> > _lines;
943
944 // (i,j) in parent <=> j can only be simplified if i is simplified
945 std::vector<std::pair<int, int> > _parent;
946 /*
947 * if i can't simplify, remove j and his parents
948 */
949 // mostRecentlyAdded[level] = line of the most recently added
950 std::map<int, int> _mostRecentlyAdded;
951
952public:
953 std::vector<int>* getLinesForPriority(int p) {
954 std::map<int, std::vector<int> >::iterator it;
955 for (it = _lines.begin(); it != _lines.end(); it++) {
956 if (it->first == p) {
957 return &(it->second);
958 }
959 }
960 return nullptr;
961 }
962 void addLine(int p, int l, int par = -1) {
963 if (par == -1) {
964 for (int i = p - 1; i >= 0; i--) {
965 auto it = _mostRecentlyAdded.find(i);
966 if (it != _mostRecentlyAdded.end()) {
967 par = it->second;
968 break;
969 }
970 }
971 }
972 if (par != -1) {
973 _parent.emplace_back(l, par);
974 }
975 _mostRecentlyAdded.insert(std::pair<int, int>(p, l));
976 std::map<int, std::vector<int> >::iterator it;
977 for (it = _lines.begin(); it != _lines.end(); it++) {
978 if (it->first == p) {
979 it->second.push_back(l);
980 return;
981 }
982 }
983 std::vector<int> v;
984 v.push_back(l);
985 _lines.insert(std::pair<int, std::vector<int> >(p, v));
986 }
987 void decrementLine(std::vector<int>* vec, int l) {
988 std::vector<int>::iterator vit;
989 if (vec != nullptr) {
990 for (vit = vec->begin(); vit != vec->end(); vit++) {
991 if (*vit >= l) {
992 *vit = *vit - 1;
993 }
994 }
995 }
996 // Now the map
997 std::map<int, std::vector<int> >::iterator it;
998 for (it = _lines.begin(); it != _lines.end(); it++) {
999 for (vit = it->second.begin(); vit != it->second.end(); vit++) {
1000 if (*vit >= l) {
1001 *vit = *vit - 1;
1002 }
1003 }
1004 }
1005 // And the parent table
1006 std::vector<std::pair<int, int> >::iterator vpit;
1007 for (vpit = _parent.begin(); vpit != _parent.end(); vpit++) {
1008 if (vpit->first >= l) {
1009 vpit->first--;
1010 }
1011 if (vpit->second >= l) {
1012 vpit->second--;
1013 }
1014 }
1015 }
1016 void remove(LinesToSimplify& lts) {
1017 std::map<int, std::vector<int> >::iterator it;
1018 for (it = lts._lines.begin(); it != lts._lines.end(); it++) {
1019 std::vector<int>::iterator vit;
1020 for (vit = it->second.begin(); vit != it->second.end(); vit++) {
1021 remove(nullptr, *vit, false);
1022 }
1023 }
1024 }
1025 void remove(std::vector<int>* v, int i, bool success = true) {
1026 if (v != nullptr) {
1027 v->erase(std::remove(v->begin(), v->end(), i), v->end());
1028 }
1029 for (auto& line : _lines) {
1030 std::vector<int>& l = line.second;
1031 l.erase(std::remove(l.begin(), l.end(), i), l.end());
1032 }
1033 // Call on its parent
1034 if (!success) {
1035 std::vector<std::pair<int, int> >::iterator vpit;
1036 for (vpit = _parent.begin(); vpit != _parent.end(); vpit++) {
1037 if (vpit->first == i && vpit->second != i && vpit->second != -1) {
1038 remove(v, vpit->second, false);
1039 }
1040 }
1041 }
1042 }
1043 std::vector<int>* getLinesToSimplify() {
1044 auto* vec = new std::vector<int>();
1045 std::map<int, std::vector<int> >::iterator it;
1046 for (it = _lines.begin(); it != _lines.end(); it++) {
1047 std::vector<int>& svec = it->second;
1048 vec->insert(vec->begin(), svec.begin(), svec.end());
1049 }
1050 return vec;
1051 }
1052};
1053
1054Document* expression_to_document(const Expression* e);
1055Document* annotation_to_document(const Annotation& ann);
1056Document* tiexpression_to_document(const Type& type, const Expression* e) {
1057 auto* dl = new DocumentList("", "", "", false);
1058 switch (type.ti()) {
1059 case Type::TI_PAR:
1060 break;
1061 case Type::TI_VAR:
1062 dl->addStringToList("var ");
1063 break;
1064 }
1065 if (type.ot() == Type::OT_OPTIONAL) {
1066 dl->addStringToList("opt ");
1067 }
1068 if (type.st() == Type::ST_SET) {
1069 dl->addStringToList("set of ");
1070 }
1071 if (e == nullptr) {
1072 switch (type.bt()) {
1073 case Type::BT_INT:
1074 dl->addStringToList("int");
1075 break;
1076 case Type::BT_BOOL:
1077 dl->addStringToList("bool");
1078 break;
1079 case Type::BT_FLOAT:
1080 dl->addStringToList("float");
1081 break;
1082 case Type::BT_STRING:
1083 dl->addStringToList("string");
1084 break;
1085 case Type::BT_ANN:
1086 dl->addStringToList("ann");
1087 break;
1088 case Type::BT_BOT:
1089 dl->addStringToList("bot");
1090 break;
1091 case Type::BT_TOP:
1092 dl->addStringToList("top");
1093 break;
1094 case Type::BT_UNKNOWN:
1095 dl->addStringToList("???");
1096 break;
1097 }
1098 } else {
1099 dl->addDocumentToList(expression_to_document(e));
1100 }
1101 return dl;
1102}
1103
1104class ExpressionDocumentMapper {
1105public:
1106 typedef Document* ret;
1107 static ret mapIntLit(const IntLit& il) {
1108 std::ostringstream oss;
1109 oss << il.v();
1110 return new StringDocument(oss.str());
1111 }
1112 static ret mapFloatLit(const FloatLit& fl) {
1113 std::ostringstream oss;
1114 pp_floatval(oss, fl.v());
1115 return new StringDocument(oss.str());
1116 }
1117 static ret mapSetLit(const SetLit& sl) {
1118 DocumentList* dl;
1119 if (sl.isv() != nullptr) {
1120 if (sl.type().bt() == Type::BT_BOOL) {
1121 if (sl.isv()->size() == 0) {
1122 dl = new DocumentList("true..false", "", "");
1123 } else {
1124 if (sl.isv()->min() == 0) {
1125 if (sl.isv()->max() == 0) {
1126 dl = new DocumentList("{false}", "", "");
1127 } else {
1128 dl = new DocumentList("{false,true}", "", "");
1129 }
1130 } else {
1131 dl = new DocumentList("{true}", "", "");
1132 }
1133 }
1134 } else {
1135 if (sl.isv()->size() == 0) {
1136 dl = new DocumentList("1..0", "", "");
1137 } else if (sl.isv()->size() == 1) {
1138 dl = new DocumentList("", "..", "");
1139 {
1140 std::ostringstream oss;
1141 oss << sl.isv()->min(0);
1142 dl->addDocumentToList(new StringDocument(oss.str()));
1143 }
1144 {
1145 std::ostringstream oss;
1146 oss << sl.isv()->max(0);
1147 dl->addDocumentToList(new StringDocument(oss.str()));
1148 }
1149 } else {
1150 dl = new DocumentList("{", ", ", "}", true);
1151 IntSetRanges isr(sl.isv());
1152 for (Ranges::ToValues<IntSetRanges> isv(isr); isv(); ++isv) {
1153 std::ostringstream oss;
1154 oss << isv.val();
1155 dl->addDocumentToList(new StringDocument(oss.str()));
1156 }
1157 }
1158 }
1159 } else if (sl.fsv() != nullptr) {
1160 if (sl.fsv()->size() == 0) {
1161 dl = new DocumentList("1.0..0.0", "", "");
1162 } else if (sl.fsv()->size() == 1) {
1163 dl = new DocumentList("", "..", "");
1164 {
1165 std::ostringstream oss;
1166 pp_floatval(oss, sl.fsv()->min(0));
1167 dl->addDocumentToList(new StringDocument(oss.str()));
1168 }
1169 {
1170 std::ostringstream oss;
1171 pp_floatval(oss, sl.fsv()->max(0));
1172 dl->addDocumentToList(new StringDocument(oss.str()));
1173 }
1174 } else {
1175 dl = new DocumentList("", " union ", "", true);
1176 FloatSetRanges fsr(sl.fsv());
1177 for (; fsr(); ++fsr) {
1178 std::ostringstream oss;
1179 pp_floatval(oss, fsr.min());
1180 oss << "..";
1181 pp_floatval(oss, fsr.max());
1182 dl->addDocumentToList(new StringDocument(oss.str()));
1183 }
1184 }
1185
1186 } else {
1187 dl = new DocumentList("{", ", ", "}", true);
1188 for (unsigned int i = 0; i < sl.v().size(); i++) {
1189 dl->addDocumentToList(expression_to_document((sl.v()[i])));
1190 }
1191 }
1192 return dl;
1193 }
1194 static ret mapBoolLit(const BoolLit& bl) {
1195 return new StringDocument(std::string(bl.v() ? "true" : "false"));
1196 }
1197 static ret mapStringLit(const StringLit& sl) {
1198 std::ostringstream oss;
1199 oss << "\"" << Printer::escapeStringLit(sl.v()) << "\"";
1200 return new StringDocument(oss.str());
1201 }
1202 static ret mapId(const Id& id) {
1203 if (&id == constants().absent) {
1204 return new StringDocument("<>");
1205 }
1206 if (id.idn() == -1) {
1207 return new StringDocument(std::string(id.v().c_str(), id.v().size()));
1208 }
1209 std::ostringstream oss;
1210 oss << "X_INTRODUCED_" << id.idn() << "_";
1211 return new StringDocument(oss.str());
1212 }
1213 static ret mapTIId(const TIId& id) {
1214 std::ostringstream ss;
1215 ss << "$" << id.v();
1216 return new StringDocument(ss.str());
1217 }
1218 static ret mapAnonVar(const AnonVar& /*v*/) { return new StringDocument("_"); }
1219 static ret mapArrayLit(const ArrayLit& al) {
1220 /// TODO: test multi-dimensional arrays handling
1221 DocumentList* dl;
1222 unsigned int n = al.dims();
1223 if (n == 1 && al.min(0) == 1) {
1224 dl = new DocumentList("[", ", ", "]");
1225 for (unsigned int i = 0; i < al.size(); i++) {
1226 dl->addDocumentToList(expression_to_document(al[i]));
1227 }
1228 } else if (n == 2 && al.min(0) == 1 && al.min(1) == 1) {
1229 dl = new DocumentList("[| ", " | ", " |]");
1230 for (int i = 0; i < al.max(0); i++) {
1231 auto* row = new DocumentList("", ", ", "");
1232 for (int j = 0; j < al.max(1); j++) {
1233 row->addDocumentToList(expression_to_document(al[i * al.max(1) + j]));
1234 }
1235 dl->addDocumentToList(row);
1236 if (i != al.max(0) - 1) {
1237 dl->addBreakPoint(true); // dont simplify
1238 }
1239 }
1240 } else {
1241 dl = new DocumentList("", "", "");
1242 std::stringstream oss;
1243 oss << "array" << n << "d";
1244 dl->addStringToList(oss.str());
1245 auto* args = new DocumentList("(", ", ", ")");
1246
1247 for (int i = 0; i < al.dims(); i++) {
1248 oss.str("");
1249 oss << al.min(i) << ".." << al.max(i);
1250 args->addStringToList(oss.str());
1251 }
1252 auto* array = new DocumentList("[", ", ", "]");
1253 for (unsigned int i = 0; i < al.size(); i++) {
1254 array->addDocumentToList(expression_to_document(al[i]));
1255 }
1256 args->addDocumentToList(array);
1257 dl->addDocumentToList(args);
1258 }
1259 return dl;
1260 }
1261 static ret mapArrayAccess(const ArrayAccess& aa) {
1262 auto* dl = new DocumentList("", "", "");
1263
1264 dl->addDocumentToList(expression_to_document(aa.v()));
1265 auto* args = new DocumentList("[", ", ", "]");
1266 for (unsigned int i = 0; i < aa.idx().size(); i++) {
1267 args->addDocumentToList(expression_to_document(aa.idx()[i]));
1268 }
1269 dl->addDocumentToList(args);
1270 return dl;
1271 }
1272 static ret mapComprehension(const Comprehension& c) {
1273 std::ostringstream oss;
1274 DocumentList* dl;
1275 if (c.set()) {
1276 dl = new DocumentList("{ ", " | ", " }");
1277 } else {
1278 dl = new DocumentList("[ ", " | ", " ]");
1279 }
1280 dl->addDocumentToList(expression_to_document(c.e()));
1281 auto* head = new DocumentList("", " ", "");
1282 auto* generators = new DocumentList("", ", ", "");
1283 for (int i = 0; i < c.numberOfGenerators(); i++) {
1284 auto* gen = new DocumentList("", "", "");
1285 auto* idents = new DocumentList("", ", ", "");
1286 for (int j = 0; j < c.numberOfDecls(i); j++) {
1287 std::ostringstream ss;
1288 Id* ident = c.decl(i, j)->id();
1289 if (ident->idn() == -1) {
1290 ss << ident->v();
1291 } else {
1292 ss << "X_INTRODUCED_" << ident->idn() << "_";
1293 }
1294 idents->addStringToList(ss.str());
1295 }
1296 gen->addDocumentToList(idents);
1297 if (c.in(i) == nullptr) {
1298 gen->addStringToList(" = ");
1299 gen->addDocumentToList(expression_to_document(c.where(i)));
1300 } else {
1301 gen->addStringToList(" in ");
1302 gen->addDocumentToList(expression_to_document(c.in(i)));
1303 if (c.where(i) != nullptr) {
1304 gen->addStringToList(" where ");
1305 gen->addDocumentToList(expression_to_document(c.where(i)));
1306 }
1307 }
1308 generators->addDocumentToList(gen);
1309 }
1310 head->addDocumentToList(generators);
1311 dl->addDocumentToList(head);
1312
1313 return dl;
1314 }
1315 static ret mapITE(const ITE& ite) {
1316 auto* dl = new DocumentList("", "", "");
1317 for (int i = 0; i < ite.size(); i++) {
1318 std::string beg = (i == 0 ? "if " : " elseif ");
1319 dl->addStringToList(beg);
1320 dl->addDocumentToList(expression_to_document(ite.ifExpr(i)));
1321 dl->addStringToList(" then ");
1322
1323 auto* ifdoc = new DocumentList("", "", "", false);
1324 ifdoc->addBreakPoint();
1325 ifdoc->addDocumentToList(expression_to_document(ite.thenExpr(i)));
1326 dl->addDocumentToList(ifdoc);
1327 dl->addStringToList(" ");
1328 }
1329 dl->addBreakPoint();
1330 dl->addStringToList("else ");
1331
1332 auto* elsedoc = new DocumentList("", "", "", false);
1333 elsedoc->addBreakPoint();
1334 elsedoc->addDocumentToList(expression_to_document(ite.elseExpr()));
1335 dl->addDocumentToList(elsedoc);
1336 dl->addStringToList(" ");
1337 dl->addBreakPoint();
1338 dl->addStringToList("endif");
1339
1340 return dl;
1341 }
1342 static ret mapBinOp(const BinOp& bo) {
1343 Parentheses ps = need_parentheses(&bo, bo.lhs(), bo.rhs());
1344 DocumentList* opLeft;
1345 DocumentList* dl;
1346 DocumentList* opRight;
1347 bool linebreak = false;
1348 if ((ps & PN_LEFT) != 0) {
1349 opLeft = new DocumentList("(", " ", ")");
1350 } else {
1351 opLeft = new DocumentList("", " ", "");
1352 }
1353 opLeft->addDocumentToList(expression_to_document(bo.lhs()));
1354 std::string op;
1355 switch (bo.op()) {
1356 case BOT_PLUS:
1357 op = "+";
1358 break;
1359 case BOT_MINUS:
1360 op = "-";
1361 break;
1362 case BOT_MULT:
1363 op = "*";
1364 break;
1365 case BOT_POW:
1366 op = "^";
1367 break;
1368 case BOT_DIV:
1369 op = "/";
1370 break;
1371 case BOT_IDIV:
1372 op = " div ";
1373 break;
1374 case BOT_MOD:
1375 op = " mod ";
1376 break;
1377 case BOT_LE:
1378 op = " < ";
1379 break;
1380 case BOT_LQ:
1381 op = "<=";
1382 break;
1383 case BOT_GR:
1384 op = " > ";
1385 break;
1386 case BOT_GQ:
1387 op = ">=";
1388 break;
1389 case BOT_EQ:
1390 op = "==";
1391 break;
1392 case BOT_NQ:
1393 op = "!=";
1394 break;
1395 case BOT_IN:
1396 op = " in ";
1397 break;
1398 case BOT_SUBSET:
1399 op = " subset ";
1400 break;
1401 case BOT_SUPERSET:
1402 op = " superset ";
1403 break;
1404 case BOT_UNION:
1405 op = " union ";
1406 break;
1407 case BOT_DIFF:
1408 op = " diff ";
1409 break;
1410 case BOT_SYMDIFF:
1411 op = " symdiff ";
1412 break;
1413 case BOT_INTERSECT:
1414 op = " intersect ";
1415 break;
1416 case BOT_PLUSPLUS:
1417 op = "++";
1418 linebreak = true;
1419 break;
1420 case BOT_EQUIV:
1421 op = " <-> ";
1422 break;
1423 case BOT_IMPL:
1424 op = " -> ";
1425 break;
1426 case BOT_RIMPL:
1427 op = " <- ";
1428 break;
1429 case BOT_OR:
1430 op = " \\/ ";
1431 linebreak = true;
1432 break;
1433 case BOT_AND:
1434 op = " /\\ ";
1435 linebreak = true;
1436 break;
1437 case BOT_XOR:
1438 op = " xor ";
1439 break;
1440 case BOT_DOTDOT:
1441 op = "..";
1442 break;
1443 default:
1444 assert(false);
1445 break;
1446 }
1447 dl = new DocumentList("", op, "");
1448
1449 if ((ps & PN_RIGHT) != 0) {
1450 opRight = new DocumentList("(", " ", ")");
1451 } else {
1452 opRight = new DocumentList("", "", "");
1453 }
1454 opRight->addDocumentToList(expression_to_document(bo.rhs()));
1455 dl->addDocumentToList(opLeft);
1456 if (linebreak) {
1457 dl->addBreakPoint();
1458 }
1459 dl->addDocumentToList(opRight);
1460
1461 return dl;
1462 }
1463 static ret mapUnOp(const UnOp& uo) {
1464 auto* dl = new DocumentList("", "", "");
1465 std::string op;
1466 switch (uo.op()) {
1467 case UOT_NOT:
1468 op = "not ";
1469 break;
1470 case UOT_PLUS:
1471 op = "+";
1472 break;
1473 case UOT_MINUS:
1474 op = "-";
1475 break;
1476 default:
1477 assert(false);
1478 break;
1479 }
1480 dl->addStringToList(op);
1481 DocumentList* unop;
1482 bool needParen = (uo.e()->isa<BinOp>() || uo.e()->isa<UnOp>());
1483 if (needParen) {
1484 unop = new DocumentList("(", " ", ")");
1485 } else {
1486 unop = new DocumentList("", " ", "");
1487 }
1488
1489 unop->addDocumentToList(expression_to_document(uo.e()));
1490 dl->addDocumentToList(unop);
1491 return dl;
1492 }
1493 static ret mapCall(const Call& c) {
1494 if (c.argCount() == 1) {
1495 /*
1496 * if we have only one argument, and this is an array comprehension,
1497 * we convert it into the following syntax
1498 * forall (f(i,j) | i in 1..10)
1499 * -->
1500 * forall (i in 1..10) (f(i,j))
1501 */
1502
1503 const Expression* e = c.arg(0);
1504 if (e->isa<Comprehension>()) {
1505 const auto* com = e->cast<Comprehension>();
1506 if (!com->set()) {
1507 auto* dl = new DocumentList("", " ", "");
1508 dl->addStringToList(std::string(c.id().c_str(), c.id().size()));
1509 auto* args = new DocumentList("", " ", "", false);
1510 auto* generators = new DocumentList("", ", ", "");
1511
1512 for (int i = 0; i < com->numberOfGenerators(); i++) {
1513 auto* gen = new DocumentList("", "", "");
1514 auto* idents = new DocumentList("", ", ", "");
1515 for (int j = 0; j < com->numberOfDecls(i); j++) {
1516 idents->addStringToList(std::string(com->decl(i, j)->id()->v().c_str(),
1517 com->decl(i, j)->id()->v().size()));
1518 }
1519 gen->addDocumentToList(idents);
1520 if (com->in(i) == nullptr) {
1521 gen->addStringToList(" = ");
1522 gen->addDocumentToList(expression_to_document(com->where(i)));
1523 } else {
1524 gen->addStringToList(" in ");
1525 gen->addDocumentToList(expression_to_document(com->in(i)));
1526 if (com->where(i) != nullptr) {
1527 gen->addStringToList(" where ");
1528 gen->addDocumentToList(expression_to_document(com->where(i)));
1529 }
1530 }
1531 generators->addDocumentToList(gen);
1532 }
1533
1534 args->addStringToList("(");
1535 args->addDocumentToList(generators);
1536 args->addStringToList(")");
1537
1538 args->addStringToList("(");
1539 args->addBreakPoint();
1540 args->addDocumentToList(expression_to_document(com->e()));
1541
1542 dl->addDocumentToList(args);
1543 dl->addBreakPoint();
1544 dl->addStringToList(")");
1545
1546 return dl;
1547 }
1548 }
1549 }
1550 std::ostringstream beg;
1551 beg << c.id() << "(";
1552 auto* dl = new DocumentList(beg.str(), ", ", ")");
1553 for (unsigned int i = 0; i < c.argCount(); i++) {
1554 dl->addDocumentToList(expression_to_document(c.arg(i)));
1555 }
1556 return dl;
1557 }
1558 static ret mapVarDecl(const VarDecl& vd) {
1559 std::ostringstream oss;
1560 auto* dl = new DocumentList("", "", "");
1561 dl->addDocumentToList(expression_to_document(vd.ti()));
1562 if (vd.id()->idn() == -1) {
1563 if (vd.id()->v().size() != 0) {
1564 oss << ": " << vd.id()->v().c_str();
1565 }
1566 } else {
1567 oss << ": X_INTRODUCED_" << vd.id()->idn() << "_";
1568 }
1569 dl->addStringToList(oss.str());
1570
1571 if (vd.introduced()) {
1572 dl->addStringToList(" ::var_is_introduced ");
1573 }
1574 if (!vd.ann().isEmpty()) {
1575 dl->addDocumentToList(annotation_to_document(vd.ann()));
1576 }
1577 if (vd.e() != nullptr) {
1578 dl->addStringToList(" = ");
1579 dl->addDocumentToList(expression_to_document(vd.e()));
1580 }
1581 return dl;
1582 }
1583 static ret mapLet(const Let& l) {
1584 auto* letin = new DocumentList("", "", "", false);
1585 auto* lets = new DocumentList("", " ", "", true);
1586 auto* inexpr = new DocumentList("", "", "");
1587 bool ds = l.let().size() > 1;
1588
1589 for (unsigned int i = 0; i < l.let().size(); i++) {
1590 if (i != 0) {
1591 lets->addBreakPoint(ds);
1592 }
1593 auto* exp = new DocumentList("", " ", ",");
1594 const Expression* li = l.let()[i];
1595 if (!li->isa<VarDecl>()) {
1596 exp->addStringToList("constraint");
1597 }
1598 exp->addDocumentToList(expression_to_document(li));
1599 lets->addDocumentToList(exp);
1600 }
1601
1602 inexpr->addDocumentToList(expression_to_document(l.in()));
1603 letin->addBreakPoint(ds);
1604 letin->addDocumentToList(lets);
1605
1606 auto* letin2 = new DocumentList("", "", "", false);
1607
1608 letin2->addBreakPoint();
1609 letin2->addDocumentToList(inexpr);
1610
1611 auto* dl = new DocumentList("", "", "");
1612 dl->addStringToList("let {");
1613 dl->addDocumentToList(letin);
1614 dl->addBreakPoint(ds);
1615 dl->addStringToList("} in (");
1616 dl->addDocumentToList(letin2);
1617 // dl->addBreakPoint();
1618 dl->addStringToList(")");
1619 return dl;
1620 }
1621 static ret mapTypeInst(const TypeInst& ti) {
1622 auto* dl = new DocumentList("", "", "");
1623 if (ti.isarray()) {
1624 dl->addStringToList("array [");
1625 auto* ran = new DocumentList("", ", ", "");
1626 for (unsigned int i = 0; i < ti.ranges().size(); i++) {
1627 ran->addDocumentToList(tiexpression_to_document(Type::parint(), ti.ranges()[i]));
1628 }
1629 dl->addDocumentToList(ran);
1630 dl->addStringToList("] of ");
1631 }
1632 dl->addDocumentToList(tiexpression_to_document(ti.type(), ti.domain()));
1633 return dl;
1634 }
1635};
1636
1637Document* annotation_to_document(const Annotation& ann) {
1638 auto* dl = new DocumentList(" :: ", " :: ", "");
1639 for (ExpressionSetIter it = ann.begin(); it != ann.end(); ++it) {
1640 dl->addDocumentToList(expression_to_document(*it));
1641 }
1642 return dl;
1643}
1644
1645Document* expression_to_document(const Expression* e) {
1646 if (e == nullptr) {
1647 return new StringDocument("NULL");
1648 }
1649 ExpressionDocumentMapper esm;
1650 ExpressionMapper<ExpressionDocumentMapper> em(esm);
1651 auto* dl = new DocumentList("", "", "");
1652 Document* s = em.map(e);
1653 dl->addDocumentToList(s);
1654 if (!e->isa<VarDecl>() && !e->ann().isEmpty()) {
1655 dl->addDocumentToList(annotation_to_document(e->ann()));
1656 }
1657 return dl;
1658}
1659
1660class ItemDocumentMapper {
1661public:
1662 typedef Document* ret;
1663 static ret mapIncludeI(const IncludeI& ii) {
1664 std::ostringstream oss;
1665 oss << "include \"" << Printer::escapeStringLit(ii.f()) << "\";";
1666 return new StringDocument(oss.str());
1667 }
1668 static ret mapVarDeclI(const VarDeclI& vi) {
1669 auto* dl = new DocumentList("", " ", ";");
1670 dl->addDocumentToList(expression_to_document(vi.e()));
1671 return dl;
1672 }
1673 static ret mapAssignI(const AssignI& ai) {
1674 auto* dl = new DocumentList("", " = ", ";");
1675 dl->addStringToList(std::string(ai.id().c_str(), ai.id().size()));
1676 dl->addDocumentToList(expression_to_document(ai.e()));
1677 return dl;
1678 }
1679 static ret mapConstraintI(const ConstraintI& ci) {
1680 auto* dl = new DocumentList("constraint ", " ", ";");
1681 dl->addDocumentToList(expression_to_document(ci.e()));
1682 return dl;
1683 }
1684 static ret mapSolveI(const SolveI& si) {
1685 auto* dl = new DocumentList("", "", ";");
1686 dl->addStringToList("solve");
1687 if (!si.ann().isEmpty()) {
1688 dl->addDocumentToList(annotation_to_document(si.ann()));
1689 }
1690 switch (si.st()) {
1691 case SolveI::ST_SAT:
1692 dl->addStringToList(" satisfy");
1693 break;
1694 case SolveI::ST_MIN:
1695 dl->addStringToList(" minimize ");
1696 dl->addDocumentToList(expression_to_document(si.e()));
1697 break;
1698 case SolveI::ST_MAX:
1699 dl->addStringToList(" maximize ");
1700 dl->addDocumentToList(expression_to_document(si.e()));
1701 break;
1702 }
1703 return dl;
1704 }
1705 static ret mapOutputI(const OutputI& oi) {
1706 auto* dl = new DocumentList("", " ", ";");
1707 dl->addStringToList("output ");
1708 for (ExpressionSetIter i = oi.ann().begin(); i != oi.ann().end(); ++i) {
1709 Call* c = (*i)->dynamicCast<Call>();
1710 if (c != nullptr && c->id() == "mzn_output_section") {
1711 dl->addStringToList(":: ");
1712 dl->addDocumentToList(expression_to_document(c->arg(0)));
1713 }
1714 }
1715 if (!oi.ann().isEmpty()) {
1716 dl->addStringToList(" ");
1717 }
1718 dl->addDocumentToList(expression_to_document(oi.e()));
1719 return dl;
1720 }
1721 static ret mapFunctionI(const FunctionI& fi) {
1722 DocumentList* dl;
1723 if (fi.ti()->type().isAnn() && fi.e() == nullptr) {
1724 dl = new DocumentList("annotation ", " ", ";", false);
1725 } else if (fi.ti()->type() == Type::parbool()) {
1726 dl = new DocumentList("test ", "", ";", false);
1727 } else if (fi.ti()->type() == Type::varbool()) {
1728 dl = new DocumentList("predicate ", "", ";", false);
1729 } else {
1730 dl = new DocumentList("function ", "", ";", false);
1731 dl->addDocumentToList(expression_to_document(fi.ti()));
1732 dl->addStringToList(": ");
1733 }
1734 dl->addStringToList(std::string(fi.id().c_str(), fi.id().size()));
1735 if (fi.paramCount() > 0) {
1736 auto* params = new DocumentList("(", ", ", ")");
1737 for (unsigned int i = 0; i < fi.paramCount(); i++) {
1738 auto* par = new DocumentList("", "", "");
1739 par->setUnbreakable(true);
1740 par->addDocumentToList(expression_to_document(fi.param(i)));
1741 params->addDocumentToList(par);
1742 }
1743 dl->addDocumentToList(params);
1744 }
1745 if (fi.capturedAnnotationsVar() != nullptr) {
1746 dl->addStringToList(" ann : ");
1747 dl->addDocumentToList(expression_to_document(fi.capturedAnnotationsVar()->id()));
1748 dl->addStringToList(" ");
1749 }
1750 if (!fi.ann().isEmpty()) {
1751 dl->addDocumentToList(annotation_to_document(fi.ann()));
1752 }
1753 if (fi.e() != nullptr) {
1754 dl->addStringToList(" = ");
1755 dl->addBreakPoint();
1756 dl->addDocumentToList(expression_to_document(fi.e()));
1757 }
1758
1759 return dl;
1760 }
1761};
1762
1763class PrettyPrinter {
1764public:
1765 /*
1766 * \brief Constructor for class Pretty Printer
1767 * \param maxwidth (default 80) : number of rows
1768 * \param indentationBase : spaces that represent the atomic number of spaces
1769 * \param sim : whether we want to simplify the result
1770 * \param deepSimp : whether we want to simplify at each breakpoint or not
1771 */
1772 PrettyPrinter(int _maxwidth = 80, int _indentationBase = 4, bool sim = false,
1773 bool deepSimp = false);
1774
1775 void print(Document* d);
1776 void print(std::ostream& os) const;
1777
1778private:
1779 int _maxwidth;
1780 int _indentationBase;
1781 int _currentLine;
1782 int _currentItem;
1783 std::vector<std::vector<Line> > _items;
1784 std::vector<LinesToSimplify> _linesToSimplify;
1785 std::vector<LinesToSimplify> _linesNotToSimplify;
1786 bool _simp;
1787 bool _deeplySimp;
1788
1789 void addItem();
1790
1791 void addLine(int indentation, bool bp = false, bool simpl = false, int level = 0);
1792 static std::string printSpaces(int n);
1793 const std::vector<Line>& getCurrentItemLines() const;
1794
1795 void printDocument(Document* d, bool alignment, int alignmentCol, const std::string& before = "",
1796 const std::string& after = "");
1797 void printDocList(DocumentList* d, int alignmentCol, const std::string& before = "",
1798 const std::string& after = "");
1799 void printStringDoc(StringDocument* d, bool alignment, int alignmentCol,
1800 const std::string& before = "", const std::string& after = "");
1801 void printString(const std::string& s, bool alignment, int alignmentCol);
1802 bool simplify(int item, int line, std::vector<int>* vec);
1803 void simplifyItem(int item);
1804};
1805
1806void PrettyPrinter::print(Document* d) {
1807 addItem();
1808 addLine(0);
1809 printDocument(d, true, 0);
1810 if (_simp) {
1811 simplifyItem(_currentItem);
1812 }
1813}
1814
1815PrettyPrinter::PrettyPrinter(int maxwidth, int indentationBase, bool sim, bool deepsim) {
1816 _maxwidth = maxwidth;
1817 _indentationBase = indentationBase;
1818 _currentLine = -1;
1819 _currentItem = -1;
1820
1821 _simp = sim;
1822 _deeplySimp = deepsim;
1823}
1824const std::vector<Line>& PrettyPrinter::getCurrentItemLines() const { return _items[_currentItem]; }
1825
1826void PrettyPrinter::addLine(int indentation, bool bp, bool simpl, int level) {
1827 _items[_currentItem].push_back(Line(indentation));
1828 _currentLine++;
1829 if (bp && _deeplySimp) {
1830 _linesToSimplify[_currentItem].addLine(level, _currentLine);
1831 if (!simpl) {
1832 _linesNotToSimplify[_currentItem].addLine(0, _currentLine);
1833 }
1834 }
1835}
1836void PrettyPrinter::addItem() {
1837 _items.emplace_back();
1838 _linesToSimplify.emplace_back();
1839 _linesNotToSimplify.emplace_back();
1840 _currentItem++;
1841 _currentLine = -1;
1842}
1843
1844void PrettyPrinter::print(std::ostream& os) const {
1845 std::vector<Line>::const_iterator it;
1846 int nItems = static_cast<int>(_items.size());
1847 for (int item = 0; item < nItems; item++) {
1848 for (it = _items[item].begin(); it != _items[item].end(); it++) {
1849 it->print(os);
1850 }
1851 // os << std::endl;
1852 }
1853}
1854std::string PrettyPrinter::printSpaces(int n) {
1855 std::string result;
1856 for (int i = 0; i < n; i++) {
1857 result += " ";
1858 }
1859 return result;
1860}
1861
1862void PrettyPrinter::printDocument(Document* d, bool alignment, int alignmentCol,
1863 const std::string& before, const std::string& after) {
1864 if (auto* dl = dynamic_cast<DocumentList*>(d)) {
1865 printDocList(dl, alignmentCol, before, after);
1866 } else if (auto* sd = dynamic_cast<StringDocument*>(d)) {
1867 printStringDoc(sd, alignment, alignmentCol, before, after);
1868 } else if (auto* bp = dynamic_cast<BreakPoint*>(d)) {
1869 printString(before, alignment, alignmentCol);
1870 addLine(alignmentCol, _deeplySimp, !bp->getDontSimplify(), d->getLevel());
1871 printString(after, alignment, alignmentCol);
1872 } else {
1873 throw InternalError("PrettyPrinter::print : Wrong type of document");
1874 }
1875}
1876
1877void PrettyPrinter::printStringDoc(StringDocument* d, bool alignment, int alignmentCol,
1878 const std::string& before, const std::string& after) {
1879 std::string s;
1880 if (d != nullptr) {
1881 s = d->getString();
1882 }
1883 s = before + s + after;
1884 printString(s, alignment, alignmentCol);
1885}
1886
1887void PrettyPrinter::printString(const std::string& s, bool alignment, int alignmentCol) {
1888 Line& l = _items[_currentItem][_currentLine];
1889 int size = static_cast<int>(s.size());
1890 if (size <= l.getSpaceLeft(_maxwidth)) {
1891 l.addString(s);
1892 } else {
1893 int col = alignment && _maxwidth - alignmentCol >= size ? alignmentCol : _indentationBase;
1894 addLine(col);
1895 _items[_currentItem][_currentLine].addString(s);
1896 }
1897}
1898
1899void PrettyPrinter::printDocList(DocumentList* d, int alignmentCol, const std::string& super_before,
1900 const std::string& super_after) {
1901 std::vector<Document*> ld = d->getDocs();
1902 std::string beginToken = d->getBeginToken();
1903 std::string separator = d->getSeparator();
1904 std::string endToken = d->getEndToken();
1905 bool _alignment = d->getAlignment();
1906 if (d->getUnbreakable()) {
1907 addLine(alignmentCol);
1908 }
1909 int currentCol = _items[_currentItem][_currentLine].getIndentation() +
1910 _items[_currentItem][_currentLine].getLength();
1911 int newAlignmentCol =
1912 _alignment ? currentCol + static_cast<int>(beginToken.size()) : alignmentCol;
1913 int vectorSize = static_cast<int>(ld.size());
1914 int lastVisibleElementIndex;
1915 for (int i = 0; i < vectorSize; i++) {
1916 if (dynamic_cast<BreakPoint*>(ld[i]) == nullptr) {
1917 lastVisibleElementIndex = i;
1918 }
1919 }
1920 if (vectorSize == 0) {
1921 printStringDoc(nullptr, true, newAlignmentCol, super_before + beginToken,
1922 endToken + super_after);
1923 }
1924 for (int i = 0; i < vectorSize; i++) {
1925 Document* subdoc = ld[i];
1926 bool bp = false;
1927 if (dynamic_cast<BreakPoint*>(subdoc) != nullptr) {
1928 if (!_alignment) {
1929 newAlignmentCol += _indentationBase;
1930 }
1931 bp = true;
1932 }
1933 std::string af;
1934 std::string be;
1935 if (i != vectorSize - 1) {
1936 if (bp || lastVisibleElementIndex <= i) {
1937 af = "";
1938 } else {
1939 af = separator;
1940 }
1941 } else {
1942 af = endToken + super_after;
1943 }
1944 if (i == 0) {
1945 be = super_before + beginToken;
1946 } else {
1947 be = "";
1948 }
1949 printDocument(subdoc, _alignment, newAlignmentCol, be, af);
1950 }
1951 if (d->getUnbreakable()) {
1952 simplify(_currentItem, _currentLine, nullptr);
1953 }
1954}
1955void PrettyPrinter::simplifyItem(int item) {
1956 _linesToSimplify[item].remove(_linesNotToSimplify[item]);
1957 std::vector<int>* vec = (_linesToSimplify[item].getLinesToSimplify());
1958 while (!vec->empty()) {
1959 if (!simplify(item, (*vec)[0], vec)) {
1960 break;
1961 }
1962 }
1963 delete vec;
1964}
1965
1966bool PrettyPrinter::simplify(int item, int line, std::vector<int>* vec) {
1967 if (line == 0) {
1968 _linesToSimplify[item].remove(vec, line, false);
1969 return false;
1970 }
1971 if (_items[item][line].getLength() > _items[item][line - 1].getSpaceLeft(_maxwidth)) {
1972 _linesToSimplify[item].remove(vec, line, false);
1973 return false;
1974 }
1975 _linesToSimplify[item].remove(vec, line, true);
1976 _items[item][line - 1].concatenateLines(_items[item][line]);
1977 _items[item].erase(_items[item].begin() + line);
1978
1979 _linesToSimplify[item].decrementLine(vec, line);
1980 _currentLine--;
1981
1982 return true;
1983}
1984
1985Printer::Printer(std::ostream& os, int width, bool flatZinc, EnvI* env)
1986 : _env(env), _ism(nullptr), _printer(nullptr), _os(os), _width(width), _flatZinc(flatZinc) {}
1987void Printer::init() {
1988 if (_ism == nullptr) {
1989 _ism = new ItemDocumentMapper();
1990 _printer = new PrettyPrinter(_width, 4, true, true);
1991 }
1992}
1993Printer::~Printer() {
1994 delete _printer;
1995 delete _ism;
1996}
1997
1998void Printer::p(Document* d) {
1999 _printer->print(d);
2000 _printer->print(_os);
2001 delete _printer;
2002 _printer = new PrettyPrinter(_width, 4, true, true);
2003}
2004void Printer::p(const Item* i) {
2005 Document* d;
2006 switch (i->iid()) {
2007 case Item::II_INC:
2008 d = ItemDocumentMapper::mapIncludeI(*i->cast<IncludeI>());
2009 break;
2010 case Item::II_VD:
2011 d = ItemDocumentMapper::mapVarDeclI(*i->cast<VarDeclI>());
2012 break;
2013 case Item::II_ASN:
2014 d = ItemDocumentMapper::mapAssignI(*i->cast<AssignI>());
2015 break;
2016 case Item::II_CON:
2017 d = ItemDocumentMapper::mapConstraintI(*i->cast<ConstraintI>());
2018 break;
2019 case Item::II_SOL:
2020 d = ItemDocumentMapper::mapSolveI(*i->cast<SolveI>());
2021 break;
2022 case Item::II_OUT:
2023 d = ItemDocumentMapper::mapOutputI(*i->cast<OutputI>());
2024 break;
2025 case Item::II_FUN:
2026 d = ItemDocumentMapper::mapFunctionI(*i->cast<FunctionI>());
2027 break;
2028 }
2029 p(d);
2030 delete d;
2031}
2032
2033void Printer::print(const Expression* e) {
2034 if (_width == 0) {
2035 PlainPrinter p(_os, _flatZinc, _env);
2036 p.p(e);
2037 } else {
2038 init();
2039 Document* d = expression_to_document(e);
2040 p(d);
2041 delete d;
2042 }
2043}
2044void Printer::print(const Item* i) {
2045 if (_width == 0) {
2046 PlainPrinter p(_os, _flatZinc, _env);
2047 p.p(i);
2048 } else {
2049 init();
2050 p(i);
2051 }
2052}
2053void Printer::print(const Model* m) {
2054 if (_width == 0) {
2055 PlainPrinter p(_os, _flatZinc, _env);
2056 for (auto* i : *m) {
2057 p.p(i);
2058 }
2059 } else {
2060 init();
2061 for (auto* i : *m) {
2062 p(i);
2063 }
2064 }
2065}
2066
2067} // namespace MiniZinc
2068
2069void debugprint(MiniZinc::Expression* e) { std::cerr << *e << "\n"; }
2070void debugprint(MiniZinc::Item* i) { std::cerr << *i; }
2071void debugprint(MiniZinc::Model* m) {
2072 MiniZinc::Printer p(std::cerr, 0);
2073 p.print(m);
2074}
2075void debugprint(const MiniZinc::Location& loc) { std::cerr << loc << std::endl; }