this repo has no description
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 \"" << 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 _os << "output ";
693 p(i->cast<OutputI>()->e());
694 break;
695 case Item::II_FUN: {
696 const FunctionI& fi = *i->cast<FunctionI>();
697 if (fi.ti()->type().isAnn() && fi.e() == nullptr) {
698 _os << "annotation ";
699 } else if (fi.ti()->type() == Type::parbool()) {
700 _os << "test ";
701 } else if (fi.ti()->type() == Type::varbool()) {
702 _os << "predicate ";
703 } else {
704 _os << "function ";
705 p(fi.ti());
706 _os << " : ";
707 }
708 _os << fi.id();
709 if (fi.params().size() > 0) {
710 _os << "(";
711 for (unsigned int j = 0; j < fi.params().size(); j++) {
712 p(fi.params()[j]);
713 if (j < fi.params().size() - 1) {
714 _os << ",";
715 }
716 }
717 _os << ")";
718 }
719 p(fi.ann());
720 if (fi.e() != nullptr) {
721 _os << " = ";
722 p(fi.e());
723 }
724 } break;
725 }
726 _os << ";" << std::endl;
727 }
728};
729
730template <class T>
731class ExpressionMapper {
732protected:
733 T& _t;
734
735public:
736 ExpressionMapper(T& t) : _t(t) {}
737 typename T::ret map(const Expression* e) {
738 switch (e->eid()) {
739 case Expression::E_INTLIT:
740 return _t.mapIntLit(*e->cast<IntLit>());
741 case Expression::E_FLOATLIT:
742 return _t.mapFloatLit(*e->cast<FloatLit>());
743 case Expression::E_SETLIT:
744 return _t.mapSetLit(*e->cast<SetLit>());
745 case Expression::E_BOOLLIT:
746 return _t.mapBoolLit(*e->cast<BoolLit>());
747 case Expression::E_STRINGLIT:
748 return _t.mapStringLit(*e->cast<StringLit>());
749 case Expression::E_ID:
750 return _t.mapId(*e->cast<Id>());
751 case Expression::E_ANON:
752 return _t.mapAnonVar(*e->cast<AnonVar>());
753 case Expression::E_ARRAYLIT:
754 return _t.mapArrayLit(*e->cast<ArrayLit>());
755 case Expression::E_ARRAYACCESS:
756 return _t.mapArrayAccess(*e->cast<ArrayAccess>());
757 case Expression::E_COMP:
758 return _t.mapComprehension(*e->cast<Comprehension>());
759 case Expression::E_ITE:
760 return _t.mapITE(*e->cast<ITE>());
761 case Expression::E_BINOP:
762 return _t.mapBinOp(*e->cast<BinOp>());
763 case Expression::E_UNOP:
764 return _t.mapUnOp(*e->cast<UnOp>());
765 case Expression::E_CALL:
766 return _t.mapCall(*e->cast<Call>());
767 case Expression::E_VARDECL:
768 return _t.mapVarDecl(*e->cast<VarDecl>());
769 case Expression::E_LET:
770 return _t.mapLet(*e->cast<Let>());
771 case Expression::E_TI:
772 return _t.mapTypeInst(*e->cast<TypeInst>());
773 case Expression::E_TIID:
774 return _t.mapTIId(*e->cast<TIId>());
775 default:
776 assert(false);
777 return typename T::ret();
778 break;
779 }
780 }
781};
782
783class Document {
784private:
785 int _level;
786
787public:
788 Document() : _level(0) {}
789 virtual ~Document() {}
790 int getLevel() const { return _level; }
791 // Make this object a child of "d".
792 virtual void setParent(Document* d) { _level = d->_level + 1; }
793};
794
795class BreakPoint : public Document {
796private:
797 bool _dontSimplify;
798
799public:
800 BreakPoint() { _dontSimplify = false; }
801 BreakPoint(bool ds) { _dontSimplify = ds; }
802 ~BreakPoint() override {}
803 void setDontSimplify(bool b) { _dontSimplify = b; }
804 bool getDontSimplify() const { return _dontSimplify; }
805};
806
807class StringDocument : public Document {
808private:
809 std::string _stringDocument;
810
811public:
812 StringDocument() {}
813 ~StringDocument() override {}
814
815 StringDocument(std::string s) : _stringDocument(std::move(s)) {}
816
817 std::string getString() { return _stringDocument; }
818 void setString(std::string s) { _stringDocument = std::move(s); }
819};
820
821class DocumentList : public Document {
822private:
823 std::vector<Document*> _docs;
824 std::string _beginToken;
825 std::string _separator;
826 std::string _endToken;
827 bool _unbreakable;
828 bool _alignment;
829
830public:
831 ~DocumentList() override {
832 std::vector<Document*>::iterator it;
833 for (it = _docs.begin(); it != _docs.end(); it++) {
834 delete *it;
835 }
836 }
837 DocumentList(std::string beginToken = "", std::string separator = "", std::string endToken = "",
838 bool alignment = true);
839
840 void addDocumentToList(Document* d) {
841 _docs.push_back(d);
842 d->setParent(this);
843 }
844
845 void setParent(Document* d) override {
846 Document::setParent(d);
847 std::vector<Document*>::iterator it;
848 for (it = _docs.begin(); it != _docs.end(); it++) {
849 (*it)->setParent(this);
850 }
851 }
852
853 void addStringToList(std::string s) { addDocumentToList(new StringDocument(std::move(s))); }
854
855 void addBreakPoint(bool b = false) { addDocumentToList(new BreakPoint(b)); }
856
857 std::vector<Document*> getDocs() { return _docs; }
858
859 void setList(std::vector<Document*> ld) { _docs = std::move(ld); }
860
861 std::string getBeginToken() { return _beginToken; }
862
863 std::string getEndToken() { return _endToken; }
864
865 std::string getSeparator() { return _separator; }
866
867 bool getUnbreakable() const { return _unbreakable; }
868
869 void setUnbreakable(bool b) { _unbreakable = b; }
870
871 bool getAlignment() const { return _alignment; }
872};
873
874DocumentList::DocumentList(std::string beginToken, std::string separator, std::string endToken,
875 bool alignment) {
876 _beginToken = std::move(beginToken);
877 _separator = std::move(separator);
878 _endToken = std::move(endToken);
879 _alignment = alignment;
880 _unbreakable = false;
881}
882
883class Line {
884private:
885 int _indentation;
886 int _lineLength;
887 std::vector<std::string> _text;
888
889public:
890 Line() : _indentation(0), _lineLength(0), _text(0) {}
891 Line(const Line&) = default;
892 Line(const int indent) : _indentation(indent), _lineLength(0), _text(0) {}
893 Line& operator=(const Line&) = default;
894 bool operator==(const Line& l) { return &l == this; }
895
896 void setIndentation(int i) { _indentation = i; }
897
898 int getLength() const { return _lineLength; }
899 int getIndentation() const { return _indentation; }
900 int getSpaceLeft(int maxwidth) const;
901 void addString(const std::string& s);
902 void concatenateLines(Line& l);
903
904 void print(std::ostream& os) const {
905 for (int i = 0; i < getIndentation(); i++) {
906 os << " ";
907 }
908 std::vector<std::string>::const_iterator it;
909 for (it = _text.begin(); it != _text.end(); it++) {
910 os << (*it);
911 }
912 os << "\n";
913 }
914};
915
916int Line::getSpaceLeft(int maxwidth) const { return maxwidth - _lineLength - _indentation; }
917void Line::addString(const std::string& s) {
918 _lineLength += static_cast<int>(s.size());
919 _text.push_back(s);
920}
921void Line::concatenateLines(Line& l) {
922 _text.insert(_text.end(), l._text.begin(), l._text.end());
923 _lineLength += l._lineLength;
924}
925
926class LinesToSimplify {
927private:
928 std::map<int, std::vector<int> > _lines;
929
930 // (i,j) in parent <=> j can only be simplified if i is simplified
931 std::vector<std::pair<int, int> > _parent;
932 /*
933 * if i can't simplify, remove j and his parents
934 */
935 // mostRecentlyAdded[level] = line of the most recently added
936 std::map<int, int> _mostRecentlyAdded;
937
938public:
939 std::vector<int>* getLinesForPriority(int p) {
940 std::map<int, std::vector<int> >::iterator it;
941 for (it = _lines.begin(); it != _lines.end(); it++) {
942 if (it->first == p) {
943 return &(it->second);
944 }
945 }
946 return nullptr;
947 }
948 void addLine(int p, int l, int par = -1) {
949 if (par == -1) {
950 for (int i = p - 1; i >= 0; i--) {
951 auto it = _mostRecentlyAdded.find(i);
952 if (it != _mostRecentlyAdded.end()) {
953 par = it->second;
954 break;
955 }
956 }
957 }
958 if (par != -1) {
959 _parent.emplace_back(l, par);
960 }
961 _mostRecentlyAdded.insert(std::pair<int, int>(p, l));
962 std::map<int, std::vector<int> >::iterator it;
963 for (it = _lines.begin(); it != _lines.end(); it++) {
964 if (it->first == p) {
965 it->second.push_back(l);
966 return;
967 }
968 }
969 std::vector<int> v;
970 v.push_back(l);
971 _lines.insert(std::pair<int, std::vector<int> >(p, v));
972 }
973 void decrementLine(std::vector<int>* vec, int l) {
974 std::vector<int>::iterator vit;
975 if (vec != nullptr) {
976 for (vit = vec->begin(); vit != vec->end(); vit++) {
977 if (*vit >= l) {
978 *vit = *vit - 1;
979 }
980 }
981 }
982 // Now the map
983 std::map<int, std::vector<int> >::iterator it;
984 for (it = _lines.begin(); it != _lines.end(); it++) {
985 for (vit = it->second.begin(); vit != it->second.end(); vit++) {
986 if (*vit >= l) {
987 *vit = *vit - 1;
988 }
989 }
990 }
991 // And the parent table
992 std::vector<std::pair<int, int> >::iterator vpit;
993 for (vpit = _parent.begin(); vpit != _parent.end(); vpit++) {
994 if (vpit->first >= l) {
995 vpit->first--;
996 }
997 if (vpit->second >= l) {
998 vpit->second--;
999 }
1000 }
1001 }
1002 void remove(LinesToSimplify& lts) {
1003 std::map<int, std::vector<int> >::iterator it;
1004 for (it = lts._lines.begin(); it != lts._lines.end(); it++) {
1005 std::vector<int>::iterator vit;
1006 for (vit = it->second.begin(); vit != it->second.end(); vit++) {
1007 remove(nullptr, *vit, false);
1008 }
1009 }
1010 }
1011 void remove(std::vector<int>* v, int i, bool success = true) {
1012 if (v != nullptr) {
1013 v->erase(std::remove(v->begin(), v->end(), i), v->end());
1014 }
1015 for (auto& line : _lines) {
1016 std::vector<int>& l = line.second;
1017 l.erase(std::remove(l.begin(), l.end(), i), l.end());
1018 }
1019 // Call on its parent
1020 if (!success) {
1021 std::vector<std::pair<int, int> >::iterator vpit;
1022 for (vpit = _parent.begin(); vpit != _parent.end(); vpit++) {
1023 if (vpit->first == i && vpit->second != i && vpit->second != -1) {
1024 remove(v, vpit->second, false);
1025 }
1026 }
1027 }
1028 }
1029 std::vector<int>* getLinesToSimplify() {
1030 auto* vec = new std::vector<int>();
1031 std::map<int, std::vector<int> >::iterator it;
1032 for (it = _lines.begin(); it != _lines.end(); it++) {
1033 std::vector<int>& svec = it->second;
1034 vec->insert(vec->begin(), svec.begin(), svec.end());
1035 }
1036 return vec;
1037 }
1038};
1039
1040Document* expression_to_document(const Expression* e);
1041Document* annotation_to_document(const Annotation& ann);
1042Document* tiexpression_to_document(const Type& type, const Expression* e) {
1043 auto* dl = new DocumentList("", "", "", false);
1044 switch (type.ti()) {
1045 case Type::TI_PAR:
1046 break;
1047 case Type::TI_VAR:
1048 dl->addStringToList("var ");
1049 break;
1050 }
1051 if (type.ot() == Type::OT_OPTIONAL) {
1052 dl->addStringToList("opt ");
1053 }
1054 if (type.st() == Type::ST_SET) {
1055 dl->addStringToList("set of ");
1056 }
1057 if (e == nullptr) {
1058 switch (type.bt()) {
1059 case Type::BT_INT:
1060 dl->addStringToList("int");
1061 break;
1062 case Type::BT_BOOL:
1063 dl->addStringToList("bool");
1064 break;
1065 case Type::BT_FLOAT:
1066 dl->addStringToList("float");
1067 break;
1068 case Type::BT_STRING:
1069 dl->addStringToList("string");
1070 break;
1071 case Type::BT_ANN:
1072 dl->addStringToList("ann");
1073 break;
1074 case Type::BT_BOT:
1075 dl->addStringToList("bot");
1076 break;
1077 case Type::BT_TOP:
1078 dl->addStringToList("top");
1079 break;
1080 case Type::BT_UNKNOWN:
1081 dl->addStringToList("???");
1082 break;
1083 }
1084 } else {
1085 dl->addDocumentToList(expression_to_document(e));
1086 }
1087 return dl;
1088}
1089
1090class ExpressionDocumentMapper {
1091public:
1092 typedef Document* ret;
1093 static ret mapIntLit(const IntLit& il) {
1094 std::ostringstream oss;
1095 oss << il.v();
1096 return new StringDocument(oss.str());
1097 }
1098 static ret mapFloatLit(const FloatLit& fl) {
1099 std::ostringstream oss;
1100 pp_floatval(oss, fl.v());
1101 return new StringDocument(oss.str());
1102 }
1103 static ret mapSetLit(const SetLit& sl) {
1104 DocumentList* dl;
1105 if (sl.isv() != nullptr) {
1106 if (sl.type().bt() == Type::BT_BOOL) {
1107 if (sl.isv()->size() == 0) {
1108 dl = new DocumentList("true..false", "", "");
1109 } else {
1110 if (sl.isv()->min() == 0) {
1111 if (sl.isv()->max() == 0) {
1112 dl = new DocumentList("{false}", "", "");
1113 } else {
1114 dl = new DocumentList("{false,true}", "", "");
1115 }
1116 } else {
1117 dl = new DocumentList("{true}", "", "");
1118 }
1119 }
1120 } else {
1121 if (sl.isv()->size() == 0) {
1122 dl = new DocumentList("1..0", "", "");
1123 } else if (sl.isv()->size() == 1) {
1124 dl = new DocumentList("", "..", "");
1125 {
1126 std::ostringstream oss;
1127 oss << sl.isv()->min(0);
1128 dl->addDocumentToList(new StringDocument(oss.str()));
1129 }
1130 {
1131 std::ostringstream oss;
1132 oss << sl.isv()->max(0);
1133 dl->addDocumentToList(new StringDocument(oss.str()));
1134 }
1135 } else {
1136 dl = new DocumentList("{", ", ", "}", true);
1137 IntSetRanges isr(sl.isv());
1138 for (Ranges::ToValues<IntSetRanges> isv(isr); isv(); ++isv) {
1139 std::ostringstream oss;
1140 oss << isv.val();
1141 dl->addDocumentToList(new StringDocument(oss.str()));
1142 }
1143 }
1144 }
1145 } else if (sl.fsv() != nullptr) {
1146 if (sl.fsv()->size() == 0) {
1147 dl = new DocumentList("1.0..0.0", "", "");
1148 } else if (sl.fsv()->size() == 1) {
1149 dl = new DocumentList("", "..", "");
1150 {
1151 std::ostringstream oss;
1152 pp_floatval(oss, sl.fsv()->min(0));
1153 dl->addDocumentToList(new StringDocument(oss.str()));
1154 }
1155 {
1156 std::ostringstream oss;
1157 pp_floatval(oss, sl.fsv()->max(0));
1158 dl->addDocumentToList(new StringDocument(oss.str()));
1159 }
1160 } else {
1161 dl = new DocumentList("", " union ", "", true);
1162 FloatSetRanges fsr(sl.fsv());
1163 for (; fsr(); ++fsr) {
1164 std::ostringstream oss;
1165 pp_floatval(oss, fsr.min());
1166 oss << "..";
1167 pp_floatval(oss, fsr.max());
1168 dl->addDocumentToList(new StringDocument(oss.str()));
1169 }
1170 }
1171
1172 } else {
1173 dl = new DocumentList("{", ", ", "}", true);
1174 for (unsigned int i = 0; i < sl.v().size(); i++) {
1175 dl->addDocumentToList(expression_to_document((sl.v()[i])));
1176 }
1177 }
1178 return dl;
1179 }
1180 static ret mapBoolLit(const BoolLit& bl) {
1181 return new StringDocument(std::string(bl.v() ? "true" : "false"));
1182 }
1183 static ret mapStringLit(const StringLit& sl) {
1184 std::ostringstream oss;
1185 oss << "\"" << Printer::escapeStringLit(sl.v()) << "\"";
1186 return new StringDocument(oss.str());
1187 }
1188 static ret mapId(const Id& id) {
1189 if (&id == constants().absent) {
1190 return new StringDocument("<>");
1191 }
1192 if (id.idn() == -1) {
1193 return new StringDocument(std::string(id.v().c_str(), id.v().size()));
1194 }
1195 std::ostringstream oss;
1196 oss << "X_INTRODUCED_" << id.idn() << "_";
1197 return new StringDocument(oss.str());
1198 }
1199 static ret mapTIId(const TIId& id) {
1200 std::ostringstream ss;
1201 ss << "$" << id.v();
1202 return new StringDocument(ss.str());
1203 }
1204 static ret mapAnonVar(const AnonVar& /*v*/) { return new StringDocument("_"); }
1205 static ret mapArrayLit(const ArrayLit& al) {
1206 /// TODO: test multi-dimensional arrays handling
1207 DocumentList* dl;
1208 unsigned int n = al.dims();
1209 if (n == 1 && al.min(0) == 1) {
1210 dl = new DocumentList("[", ", ", "]");
1211 for (unsigned int i = 0; i < al.size(); i++) {
1212 dl->addDocumentToList(expression_to_document(al[i]));
1213 }
1214 } else if (n == 2 && al.min(0) == 1 && al.min(1) == 1) {
1215 dl = new DocumentList("[| ", " | ", " |]");
1216 for (int i = 0; i < al.max(0); i++) {
1217 auto* row = new DocumentList("", ", ", "");
1218 for (int j = 0; j < al.max(1); j++) {
1219 row->addDocumentToList(expression_to_document(al[i * al.max(1) + j]));
1220 }
1221 dl->addDocumentToList(row);
1222 if (i != al.max(0) - 1) {
1223 dl->addBreakPoint(true); // dont simplify
1224 }
1225 }
1226 } else {
1227 dl = new DocumentList("", "", "");
1228 std::stringstream oss;
1229 oss << "array" << n << "d";
1230 dl->addStringToList(oss.str());
1231 auto* args = new DocumentList("(", ", ", ")");
1232
1233 for (int i = 0; i < al.dims(); i++) {
1234 oss.str("");
1235 oss << al.min(i) << ".." << al.max(i);
1236 args->addStringToList(oss.str());
1237 }
1238 auto* array = new DocumentList("[", ", ", "]");
1239 for (unsigned int i = 0; i < al.size(); i++) {
1240 array->addDocumentToList(expression_to_document(al[i]));
1241 }
1242 args->addDocumentToList(array);
1243 dl->addDocumentToList(args);
1244 }
1245 return dl;
1246 }
1247 static ret mapArrayAccess(const ArrayAccess& aa) {
1248 auto* dl = new DocumentList("", "", "");
1249
1250 dl->addDocumentToList(expression_to_document(aa.v()));
1251 auto* args = new DocumentList("[", ", ", "]");
1252 for (unsigned int i = 0; i < aa.idx().size(); i++) {
1253 args->addDocumentToList(expression_to_document(aa.idx()[i]));
1254 }
1255 dl->addDocumentToList(args);
1256 return dl;
1257 }
1258 static ret mapComprehension(const Comprehension& c) {
1259 std::ostringstream oss;
1260 DocumentList* dl;
1261 if (c.set()) {
1262 dl = new DocumentList("{ ", " | ", " }");
1263 } else {
1264 dl = new DocumentList("[ ", " | ", " ]");
1265 }
1266 dl->addDocumentToList(expression_to_document(c.e()));
1267 auto* head = new DocumentList("", " ", "");
1268 auto* generators = new DocumentList("", ", ", "");
1269 for (int i = 0; i < c.numberOfGenerators(); i++) {
1270 auto* gen = new DocumentList("", "", "");
1271 auto* idents = new DocumentList("", ", ", "");
1272 for (int j = 0; j < c.numberOfDecls(i); j++) {
1273 std::ostringstream ss;
1274 Id* ident = c.decl(i, j)->id();
1275 if (ident->idn() == -1) {
1276 ss << ident->v();
1277 } else {
1278 ss << "X_INTRODUCED_" << ident->idn() << "_";
1279 }
1280 idents->addStringToList(ss.str());
1281 }
1282 gen->addDocumentToList(idents);
1283 if (c.in(i) == nullptr) {
1284 gen->addStringToList(" = ");
1285 gen->addDocumentToList(expression_to_document(c.where(i)));
1286 } else {
1287 gen->addStringToList(" in ");
1288 gen->addDocumentToList(expression_to_document(c.in(i)));
1289 if (c.where(i) != nullptr) {
1290 gen->addStringToList(" where ");
1291 gen->addDocumentToList(expression_to_document(c.where(i)));
1292 }
1293 }
1294 generators->addDocumentToList(gen);
1295 }
1296 head->addDocumentToList(generators);
1297 dl->addDocumentToList(head);
1298
1299 return dl;
1300 }
1301 static ret mapITE(const ITE& ite) {
1302 auto* dl = new DocumentList("", "", "");
1303 for (int i = 0; i < ite.size(); i++) {
1304 std::string beg = (i == 0 ? "if " : " elseif ");
1305 dl->addStringToList(beg);
1306 dl->addDocumentToList(expression_to_document(ite.ifExpr(i)));
1307 dl->addStringToList(" then ");
1308
1309 auto* ifdoc = new DocumentList("", "", "", false);
1310 ifdoc->addBreakPoint();
1311 ifdoc->addDocumentToList(expression_to_document(ite.thenExpr(i)));
1312 dl->addDocumentToList(ifdoc);
1313 dl->addStringToList(" ");
1314 }
1315 dl->addBreakPoint();
1316 dl->addStringToList("else ");
1317
1318 auto* elsedoc = new DocumentList("", "", "", false);
1319 elsedoc->addBreakPoint();
1320 elsedoc->addDocumentToList(expression_to_document(ite.elseExpr()));
1321 dl->addDocumentToList(elsedoc);
1322 dl->addStringToList(" ");
1323 dl->addBreakPoint();
1324 dl->addStringToList("endif");
1325
1326 return dl;
1327 }
1328 static ret mapBinOp(const BinOp& bo) {
1329 Parentheses ps = need_parentheses(&bo, bo.lhs(), bo.rhs());
1330 DocumentList* opLeft;
1331 DocumentList* dl;
1332 DocumentList* opRight;
1333 bool linebreak = false;
1334 if ((ps & PN_LEFT) != 0) {
1335 opLeft = new DocumentList("(", " ", ")");
1336 } else {
1337 opLeft = new DocumentList("", " ", "");
1338 }
1339 opLeft->addDocumentToList(expression_to_document(bo.lhs()));
1340 std::string op;
1341 switch (bo.op()) {
1342 case BOT_PLUS:
1343 op = "+";
1344 break;
1345 case BOT_MINUS:
1346 op = "-";
1347 break;
1348 case BOT_MULT:
1349 op = "*";
1350 break;
1351 case BOT_POW:
1352 op = "^";
1353 break;
1354 case BOT_DIV:
1355 op = "/";
1356 break;
1357 case BOT_IDIV:
1358 op = " div ";
1359 break;
1360 case BOT_MOD:
1361 op = " mod ";
1362 break;
1363 case BOT_LE:
1364 op = " < ";
1365 break;
1366 case BOT_LQ:
1367 op = "<=";
1368 break;
1369 case BOT_GR:
1370 op = " > ";
1371 break;
1372 case BOT_GQ:
1373 op = ">=";
1374 break;
1375 case BOT_EQ:
1376 op = "==";
1377 break;
1378 case BOT_NQ:
1379 op = "!=";
1380 break;
1381 case BOT_IN:
1382 op = " in ";
1383 break;
1384 case BOT_SUBSET:
1385 op = " subset ";
1386 break;
1387 case BOT_SUPERSET:
1388 op = " superset ";
1389 break;
1390 case BOT_UNION:
1391 op = " union ";
1392 break;
1393 case BOT_DIFF:
1394 op = " diff ";
1395 break;
1396 case BOT_SYMDIFF:
1397 op = " symdiff ";
1398 break;
1399 case BOT_INTERSECT:
1400 op = " intersect ";
1401 break;
1402 case BOT_PLUSPLUS:
1403 op = "++";
1404 linebreak = true;
1405 break;
1406 case BOT_EQUIV:
1407 op = " <-> ";
1408 break;
1409 case BOT_IMPL:
1410 op = " -> ";
1411 break;
1412 case BOT_RIMPL:
1413 op = " <- ";
1414 break;
1415 case BOT_OR:
1416 op = " \\/ ";
1417 linebreak = true;
1418 break;
1419 case BOT_AND:
1420 op = " /\\ ";
1421 linebreak = true;
1422 break;
1423 case BOT_XOR:
1424 op = " xor ";
1425 break;
1426 case BOT_DOTDOT:
1427 op = "..";
1428 break;
1429 default:
1430 assert(false);
1431 break;
1432 }
1433 dl = new DocumentList("", op, "");
1434
1435 if ((ps & PN_RIGHT) != 0) {
1436 opRight = new DocumentList("(", " ", ")");
1437 } else {
1438 opRight = new DocumentList("", "", "");
1439 }
1440 opRight->addDocumentToList(expression_to_document(bo.rhs()));
1441 dl->addDocumentToList(opLeft);
1442 if (linebreak) {
1443 dl->addBreakPoint();
1444 }
1445 dl->addDocumentToList(opRight);
1446
1447 return dl;
1448 }
1449 static ret mapUnOp(const UnOp& uo) {
1450 auto* dl = new DocumentList("", "", "");
1451 std::string op;
1452 switch (uo.op()) {
1453 case UOT_NOT:
1454 op = "not ";
1455 break;
1456 case UOT_PLUS:
1457 op = "+";
1458 break;
1459 case UOT_MINUS:
1460 op = "-";
1461 break;
1462 default:
1463 assert(false);
1464 break;
1465 }
1466 dl->addStringToList(op);
1467 DocumentList* unop;
1468 bool needParen = (uo.e()->isa<BinOp>() || uo.e()->isa<UnOp>());
1469 if (needParen) {
1470 unop = new DocumentList("(", " ", ")");
1471 } else {
1472 unop = new DocumentList("", " ", "");
1473 }
1474
1475 unop->addDocumentToList(expression_to_document(uo.e()));
1476 dl->addDocumentToList(unop);
1477 return dl;
1478 }
1479 static ret mapCall(const Call& c) {
1480 if (c.argCount() == 1) {
1481 /*
1482 * if we have only one argument, and this is an array comprehension,
1483 * we convert it into the following syntax
1484 * forall (f(i,j) | i in 1..10)
1485 * -->
1486 * forall (i in 1..10) (f(i,j))
1487 */
1488
1489 const Expression* e = c.arg(0);
1490 if (e->isa<Comprehension>()) {
1491 const auto* com = e->cast<Comprehension>();
1492 if (!com->set()) {
1493 auto* dl = new DocumentList("", " ", "");
1494 dl->addStringToList(std::string(c.id().c_str(), c.id().size()));
1495 auto* args = new DocumentList("", " ", "", false);
1496 auto* generators = new DocumentList("", ", ", "");
1497
1498 for (int i = 0; i < com->numberOfGenerators(); i++) {
1499 auto* gen = new DocumentList("", "", "");
1500 auto* idents = new DocumentList("", ", ", "");
1501 for (int j = 0; j < com->numberOfDecls(i); j++) {
1502 idents->addStringToList(std::string(com->decl(i, j)->id()->v().c_str(),
1503 com->decl(i, j)->id()->v().size()));
1504 }
1505 gen->addDocumentToList(idents);
1506 if (com->in(i) == nullptr) {
1507 gen->addStringToList(" = ");
1508 gen->addDocumentToList(expression_to_document(com->where(i)));
1509 } else {
1510 gen->addStringToList(" in ");
1511 gen->addDocumentToList(expression_to_document(com->in(i)));
1512 if (com->where(i) != nullptr) {
1513 gen->addStringToList(" where ");
1514 gen->addDocumentToList(expression_to_document(com->where(i)));
1515 }
1516 }
1517 generators->addDocumentToList(gen);
1518 }
1519
1520 args->addStringToList("(");
1521 args->addDocumentToList(generators);
1522 args->addStringToList(")");
1523
1524 args->addStringToList("(");
1525 args->addBreakPoint();
1526 args->addDocumentToList(expression_to_document(com->e()));
1527
1528 dl->addDocumentToList(args);
1529 dl->addBreakPoint();
1530 dl->addStringToList(")");
1531
1532 return dl;
1533 }
1534 }
1535 }
1536 std::ostringstream beg;
1537 beg << c.id() << "(";
1538 auto* dl = new DocumentList(beg.str(), ", ", ")");
1539 for (unsigned int i = 0; i < c.argCount(); i++) {
1540 dl->addDocumentToList(expression_to_document(c.arg(i)));
1541 }
1542 return dl;
1543 }
1544 static ret mapVarDecl(const VarDecl& vd) {
1545 std::ostringstream oss;
1546 auto* dl = new DocumentList("", "", "");
1547 dl->addDocumentToList(expression_to_document(vd.ti()));
1548 if (vd.id()->idn() == -1) {
1549 if (vd.id()->v().size() != 0) {
1550 oss << ": " << vd.id()->v().c_str();
1551 }
1552 } else {
1553 oss << ": X_INTRODUCED_" << vd.id()->idn() << "_";
1554 }
1555 dl->addStringToList(oss.str());
1556
1557 if (vd.introduced()) {
1558 dl->addStringToList(" ::var_is_introduced ");
1559 }
1560 if (!vd.ann().isEmpty()) {
1561 dl->addDocumentToList(annotation_to_document(vd.ann()));
1562 }
1563 if (vd.e() != nullptr) {
1564 dl->addStringToList(" = ");
1565 dl->addDocumentToList(expression_to_document(vd.e()));
1566 }
1567 return dl;
1568 }
1569 static ret mapLet(const Let& l) {
1570 auto* letin = new DocumentList("", "", "", false);
1571 auto* lets = new DocumentList("", " ", "", true);
1572 auto* inexpr = new DocumentList("", "", "");
1573 bool ds = l.let().size() > 1;
1574
1575 for (unsigned int i = 0; i < l.let().size(); i++) {
1576 if (i != 0) {
1577 lets->addBreakPoint(ds);
1578 }
1579 auto* exp = new DocumentList("", " ", ",");
1580 const Expression* li = l.let()[i];
1581 if (!li->isa<VarDecl>()) {
1582 exp->addStringToList("constraint");
1583 }
1584 exp->addDocumentToList(expression_to_document(li));
1585 lets->addDocumentToList(exp);
1586 }
1587
1588 inexpr->addDocumentToList(expression_to_document(l.in()));
1589 letin->addBreakPoint(ds);
1590 letin->addDocumentToList(lets);
1591
1592 auto* letin2 = new DocumentList("", "", "", false);
1593
1594 letin2->addBreakPoint();
1595 letin2->addDocumentToList(inexpr);
1596
1597 auto* dl = new DocumentList("", "", "");
1598 dl->addStringToList("let {");
1599 dl->addDocumentToList(letin);
1600 dl->addBreakPoint(ds);
1601 dl->addStringToList("} in (");
1602 dl->addDocumentToList(letin2);
1603 // dl->addBreakPoint();
1604 dl->addStringToList(")");
1605 return dl;
1606 }
1607 static ret mapTypeInst(const TypeInst& ti) {
1608 auto* dl = new DocumentList("", "", "");
1609 if (ti.isarray()) {
1610 dl->addStringToList("array [");
1611 auto* ran = new DocumentList("", ", ", "");
1612 for (unsigned int i = 0; i < ti.ranges().size(); i++) {
1613 ran->addDocumentToList(tiexpression_to_document(Type::parint(), ti.ranges()[i]));
1614 }
1615 dl->addDocumentToList(ran);
1616 dl->addStringToList("] of ");
1617 }
1618 dl->addDocumentToList(tiexpression_to_document(ti.type(), ti.domain()));
1619 return dl;
1620 }
1621};
1622
1623Document* annotation_to_document(const Annotation& ann) {
1624 auto* dl = new DocumentList(" :: ", " :: ", "");
1625 for (ExpressionSetIter it = ann.begin(); it != ann.end(); ++it) {
1626 dl->addDocumentToList(expression_to_document(*it));
1627 }
1628 return dl;
1629}
1630
1631Document* expression_to_document(const Expression* e) {
1632 if (e == nullptr) {
1633 return new StringDocument("NULL");
1634 }
1635 ExpressionDocumentMapper esm;
1636 ExpressionMapper<ExpressionDocumentMapper> em(esm);
1637 auto* dl = new DocumentList("", "", "");
1638 Document* s = em.map(e);
1639 dl->addDocumentToList(s);
1640 if (!e->isa<VarDecl>() && !e->ann().isEmpty()) {
1641 dl->addDocumentToList(annotation_to_document(e->ann()));
1642 }
1643 return dl;
1644}
1645
1646class ItemDocumentMapper {
1647public:
1648 typedef Document* ret;
1649 static ret mapIncludeI(const IncludeI& ii) {
1650 std::ostringstream oss;
1651 oss << "include \"" << ii.f() << "\";";
1652 return new StringDocument(oss.str());
1653 }
1654 static ret mapVarDeclI(const VarDeclI& vi) {
1655 auto* dl = new DocumentList("", " ", ";");
1656 dl->addDocumentToList(expression_to_document(vi.e()));
1657 return dl;
1658 }
1659 static ret mapAssignI(const AssignI& ai) {
1660 auto* dl = new DocumentList("", " = ", ";");
1661 dl->addStringToList(std::string(ai.id().c_str(), ai.id().size()));
1662 dl->addDocumentToList(expression_to_document(ai.e()));
1663 return dl;
1664 }
1665 static ret mapConstraintI(const ConstraintI& ci) {
1666 auto* dl = new DocumentList("constraint ", " ", ";");
1667 dl->addDocumentToList(expression_to_document(ci.e()));
1668 return dl;
1669 }
1670 static ret mapSolveI(const SolveI& si) {
1671 auto* dl = new DocumentList("", "", ";");
1672 dl->addStringToList("solve");
1673 if (!si.ann().isEmpty()) {
1674 dl->addDocumentToList(annotation_to_document(si.ann()));
1675 }
1676 switch (si.st()) {
1677 case SolveI::ST_SAT:
1678 dl->addStringToList(" satisfy");
1679 break;
1680 case SolveI::ST_MIN:
1681 dl->addStringToList(" minimize ");
1682 dl->addDocumentToList(expression_to_document(si.e()));
1683 break;
1684 case SolveI::ST_MAX:
1685 dl->addStringToList(" maximize ");
1686 dl->addDocumentToList(expression_to_document(si.e()));
1687 break;
1688 }
1689 return dl;
1690 }
1691 static ret mapOutputI(const OutputI& oi) {
1692 auto* dl = new DocumentList("output ", " ", ";");
1693 dl->addDocumentToList(expression_to_document(oi.e()));
1694 return dl;
1695 }
1696 static ret mapFunctionI(const FunctionI& fi) {
1697 DocumentList* dl;
1698 if (fi.ti()->type().isAnn() && fi.e() == nullptr) {
1699 dl = new DocumentList("annotation ", " ", ";", false);
1700 } else if (fi.ti()->type() == Type::parbool()) {
1701 dl = new DocumentList("test ", "", ";", false);
1702 } else if (fi.ti()->type() == Type::varbool()) {
1703 dl = new DocumentList("predicate ", "", ";", false);
1704 } else {
1705 dl = new DocumentList("function ", "", ";", false);
1706 dl->addDocumentToList(expression_to_document(fi.ti()));
1707 dl->addStringToList(": ");
1708 }
1709 dl->addStringToList(std::string(fi.id().c_str(), fi.id().size()));
1710 if (fi.params().size() > 0) {
1711 auto* params = new DocumentList("(", ", ", ")");
1712 for (unsigned int i = 0; i < fi.params().size(); i++) {
1713 auto* par = new DocumentList("", "", "");
1714 par->setUnbreakable(true);
1715 par->addDocumentToList(expression_to_document(fi.params()[i]));
1716 params->addDocumentToList(par);
1717 }
1718 dl->addDocumentToList(params);
1719 }
1720 if (!fi.ann().isEmpty()) {
1721 dl->addDocumentToList(annotation_to_document(fi.ann()));
1722 }
1723 if (fi.e() != nullptr) {
1724 dl->addStringToList(" = ");
1725 dl->addBreakPoint();
1726 dl->addDocumentToList(expression_to_document(fi.e()));
1727 }
1728
1729 return dl;
1730 }
1731};
1732
1733class PrettyPrinter {
1734public:
1735 /*
1736 * \brief Constructor for class Pretty Printer
1737 * \param maxwidth (default 80) : number of rows
1738 * \param indentationBase : spaces that represent the atomic number of spaces
1739 * \param sim : whether we want to simplify the result
1740 * \param deepSimp : whether we want to simplify at each breakpoint or not
1741 */
1742 PrettyPrinter(int _maxwidth = 80, int _indentationBase = 4, bool sim = false,
1743 bool deepSimp = false);
1744
1745 void print(Document* d);
1746 void print(std::ostream& os) const;
1747
1748private:
1749 int _maxwidth;
1750 int _indentationBase;
1751 int _currentLine;
1752 int _currentItem;
1753 std::vector<std::vector<Line> > _items;
1754 std::vector<LinesToSimplify> _linesToSimplify;
1755 std::vector<LinesToSimplify> _linesNotToSimplify;
1756 bool _simp;
1757 bool _deeplySimp;
1758
1759 void addItem();
1760
1761 void addLine(int indentation, bool bp = false, bool simpl = false, int level = 0);
1762 static std::string printSpaces(int n);
1763 const std::vector<Line>& getCurrentItemLines() const;
1764
1765 void printDocument(Document* d, bool alignment, int alignmentCol, const std::string& before = "",
1766 const std::string& after = "");
1767 void printDocList(DocumentList* d, int alignmentCol, const std::string& before = "",
1768 const std::string& after = "");
1769 void printStringDoc(StringDocument* d, bool alignment, int alignmentCol,
1770 const std::string& before = "", const std::string& after = "");
1771 void printString(const std::string& s, bool alignment, int alignmentCol);
1772 bool simplify(int item, int line, std::vector<int>* vec);
1773 void simplifyItem(int item);
1774};
1775
1776void PrettyPrinter::print(Document* d) {
1777 addItem();
1778 addLine(0);
1779 printDocument(d, true, 0);
1780 if (_simp) {
1781 simplifyItem(_currentItem);
1782 }
1783}
1784
1785PrettyPrinter::PrettyPrinter(int maxwidth, int indentationBase, bool sim, bool deepsim) {
1786 _maxwidth = maxwidth;
1787 _indentationBase = indentationBase;
1788 _currentLine = -1;
1789 _currentItem = -1;
1790
1791 _simp = sim;
1792 _deeplySimp = deepsim;
1793}
1794const std::vector<Line>& PrettyPrinter::getCurrentItemLines() const { return _items[_currentItem]; }
1795
1796void PrettyPrinter::addLine(int indentation, bool bp, bool simpl, int level) {
1797 _items[_currentItem].push_back(Line(indentation));
1798 _currentLine++;
1799 if (bp && _deeplySimp) {
1800 _linesToSimplify[_currentItem].addLine(level, _currentLine);
1801 if (!simpl) {
1802 _linesNotToSimplify[_currentItem].addLine(0, _currentLine);
1803 }
1804 }
1805}
1806void PrettyPrinter::addItem() {
1807 _items.emplace_back();
1808 _linesToSimplify.emplace_back();
1809 _linesNotToSimplify.emplace_back();
1810 _currentItem++;
1811 _currentLine = -1;
1812}
1813
1814void PrettyPrinter::print(std::ostream& os) const {
1815 std::vector<Line>::const_iterator it;
1816 int nItems = static_cast<int>(_items.size());
1817 for (int item = 0; item < nItems; item++) {
1818 for (it = _items[item].begin(); it != _items[item].end(); it++) {
1819 it->print(os);
1820 }
1821 // os << std::endl;
1822 }
1823}
1824std::string PrettyPrinter::printSpaces(int n) {
1825 std::string result;
1826 for (int i = 0; i < n; i++) {
1827 result += " ";
1828 }
1829 return result;
1830}
1831
1832void PrettyPrinter::printDocument(Document* d, bool alignment, int alignmentCol,
1833 const std::string& before, const std::string& after) {
1834 if (auto* dl = dynamic_cast<DocumentList*>(d)) {
1835 printDocList(dl, alignmentCol, before, after);
1836 } else if (auto* sd = dynamic_cast<StringDocument*>(d)) {
1837 printStringDoc(sd, alignment, alignmentCol, before, after);
1838 } else if (auto* bp = dynamic_cast<BreakPoint*>(d)) {
1839 printString(before, alignment, alignmentCol);
1840 addLine(alignmentCol, _deeplySimp, !bp->getDontSimplify(), d->getLevel());
1841 printString(after, alignment, alignmentCol);
1842 } else {
1843 throw InternalError("PrettyPrinter::print : Wrong type of document");
1844 }
1845}
1846
1847void PrettyPrinter::printStringDoc(StringDocument* d, bool alignment, int alignmentCol,
1848 const std::string& before, const std::string& after) {
1849 std::string s;
1850 if (d != nullptr) {
1851 s = d->getString();
1852 }
1853 s = before + s + after;
1854 printString(s, alignment, alignmentCol);
1855}
1856
1857void PrettyPrinter::printString(const std::string& s, bool alignment, int alignmentCol) {
1858 Line& l = _items[_currentItem][_currentLine];
1859 int size = static_cast<int>(s.size());
1860 if (size <= l.getSpaceLeft(_maxwidth)) {
1861 l.addString(s);
1862 } else {
1863 int col = alignment && _maxwidth - alignmentCol >= size ? alignmentCol : _indentationBase;
1864 addLine(col);
1865 _items[_currentItem][_currentLine].addString(s);
1866 }
1867}
1868
1869void PrettyPrinter::printDocList(DocumentList* d, int alignmentCol, const std::string& super_before,
1870 const std::string& super_after) {
1871 std::vector<Document*> ld = d->getDocs();
1872 std::string beginToken = d->getBeginToken();
1873 std::string separator = d->getSeparator();
1874 std::string endToken = d->getEndToken();
1875 bool _alignment = d->getAlignment();
1876 if (d->getUnbreakable()) {
1877 addLine(alignmentCol);
1878 }
1879 int currentCol = _items[_currentItem][_currentLine].getIndentation() +
1880 _items[_currentItem][_currentLine].getLength();
1881 int newAlignmentCol =
1882 _alignment ? currentCol + static_cast<int>(beginToken.size()) : alignmentCol;
1883 int vectorSize = static_cast<int>(ld.size());
1884 int lastVisibleElementIndex;
1885 for (int i = 0; i < vectorSize; i++) {
1886 if (dynamic_cast<BreakPoint*>(ld[i]) == nullptr) {
1887 lastVisibleElementIndex = i;
1888 }
1889 }
1890 if (vectorSize == 0) {
1891 printStringDoc(nullptr, true, newAlignmentCol, super_before + beginToken,
1892 endToken + super_after);
1893 }
1894 for (int i = 0; i < vectorSize; i++) {
1895 Document* subdoc = ld[i];
1896 bool bp = false;
1897 if (dynamic_cast<BreakPoint*>(subdoc) != nullptr) {
1898 if (!_alignment) {
1899 newAlignmentCol += _indentationBase;
1900 }
1901 bp = true;
1902 }
1903 std::string af;
1904 std::string be;
1905 if (i != vectorSize - 1) {
1906 if (bp || lastVisibleElementIndex <= i) {
1907 af = "";
1908 } else {
1909 af = separator;
1910 }
1911 } else {
1912 af = endToken + super_after;
1913 }
1914 if (i == 0) {
1915 be = super_before + beginToken;
1916 } else {
1917 be = "";
1918 }
1919 printDocument(subdoc, _alignment, newAlignmentCol, be, af);
1920 }
1921 if (d->getUnbreakable()) {
1922 simplify(_currentItem, _currentLine, nullptr);
1923 }
1924}
1925void PrettyPrinter::simplifyItem(int item) {
1926 _linesToSimplify[item].remove(_linesNotToSimplify[item]);
1927 std::vector<int>* vec = (_linesToSimplify[item].getLinesToSimplify());
1928 while (!vec->empty()) {
1929 if (!simplify(item, (*vec)[0], vec)) {
1930 break;
1931 }
1932 }
1933 delete vec;
1934}
1935
1936bool PrettyPrinter::simplify(int item, int line, std::vector<int>* vec) {
1937 if (line == 0) {
1938 _linesToSimplify[item].remove(vec, line, false);
1939 return false;
1940 }
1941 if (_items[item][line].getLength() > _items[item][line - 1].getSpaceLeft(_maxwidth)) {
1942 _linesToSimplify[item].remove(vec, line, false);
1943 return false;
1944 }
1945 _linesToSimplify[item].remove(vec, line, true);
1946 _items[item][line - 1].concatenateLines(_items[item][line]);
1947 _items[item].erase(_items[item].begin() + line);
1948
1949 _linesToSimplify[item].decrementLine(vec, line);
1950 _currentLine--;
1951
1952 return true;
1953}
1954
1955Printer::Printer(std::ostream& os, int width, bool flatZinc, EnvI* env)
1956 : _env(env), _ism(nullptr), _printer(nullptr), _os(os), _width(width), _flatZinc(flatZinc) {}
1957void Printer::init() {
1958 if (_ism == nullptr) {
1959 _ism = new ItemDocumentMapper();
1960 _printer = new PrettyPrinter(_width, 4, true, true);
1961 }
1962}
1963Printer::~Printer() {
1964 delete _printer;
1965 delete _ism;
1966}
1967
1968void Printer::p(Document* d) {
1969 _printer->print(d);
1970 _printer->print(_os);
1971 delete _printer;
1972 _printer = new PrettyPrinter(_width, 4, true, true);
1973}
1974void Printer::p(const Item* i) {
1975 Document* d;
1976 switch (i->iid()) {
1977 case Item::II_INC:
1978 d = ItemDocumentMapper::mapIncludeI(*i->cast<IncludeI>());
1979 break;
1980 case Item::II_VD:
1981 d = ItemDocumentMapper::mapVarDeclI(*i->cast<VarDeclI>());
1982 break;
1983 case Item::II_ASN:
1984 d = ItemDocumentMapper::mapAssignI(*i->cast<AssignI>());
1985 break;
1986 case Item::II_CON:
1987 d = ItemDocumentMapper::mapConstraintI(*i->cast<ConstraintI>());
1988 break;
1989 case Item::II_SOL:
1990 d = ItemDocumentMapper::mapSolveI(*i->cast<SolveI>());
1991 break;
1992 case Item::II_OUT:
1993 d = ItemDocumentMapper::mapOutputI(*i->cast<OutputI>());
1994 break;
1995 case Item::II_FUN:
1996 d = ItemDocumentMapper::mapFunctionI(*i->cast<FunctionI>());
1997 break;
1998 }
1999 p(d);
2000 delete d;
2001}
2002
2003void Printer::print(const Expression* e) {
2004 if (_width == 0) {
2005 PlainPrinter p(_os, _flatZinc, _env);
2006 p.p(e);
2007 } else {
2008 init();
2009 Document* d = expression_to_document(e);
2010 p(d);
2011 delete d;
2012 }
2013}
2014void Printer::print(const Item* i) {
2015 if (_width == 0) {
2016 PlainPrinter p(_os, _flatZinc, _env);
2017 p.p(i);
2018 } else {
2019 init();
2020 p(i);
2021 }
2022}
2023void Printer::print(const Model* m) {
2024 if (_width == 0) {
2025 PlainPrinter p(_os, _flatZinc, _env);
2026 for (auto* i : *m) {
2027 p.p(i);
2028 }
2029 } else {
2030 init();
2031 for (auto* i : *m) {
2032 p(i);
2033 }
2034 }
2035}
2036
2037} // namespace MiniZinc
2038
2039void debugprint(MiniZinc::Expression* e) { std::cerr << *e << "\n"; }
2040void debugprint(MiniZinc::Item* i) { std::cerr << *i; }
2041void debugprint(MiniZinc::Model* m) {
2042 MiniZinc::Printer p(std::cerr, 0);
2043 p.print(m);
2044}
2045void debugprint(const MiniZinc::Location& loc) { std::cerr << loc << std::endl; }