this repo has no description
at develop 131 kB view raw
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3/* 4 * Main authors: 5 * Guido Tack <guido.tack@monash.edu> 6 */ 7 8/* This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 11 12#include <minizinc/astexception.hh> 13#include <minizinc/astiterator.hh> 14#include <minizinc/flatten_internal.hh> 15#include <minizinc/hash.hh> 16#include <minizinc/prettyprinter.hh> 17#include <minizinc/typecheck.hh> 18 19#include <sstream> 20#include <string> 21#include <unordered_map> 22#include <utility> 23 24namespace MiniZinc { 25 26Scopes::Scopes() { _s.emplace_back(ST_TOPLEVEL); } 27 28void Scopes::add(EnvI& env, VarDecl* vd) { 29 if (!_s.back().toplevel() && vd->ti()->isEnum() && (vd->e() != nullptr)) { 30 throw TypeError(env, vd->loc(), "enums are only allowed at top level"); 31 } 32 if (vd->id()->idn() == -1 && vd->id()->v() == "") { 33 return; 34 } 35 // If the current scope is ST_INNER, check if vd shadows another 36 // declaration from the same functional or toplevel scope 37 if (_s.back().st == ST_INNER) { 38 assert(_s.size() > 1); // at least toplevel scope above 39 for (int i = static_cast<int>(_s.size()) - 2; i >= 0; i--) { 40 auto previous = _s[i].m.find(vd->id()); 41 if (previous != _s[i].m.end()) { 42 std::ostringstream oss; 43 ASTString warnloc_f = vd->loc().filename(); 44 unsigned int warnloc_l = vd->id()->loc().firstLine(); 45 unsigned int warnloc_c = vd->id()->loc().firstColumn(); 46 unsigned int earlier_l = previous->second->id()->loc().firstLine(); 47 unsigned int earlier_c = previous->second->id()->loc().firstColumn(); 48 oss << "\n " << warnloc_f << ":" << warnloc_l << "." << warnloc_c << ":\n"; 49 oss << " Variable `" << *vd->id() << "' shadows variable with the same name in line " 50 << earlier_l << "." << earlier_c; 51 env.addWarning(oss.str()); 52 break; 53 } 54 if (_s[i].st != ST_INNER) { 55 break; 56 } 57 } 58 } 59 60 auto vdi = _s.back().m.find(vd->id()); 61 if (vdi == _s.back().m.end()) { 62 _s.back().m.insert(vd->id(), vd); 63 } else { 64 std::ostringstream ss; 65 ss << "identifier `" << vd->id()->str() << "' already defined"; 66 throw TypeError(env, vd->loc(), ss.str()); 67 } 68} 69 70void Scopes::pushToplevel() { _s.emplace_back(ST_TOPLEVEL); } 71 72void Scopes::pushFun() { _s.emplace_back(ST_FUN); } 73 74void Scopes::push() { _s.emplace_back(ST_INNER); } 75 76void Scopes::pop() { _s.pop_back(); } 77 78VarDecl* Scopes::find(Id* ident) { 79 int cur = static_cast<int>(_s.size()) - 1; 80 for (;;) { 81 auto vdi = _s[cur].m.find(ident); 82 if (vdi == _s[cur].m.end()) { 83 if (_s[cur].toplevel()) { 84 if (cur > 0) { 85 cur = 0; 86 } else { 87 return nullptr; 88 } 89 } else { 90 cur--; 91 } 92 } else { 93 return vdi->second; 94 } 95 } 96} 97 98VarDecl* Scopes::findSimilar(Id* ident) { 99 VarDecl* mostSimilar = nullptr; 100 int cur = static_cast<int>(_s.size()) - 1; 101 int minEdits = 3; 102 for (;;) { 103 for (auto decls : _s[cur].m) { 104 int edits = ident->levenshteinDistance(decls.first); 105 if (edits < minEdits && std::abs(static_cast<int>(ident->v().size()) - 106 static_cast<int>(decls.first->v().size())) <= 3) { 107 minEdits = edits; 108 mostSimilar = decls.second; 109 } 110 } 111 if (_s[cur].toplevel()) { 112 if (cur > 0) { 113 cur = 0; 114 } else { 115 break; 116 } 117 } else { 118 cur--; 119 } 120 } 121 return mostSimilar; 122} 123 124class VarDeclCmp { 125private: 126 std::unordered_map<VarDecl*, int>& _pos; 127 128public: 129 VarDeclCmp(std::unordered_map<VarDecl*, int>& pos) : _pos(pos) {} 130 bool operator()(Expression* e0, Expression* e1) { 131 if (auto* vd0 = Expression::dynamicCast<VarDecl>(e0)) { 132 if (auto* vd1 = Expression::dynamicCast<VarDecl>(e1)) { 133 return _pos[vd0] < _pos[vd1]; 134 } 135 return true; 136 } 137 return false; 138 } 139}; 140class ItemCmp { 141private: 142 std::unordered_map<VarDecl*, int>& _pos; 143 144public: 145 ItemCmp(std::unordered_map<VarDecl*, int>& pos) : _pos(pos) {} 146 bool operator()(Item* i0, Item* i1) { 147 if (auto* vd0 = i0->cast<VarDeclI>()) { 148 if (auto* vd1 = i1->cast<VarDeclI>()) { 149 return _pos[vd0->e()] < _pos[vd1->e()]; 150 } 151 return true; 152 } 153 return false; 154 } 155}; 156 157void create_enum_mapper(EnvI& env, Model* m, unsigned int enumId, VarDecl* vd, Model* enumItems) { 158 GCLock lock; 159 160 Id* ident = vd->id(); 161 Call* c = vd->e()->dynamicCast<Call>(); 162 auto* al = vd->e()->dynamicCast<ArrayLit>(); 163 164 std::vector<Expression*> parts; 165 if (vd->e()->isa<SetLit>()) { 166 parts.push_back(vd->e()); 167 } else if ((al != nullptr) || ((c != nullptr) && c->id() == "anon_enum" && c->argCount() == 1 && 168 c->arg(0)->isa<ArrayLit>())) { 169 if (c != nullptr) { 170 al = c->arg(0)->cast<ArrayLit>(); 171 } 172 std::vector<Expression*> enumIds(al->size()); 173 for (unsigned int i = 0; i < al->size(); i++) { 174 if (Id* eid = (*al)[i]->dynamicCast<Id>()) { 175 enumIds[i] = eid; 176 } else { 177 std::ostringstream ss; 178 ss << "invalid initialisation for enum `" << ident->v() << "'"; 179 throw TypeError(env, vd->e()->loc(), ss.str()); 180 } 181 } 182 parts.push_back(new SetLit(vd->e()->loc(), enumIds)); 183 } else if (c != nullptr) { 184 if (c->id() == "enumFromConstructors") { 185 if (c->argCount() != 1 || !c->arg(0)->isa<ArrayLit>()) { 186 throw TypeError(env, c->loc(), 187 "enumFromConstructors used with incorrect argument type (only supports " 188 "array literals)"); 189 } 190 auto* al = c->arg(0)->cast<ArrayLit>(); 191 for (unsigned int i = 0; i < al->size(); i++) { 192 parts.push_back((*al)[i]); 193 } 194 } else { 195 parts.push_back(c); 196 } 197 } else { 198 throw TypeError(env, vd->e()->loc(), 199 std::string("invalid initialisation for enum `") + ident->v().c_str() + "'"); 200 } 201 202 std::vector<Expression*> partCardinality; 203 for (unsigned int p = 0; p < parts.size(); p++) { 204 if (auto* sl = parts[p]->dynamicCast<SetLit>()) { 205 for (unsigned int i = 0; i < sl->v().size(); i++) { 206 if (!sl->v()[i]->isa<Id>()) { 207 throw TypeError( 208 env, sl->v()[i]->loc(), 209 std::string("invalid initialisation for enum `") + ident->v().c_str() + "'"); 210 } 211 auto* ti_id = new TypeInst(sl->v()[i]->loc(), Type::parenum(enumId)); 212 213 std::vector<Expression*> toEnumArgs(2); 214 toEnumArgs[0] = vd->id(); 215 if (partCardinality.empty()) { 216 toEnumArgs[1] = IntLit::a(i + 1); 217 } else { 218 toEnumArgs[1] = 219 new BinOp(Location().introduce(), partCardinality.back(), BOT_PLUS, IntLit::a(i + 1)); 220 } 221 Call* toEnum = new Call(sl->v()[i]->loc(), ASTString("to_enum"), toEnumArgs); 222 auto* vd_id = new VarDecl(ti_id->loc(), ti_id, sl->v()[i]->cast<Id>()->str(), toEnum); 223 auto* vdi_id = new VarDeclI(vd_id->loc(), vd_id); 224 std::string str(sl->v()[i]->cast<Id>()->str().c_str()); 225 env.reverseEnum[str] = vdi_id; 226 enumItems->addItem(vdi_id); 227 if (i == sl->v().size() - 1) { 228 // remember the last identifier 229 partCardinality.push_back(toEnumArgs[1]); 230 } 231 } 232 233 std::string name = 234 create_enum_to_string_name(ident, "_enum_to_string_" + std::to_string(p) + "_"); 235 std::vector<Expression*> al_args(sl->v().size()); 236 for (unsigned int i = 0; i < sl->v().size(); i++) { 237 std::string str(sl->v()[i]->cast<Id>()->str().c_str()); 238 if (str.size() >= 2 && str[0] == '\'' && str[str.size() - 1] == '\'') { 239 al_args[i] = 240 new StringLit(Location().introduce(), ASTString(str.substr(1, str.size() - 2))); 241 } else { 242 al_args[i] = new StringLit(Location().introduce(), ASTString(str)); 243 } 244 /// TODO: reimplement reverseEnum with a symbol table into the model (so you can evalPar an 245 /// expression) 246 } 247 auto* al = new ArrayLit(Location().introduce(), al_args); 248 249 std::vector<TypeInst*> ranges(1); 250 ranges[0] = new TypeInst(Location().introduce(), Type::parint()); 251 auto* ti = new TypeInst(Location().introduce(), Type::parstring(1)); 252 ti->setRanges(ranges); 253 auto* vd_enumToString = new VarDecl(Location().introduce(), ti, name, al); 254 enumItems->addItem(new VarDeclI(Location().introduce(), vd_enumToString)); 255 256 Type tx = Type::parint(); 257 tx.ot(Type::OT_OPTIONAL); 258 auto* ti_aa = new TypeInst(Location().introduce(), tx); 259 auto* vd_aa = new VarDecl(Location().introduce(), ti_aa, "x"); 260 vd_aa->toplevel(false); 261 auto* ti_ab = new TypeInst(Location().introduce(), Type::parbool()); 262 auto* vd_ab = new VarDecl(Location().introduce(), ti_ab, "b"); 263 vd_ab->toplevel(false); 264 auto* ti_aj = new TypeInst(Location().introduce(), Type::parbool()); 265 auto* vd_aj = new VarDecl(Location().introduce(), ti_aj, "json"); 266 vd_aj->toplevel(false); 267 auto* ti_fi = new TypeInst(Location().introduce(), Type::parstring()); 268 std::vector<VarDecl*> fi_params(3); 269 fi_params[0] = vd_aa; 270 fi_params[1] = vd_ab; 271 fi_params[2] = vd_aj; 272 273 std::vector<Expression*> deopt_args(1); 274 deopt_args[0] = vd_aa->id(); 275 Call* deopt = new Call(Location().introduce(), "deopt", deopt_args); 276 Call* occurs = new Call(Location().introduce(), "occurs", deopt_args); 277 std::vector<Expression*> aa_args(1); 278 aa_args[0] = deopt; 279 auto* aa = new ArrayAccess(Location().introduce(), vd_enumToString->id(), aa_args); 280 281 auto* sl_absent = new StringLit(Location().introduce(), "<>"); 282 283 ITE* if_absent = new ITE( 284 Location().introduce(), 285 {vd_aj->id(), new StringLit(Location().introduce(), ASTString("null"))}, sl_absent); 286 287 auto* json_e_quote = new StringLit(Location().introduce(), ASTString("{\"e\":\"")); 288 auto* json_e_quote_end = new StringLit(Location().introduce(), ASTString("\"}")); 289 auto* quote_aa = new BinOp(Location().introduce(), json_e_quote, BOT_PLUSPLUS, aa); 290 auto* quote_aa2 = new BinOp(Location().introduce(), quote_aa, BOT_PLUSPLUS, json_e_quote_end); 291 292 Call* quote_dzn = new Call(Location().introduce(), ASTString("showDznId"), {aa}); 293 294 std::vector<Expression*> ite_ifelse(2); 295 ite_ifelse[0] = occurs; 296 ite_ifelse[1] = 297 new ITE(Location().introduce(), {vd_ab->id(), quote_dzn, vd_aj->id(), quote_aa2}, aa); 298 299 ITE* ite = new ITE(Location().introduce(), ite_ifelse, if_absent); 300 301 std::string toString = "_toString_"; 302 if (parts.size() > 1) { 303 toString += std::to_string(p) + "_"; 304 } 305 306 auto* fi = new FunctionI(Location().introduce(), create_enum_to_string_name(ident, toString), 307 ti_fi, fi_params, ite); 308 enumItems->addItem(fi); 309 } else if (Call* c = parts[p]->dynamicCast<Call>()) { 310 if (c->id() == "anon_enum") { 311 Type tx = Type::parint(); 312 tx.ot(Type::OT_OPTIONAL); 313 auto* ti_aa = new TypeInst(Location().introduce(), tx); 314 auto* vd_aa = new VarDecl(Location().introduce(), ti_aa, "x"); 315 vd_aa->toplevel(false); 316 317 auto* ti_ab = new TypeInst(Location().introduce(), Type::parbool()); 318 auto* vd_ab = new VarDecl(Location().introduce(), ti_ab, "b"); 319 vd_ab->toplevel(false); 320 321 auto* ti_aj = new TypeInst(Location().introduce(), Type::parbool()); 322 auto* vd_aj = new VarDecl(Location().introduce(), ti_aj, "json"); 323 vd_aj->toplevel(false); 324 325 std::vector<Expression*> deopt_args(1); 326 deopt_args[0] = vd_aa->id(); 327 Call* deopt = new Call(Location().introduce(), "deopt", deopt_args); 328 Call* if_absent = new Call(Location().introduce(), "absent", deopt_args); 329 auto* sl_absent_dzn = new StringLit(Location().introduce(), "<>"); 330 ITE* sl_absent = new ITE( 331 Location().introduce(), 332 {vd_aj->id(), new StringLit(Location().introduce(), ASTString("null"))}, sl_absent_dzn); 333 334 auto* sl_dzn = new StringLit(Location().introduce(), ASTString(std::string("to_enum(") + 335 ident->str().c_str() + ",")); 336 337 std::vector<Expression*> showIntArgs(1); 338 if (partCardinality.empty()) { 339 showIntArgs[0] = deopt; 340 partCardinality.push_back(c->arg(0)); 341 } else { 342 showIntArgs[0] = 343 new BinOp(Location().introduce(), partCardinality.back(), BOT_PLUS, deopt); 344 partCardinality.push_back( 345 new BinOp(Location().introduce(), partCardinality.back(), BOT_PLUS, c->arg(0))); 346 } 347 348 Call* showInt = new Call(Location().introduce(), constants().ids.show, showIntArgs); 349 auto* construct_string_dzn = 350 new BinOp(Location().introduce(), sl_dzn, BOT_PLUSPLUS, showInt); 351 auto* closing_bracket = new StringLit(Location().introduce(), ASTString(")")); 352 auto* construct_string_dzn_2 = 353 new BinOp(Location().introduce(), construct_string_dzn, BOT_PLUSPLUS, closing_bracket); 354 355 auto* sl = new StringLit(Location().introduce(), 356 ASTString(std::string(ident->str().c_str()) + "_")); 357 auto* construct_string = new BinOp(Location().introduce(), sl, BOT_PLUSPLUS, showInt); 358 359 auto* json_e_quote = new StringLit(Location().introduce(), ASTString("{\"e\":\"")); 360 auto* json_e_quote_mid = new StringLit(Location().introduce(), ASTString("\", \"i\":")); 361 auto* json_e_quote_end = new StringLit(Location().introduce(), ASTString("}")); 362 auto* construct_string_json = 363 new BinOp(Location().introduce(), json_e_quote, BOT_PLUSPLUS, 364 new StringLit(Location().introduce(), ident->str())); 365 auto* construct_string_json_1a = new BinOp(Location().introduce(), construct_string_json, 366 BOT_PLUSPLUS, json_e_quote_mid); 367 auto* construct_string_json_1b = 368 new BinOp(Location().introduce(), construct_string_json_1a, BOT_PLUSPLUS, showInt); 369 auto* construct_string_json_2 = new BinOp(Location().introduce(), construct_string_json_1b, 370 BOT_PLUSPLUS, json_e_quote_end); 371 372 std::vector<Expression*> if_then(6); 373 if_then[0] = if_absent; 374 if_then[1] = sl_absent; 375 if_then[2] = vd_ab->id(); 376 if_then[3] = construct_string_dzn_2; 377 if_then[4] = vd_aj->id(); 378 if_then[5] = construct_string_json_2; 379 ITE* ite = new ITE(Location().introduce(), if_then, construct_string); 380 381 auto* ti_fi = new TypeInst(Location().introduce(), Type::parstring()); 382 std::vector<VarDecl*> fi_params(3); 383 fi_params[0] = vd_aa; 384 fi_params[1] = vd_ab; 385 fi_params[2] = vd_aj; 386 std::string toString = "_toString_"; 387 if (parts.size() > 1) { 388 toString += std::to_string(p) + "_"; 389 } 390 391 auto* fi = 392 new FunctionI(Location().introduce(), create_enum_to_string_name(ident, toString), 393 ti_fi, fi_params, ite); 394 enumItems->addItem(fi); 395 } else { 396 // This is an enum constructor C(E) 397 398 if (c->argCount() != 1 || !c->arg(0)->isa<Id>()) { 399 throw TypeError(env, c->loc(), 400 "enum constructors must have a single identifier as argument"); 401 } 402 Id* otherEnumId = c->arg(0)->cast<Id>(); 403 404 // Generate: 405 /* 406 function X: C(E: x) = to_enum(X,partCardinality.back()+x) 407 function var X: C(var E: x) = to_enum(X,partCardinality.back()+x) 408 function opt X: C(opt E: x) = if occurs(x) then C(deopt(x)) else to_enum(x,<>) endif 409 function var opt X: C(var opt E: x) = if occurs(x) then C(deopt(x)) else to_enum(x,<>) 410 endif 411 function set of X: C(set of E: x) = { C(i) | i in x } 412 function var set of X: C(var set of E: x) = { C(i) | i in x } 413 */ 414 { 415 Type Xt = Type::parint(); 416 Xt.enumId(enumId); 417 auto* Cfn_ti = new TypeInst(Location().introduce(), Xt); 418 auto* Cfn_x_ti = new TypeInst(Location().introduce(), Type(), otherEnumId); 419 auto* vd_x = new VarDecl(Location().introduce(), Cfn_x_ti, "x"); 420 vd_x->toplevel(false); 421 Expression* realX; 422 if (partCardinality.empty()) { 423 realX = vd_x->id(); 424 } else { 425 realX = new BinOp(Location().introduce(), partCardinality.back(), BOT_PLUS, vd_x->id()); 426 } 427 auto* Cfn_body = new Call(Location().introduce(), "to_enum", {vd->id(), realX}); 428 429 std::string Cfn_id(c->id().c_str()); 430 auto* Cfn = new FunctionI(Location().introduce(), Cfn_id, Cfn_ti, {vd_x}, Cfn_body); 431 env.reverseEnum[Cfn_id] = Cfn; 432 enumItems->addItem(Cfn); 433 } 434 { 435 Type Xt = Type::varint(); 436 Xt.enumId(enumId); 437 auto* Cfn_ti = new TypeInst(Location().introduce(), Xt); 438 Type argT; 439 argT.ti(Type::TI_VAR); 440 auto* Cfn_x_ti = new TypeInst(Location().introduce(), argT, otherEnumId); 441 auto* vd_x = new VarDecl(Location().introduce(), Cfn_x_ti, "x"); 442 vd_x->toplevel(false); 443 Expression* realX; 444 if (partCardinality.empty()) { 445 realX = vd_x->id(); 446 } else { 447 realX = new BinOp(Location().introduce(), partCardinality.back(), BOT_PLUS, vd_x->id()); 448 } 449 auto* Cfn_body = new Call(Location().introduce(), "to_enum", {vd->id(), realX}); 450 451 std::string Cfn_id(c->id().c_str()); 452 auto* Cfn = new FunctionI(Location().introduce(), Cfn_id, Cfn_ti, {vd_x}, Cfn_body); 453 enumItems->addItem(Cfn); 454 } 455 { 456 Type Xt = Type::parint(); 457 Xt.ot(Type::OT_OPTIONAL); 458 Xt.enumId(enumId); 459 auto* Cfn_ti = new TypeInst(Location().introduce(), Xt); 460 Type argT; 461 argT.ot(Type::OT_OPTIONAL); 462 auto* Cfn_x_ti = new TypeInst(Location().introduce(), argT, otherEnumId); 463 auto* vd_x = new VarDecl(Location().introduce(), Cfn_x_ti, "x"); 464 std::string Cfn_id(c->id().c_str()); 465 vd_x->toplevel(false); 466 auto* occurs = new Call(Location().introduce(), "occurs", {vd_x->id()}); 467 auto* deopt = new Call(Location().introduce(), "deopt", {vd_x->id()}); 468 auto* inv = new Call(Location().introduce(), Cfn_id, {deopt}); 469 auto* toEnumAbsent = 470 new Call(Location().introduce(), "to_enum", {vd->id(), constants().absent}); 471 auto* ite = new ITE(Location().introduce(), {occurs, inv}, toEnumAbsent); 472 auto* Cfn = new FunctionI(Location().introduce(), Cfn_id, Cfn_ti, {vd_x}, ite); 473 enumItems->addItem(Cfn); 474 } 475 { 476 Type Xt = Type::varint(); 477 Xt.ot(Type::OT_OPTIONAL); 478 Xt.enumId(enumId); 479 auto* Cfn_ti = new TypeInst(Location().introduce(), Xt); 480 Type argT; 481 argT.ti(Type::TI_VAR); 482 argT.ot(Type::OT_OPTIONAL); 483 auto* Cfn_x_ti = new TypeInst(Location().introduce(), argT, otherEnumId); 484 auto* vd_x = new VarDecl(Location().introduce(), Cfn_x_ti, "x"); 485 std::string Cfn_id(c->id().c_str()); 486 vd_x->toplevel(false); 487 auto* occurs = new Call(Location().introduce(), "occurs", {vd_x->id()}); 488 auto* deopt = new Call(Location().introduce(), "deopt", {vd_x->id()}); 489 auto* toEnumAbsent = 490 new Call(Location().introduce(), "to_enum", {vd->id(), constants().absent}); 491 auto* inv = new Call(Location().introduce(), Cfn_id, {deopt}); 492 auto* ite = new ITE(Location().introduce(), {occurs, inv}, toEnumAbsent); 493 auto* Cfn = new FunctionI(Location().introduce(), Cfn_id, Cfn_ti, {vd_x}, ite); 494 enumItems->addItem(Cfn); 495 } 496 { 497 Type Xt = Type::parint(); 498 Xt.st(Type::ST_SET); 499 Xt.enumId(enumId); 500 auto* Cfn_ti = new TypeInst(Location().introduce(), Xt); 501 Type argT; 502 argT.st(Type::ST_SET); 503 auto* Cfn_x_ti = new TypeInst(Location().introduce(), argT, otherEnumId); 504 auto* vd_x = new VarDecl(Location().introduce(), Cfn_x_ti, "x"); 505 std::string Cfn_id(c->id().c_str()); 506 vd_x->toplevel(false); 507 auto* s_ti = new TypeInst(Location().introduce(), Type::parint()); 508 auto* s = new VarDecl(Location().introduce(), s_ti, "s", nullptr); 509 s->toplevel(false); 510 auto* inv = new Call(Location().introduce(), Cfn_id, {s->id()}); 511 Generator gen({s}, vd_x->id(), nullptr); 512 Generators gens; 513 gens.g = {gen}; 514 auto* comprehension = new Comprehension(Location().introduce(), inv, gens, true); 515 auto* Cfn = new FunctionI(Location().introduce(), Cfn_id, Cfn_ti, {vd_x}, comprehension); 516 enumItems->addItem(Cfn); 517 } 518 { 519 Type Xt = Type::varint(); 520 Xt.st(Type::ST_SET); 521 Xt.enumId(enumId); 522 auto* Cfn_ti = new TypeInst(Location().introduce(), Xt); 523 Type argT; 524 argT.ti(Type::TI_VAR); 525 argT.st(Type::ST_SET); 526 auto* Cfn_x_ti = new TypeInst(Location().introduce(), argT, otherEnumId); 527 auto* vd_x = new VarDecl(Location().introduce(), Cfn_x_ti, "x"); 528 std::string Cfn_id(c->id().c_str()); 529 vd_x->toplevel(false); 530 auto* s_ti = new TypeInst(Location().introduce(), Type::parint()); 531 auto* s = new VarDecl(Location().introduce(), s_ti, "s", nullptr); 532 s->toplevel(false); 533 auto* inv = new Call(Location().introduce(), Cfn_id, {s->id()}); 534 Generator gen({s}, vd_x->id(), nullptr); 535 Generators gens; 536 gens.g = {gen}; 537 auto* comprehension = new Comprehension(Location().introduce(), inv, gens, true); 538 auto* Cfn = new FunctionI(Location().introduce(), Cfn_id, Cfn_ti, {vd_x}, comprehension); 539 enumItems->addItem(Cfn); 540 } 541 /* 542 function E: C⁻¹(X: x) = to_enum(E,x-partCardinality.back()) 543 function var E: C⁻¹(var X: x) = to_enum(E,x-partCardinality.back()) 544 function opt E: C⁻¹(opt X: x) = if occurs(x) then C⁻¹(deopt(x)) else to_enum(x,<>) endif 545 function var opt E: C⁻¹(var opt X: x) = if occurs(x) then C⁻¹(deopt(x)) else to_enum(x,<>) 546 endif 547 function set of E: C⁻¹(set of X: x) = { C⁻¹(i) | i in x } 548 function var set of E: C⁻¹(var set of X: x) = { C⁻¹(i) | i in x } 549 */ 550 { 551 auto* toEfn_ti = new TypeInst(Location().introduce(), Type(), otherEnumId); 552 Type Xt = Type::parint(); 553 Xt.enumId(enumId); 554 auto* toEfn_x_ti = new TypeInst(Location().introduce(), Xt, vd->id()); 555 auto* vd_x = new VarDecl(Location().introduce(), toEfn_x_ti, "x"); 556 vd_x->toplevel(false); 557 Expression* realX; 558 if (partCardinality.empty()) { 559 realX = vd_x->id(); 560 } else { 561 realX = 562 new BinOp(Location().introduce(), vd_x->id(), BOT_MINUS, partCardinality.back()); 563 } 564 auto* toEfn_body = new Call(Location().introduce(), "to_enum", {otherEnumId, realX}); 565 566 std::string Cinv_id(std::string(c->id().c_str()) + "⁻¹"); 567 auto* toEfn = 568 new FunctionI(Location().introduce(), Cinv_id, toEfn_ti, {vd_x}, toEfn_body); 569 enumItems->addItem(toEfn); 570 } 571 { 572 Type rT; 573 rT.ti(Type::TI_VAR); 574 auto* toEfn_ti = new TypeInst(Location().introduce(), rT, otherEnumId); 575 Type Xt = Type::varint(); 576 Xt.enumId(enumId); 577 auto* toEfn_x_ti = new TypeInst(Location().introduce(), Xt, vd->id()); 578 auto* vd_x = new VarDecl(Location().introduce(), toEfn_x_ti, "x"); 579 vd_x->toplevel(false); 580 Expression* realX; 581 if (partCardinality.empty()) { 582 realX = vd_x->id(); 583 } else { 584 realX = 585 new BinOp(Location().introduce(), vd_x->id(), BOT_MINUS, partCardinality.back()); 586 } 587 auto* toEfn_body = new Call(Location().introduce(), "to_enum", {otherEnumId, realX}); 588 589 std::string Cinv_id(std::string(c->id().c_str()) + "⁻¹"); 590 auto* toEfn = 591 new FunctionI(Location().introduce(), Cinv_id, toEfn_ti, {vd_x}, toEfn_body); 592 enumItems->addItem(toEfn); 593 } 594 { 595 Type rt; 596 rt.ot(Type::OT_OPTIONAL); 597 auto* Cfn_ti = new TypeInst(Location().introduce(), rt, otherEnumId); 598 Type argT; 599 argT.ot(Type::OT_OPTIONAL); 600 argT.enumId(enumId); 601 auto* Cfn_x_ti = new TypeInst(Location().introduce(), argT, vd->id()); 602 auto* vd_x = new VarDecl(Location().introduce(), Cfn_x_ti, "x"); 603 std::string Cinv_id(std::string(c->id().c_str()) + "⁻¹"); 604 vd_x->toplevel(false); 605 auto* occurs = new Call(Location().introduce(), "occurs", {vd_x->id()}); 606 auto* deopt = new Call(Location().introduce(), "deopt", {vd_x->id()}); 607 auto* inv = new Call(Location().introduce(), Cinv_id, {deopt}); 608 auto* toEnumAbsent = 609 new Call(Location().introduce(), "to_enum", {otherEnumId, constants().absent}); 610 auto* ite = new ITE(Location().introduce(), {occurs, inv}, toEnumAbsent); 611 auto* Cfn = new FunctionI(Location().introduce(), Cinv_id, Cfn_ti, {vd_x}, ite); 612 enumItems->addItem(Cfn); 613 } 614 { 615 Type rt; 616 rt.ti(Type::TI_VAR); 617 rt.ot(Type::OT_OPTIONAL); 618 auto* Cfn_ti = new TypeInst(Location().introduce(), rt, otherEnumId); 619 Type argT = Type::varint(); 620 argT.ot(Type::OT_OPTIONAL); 621 argT.enumId(enumId); 622 auto* Cfn_x_ti = new TypeInst(Location().introduce(), argT, vd->id()); 623 auto* vd_x = new VarDecl(Location().introduce(), Cfn_x_ti, "x"); 624 std::string Cinv_id(std::string(c->id().c_str()) + "⁻¹"); 625 vd_x->toplevel(false); 626 auto* occurs = new Call(Location().introduce(), "occurs", {vd_x->id()}); 627 auto* deopt = new Call(Location().introduce(), "deopt", {vd_x->id()}); 628 auto* inv = new Call(Location().introduce(), Cinv_id, {deopt}); 629 auto* toEnumAbsent = 630 new Call(Location().introduce(), "to_enum", {otherEnumId, constants().absent}); 631 auto* ite = new ITE(Location().introduce(), {occurs, inv}, toEnumAbsent); 632 auto* Cfn = new FunctionI(Location().introduce(), Cinv_id, Cfn_ti, {vd_x}, ite); 633 enumItems->addItem(Cfn); 634 } 635 { 636 Type Xt; 637 Xt.st(Type::ST_SET); 638 auto* Cfn_ti = new TypeInst(Location().introduce(), Xt, otherEnumId); 639 Type argT = Type::parint(); 640 argT.st(Type::ST_SET); 641 argT.enumId(enumId); 642 auto* Cfn_x_ti = new TypeInst(Location().introduce(), argT, vd->id()); 643 auto* vd_x = new VarDecl(Location().introduce(), Cfn_x_ti, "x"); 644 vd_x->toplevel(false); 645 std::string Cinv_id(std::string(c->id().c_str()) + "⁻¹"); 646 auto* s_ti = new TypeInst(Location().introduce(), Type::parint()); 647 auto* s = new VarDecl(Location().introduce(), s_ti, "s", nullptr); 648 s->toplevel(false); 649 auto* inv = new Call(Location().introduce(), Cinv_id, {s->id()}); 650 Generator gen({s}, vd_x->id(), nullptr); 651 Generators gens; 652 gens.g = {gen}; 653 auto* comprehension = new Comprehension(Location().introduce(), inv, gens, true); 654 auto* Cfn = new FunctionI(Location().introduce(), Cinv_id, Cfn_ti, {vd_x}, comprehension); 655 enumItems->addItem(Cfn); 656 } 657 { 658 Type Xt; 659 Xt.ti(Type::TI_VAR); 660 Xt.st(Type::ST_SET); 661 auto* Cfn_ti = new TypeInst(Location().introduce(), Xt, otherEnumId); 662 Type argT = Type::varint(); 663 argT.st(Type::ST_SET); 664 argT.enumId(enumId); 665 auto* Cfn_x_ti = new TypeInst(Location().introduce(), argT, vd->id()); 666 auto* vd_x = new VarDecl(Location().introduce(), Cfn_x_ti, "x"); 667 vd_x->toplevel(false); 668 std::string Cinv_id(std::string(c->id().c_str()) + "⁻¹"); 669 auto* s_ti = new TypeInst(Location().introduce(), Type::varint()); 670 auto* s = new VarDecl(Location().introduce(), s_ti, "s", nullptr); 671 s->toplevel(false); 672 auto* inv = new Call(Location().introduce(), Cinv_id, {s->id()}); 673 Generator gen({s}, vd_x->id(), nullptr); 674 Generators gens; 675 gens.g = {gen}; 676 auto* comprehension = new Comprehension(Location().introduce(), inv, gens, true); 677 auto* Cfn = new FunctionI(Location().introduce(), Cinv_id, Cfn_ti, {vd_x}, comprehension); 678 enumItems->addItem(Cfn); 679 } 680 681 /* 682 function string: _toString_p_X(opt X: x, bool: b, bool: json) = 683 if absent(x) then "<>" else 684 if json then "{ \"c\": \"C\", \"e\":" else "C(" endif 685 ++_toString_E(to_enum(E,deopt(x)),b,json) 686 ++ if json then "}" else ")" endif 687 endif 688 */ 689 690 { 691 Type tx = Type::parint(); 692 tx.ot(Type::OT_OPTIONAL); 693 auto* ti_aa = new TypeInst(Location().introduce(), tx); 694 auto* vd_aa = new VarDecl(Location().introduce(), ti_aa, "x"); 695 vd_aa->toplevel(false); 696 697 auto* ti_ab = new TypeInst(Location().introduce(), Type::parbool()); 698 auto* vd_ab = new VarDecl(Location().introduce(), ti_ab, "b"); 699 vd_ab->toplevel(false); 700 701 auto* ti_aj = new TypeInst(Location().introduce(), Type::parbool()); 702 auto* vd_aj = new VarDecl(Location().introduce(), ti_aj, "json"); 703 vd_aj->toplevel(false); 704 705 std::vector<Expression*> deopt_args(1); 706 deopt_args[0] = vd_aa->id(); 707 Call* deopt = new Call(Location().introduce(), "deopt", deopt_args); 708 Call* if_absent = new Call(Location().introduce(), "absent", deopt_args); 709 auto* sl_absent_dzn = new StringLit(Location().introduce(), "<>"); 710 ITE* sl_absent = 711 new ITE(Location().introduce(), 712 {vd_aj->id(), new StringLit(Location().introduce(), ASTString("null"))}, 713 sl_absent_dzn); 714 715 Call* toEnumE = new Call(Location().introduce(), "to_enum", {otherEnumId, deopt}); 716 Call* toString = new Call(Location().introduce(), 717 create_enum_to_string_name(otherEnumId, "_toString_"), 718 {toEnumE, vd_ab->id(), vd_aj->id()}); 719 720 auto* openOther = 721 new StringLit(Location().introduce(), std::string(c->id().c_str()) + "("); 722 auto* openJson = 723 new StringLit(Location().introduce(), 724 "{ \"c\" : \"" + std::string(c->id().c_str()) + "\", \"e\" : "); 725 ITE* openConstr = new ITE(Location().introduce(), {vd_aj->id(), openJson}, openOther); 726 auto* closeJson = new StringLit(Location().introduce(), "}"); 727 auto* closeOther = new StringLit(Location().introduce(), ")"); 728 ITE* closeConstr = new ITE(Location().introduce(), {vd_aj->id(), closeJson}, closeOther); 729 730 auto* concat1 = new BinOp(Location().introduce(), openConstr, BOT_PLUSPLUS, toString); 731 auto* concat2 = new BinOp(Location().introduce(), concat1, BOT_PLUSPLUS, closeConstr); 732 733 ITE* ite = new ITE(Location().introduce(), {if_absent, sl_absent}, concat2); 734 auto* ti_fi = new TypeInst(Location().introduce(), Type::parstring()); 735 std::vector<VarDecl*> fi_params(3); 736 fi_params[0] = vd_aa; 737 fi_params[1] = vd_ab; 738 fi_params[2] = vd_aj; 739 std::string XtoString = "_toString_"; 740 if (parts.size() > 1) { 741 XtoString += std::to_string(p) + "_"; 742 } 743 744 auto* fi = 745 new FunctionI(Location().introduce(), create_enum_to_string_name(ident, XtoString), 746 ti_fi, fi_params, ite); 747 enumItems->addItem(fi); 748 } 749 750 Call* cardE = new Call(Location().introduce(), "card", {otherEnumId}); 751 if (partCardinality.empty()) { 752 partCardinality.push_back(cardE); 753 } else { 754 partCardinality.push_back( 755 new BinOp(Location().introduce(), partCardinality.back(), BOT_PLUS, cardE)); 756 } 757 } 758 } else { 759 assert(false); 760 } 761 } 762 763 // Create set literal for overall enum 764 auto* rhs = new BinOp(vd->loc(), IntLit::a(1), BOT_DOTDOT, partCardinality.back()); 765 vd->e(rhs); 766 767 if (parts.size() > 1) { 768 Type tx = Type::parint(); 769 tx.ot(Type::OT_OPTIONAL); 770 auto* ti_aa = new TypeInst(Location().introduce(), tx); 771 auto* vd_aa = new VarDecl(Location().introduce(), ti_aa, "x"); 772 vd_aa->toplevel(false); 773 774 auto* ti_ab = new TypeInst(Location().introduce(), Type::parbool()); 775 auto* vd_ab = new VarDecl(Location().introduce(), ti_ab, "b"); 776 vd_ab->toplevel(false); 777 778 auto* ti_aj = new TypeInst(Location().introduce(), Type::parbool()); 779 auto* vd_aj = new VarDecl(Location().introduce(), ti_aj, "json"); 780 vd_aj->toplevel(false); 781 782 std::vector<Expression*> deopt_args(1); 783 deopt_args[0] = vd_aa->id(); 784 Call* deopt = new Call(Location().introduce(), "deopt", deopt_args); 785 Call* if_absent = new Call(Location().introduce(), "absent", deopt_args); 786 auto* sl_absent_dzn = new StringLit(Location().introduce(), "<>"); 787 ITE* sl_absent = new ITE( 788 Location().introduce(), 789 {vd_aj->id(), new StringLit(Location().introduce(), ASTString("null"))}, sl_absent_dzn); 790 791 std::vector<Expression*> ite_cases_a; 792 Expression* ite_cases_else; 793 for (unsigned int i = 0; i < parts.size(); i++) { 794 std::string toString = "_toString_" + std::to_string(i) + "_"; 795 Expression* aa; 796 if (i == 0) { 797 aa = vd_aa->id(); 798 } else { 799 auto* bo = new BinOp(Location().introduce(), deopt, BOT_MINUS, partCardinality[i - 1]); 800 Call* c = new Call(Location().introduce(), "to_enum", {vd->id(), bo}); 801 aa = c; 802 } 803 Call* c = new Call(Location().introduce(), create_enum_to_string_name(ident, toString), 804 {aa, vd_ab->id(), vd_aj->id()}); 805 if (i < parts.size() - 1) { 806 auto* bo = new BinOp(Location().introduce(), deopt, BOT_LQ, partCardinality[i]); 807 ite_cases_a.push_back(bo); 808 ite_cases_a.push_back(c); 809 } else { 810 ite_cases_else = c; 811 } 812 } 813 814 ITE* ite_cases = new ITE(Location().introduce(), ite_cases_a, ite_cases_else); 815 816 ITE* ite = new ITE(Location().introduce(), {if_absent, sl_absent}, ite_cases); 817 818 auto* ti_fi = new TypeInst(Location().introduce(), Type::parstring()); 819 std::vector<VarDecl*> fi_params(3); 820 fi_params[0] = vd_aa; 821 fi_params[1] = vd_ab; 822 fi_params[2] = vd_aj; 823 auto* fi = 824 new FunctionI(Location().introduce(), create_enum_to_string_name(ident, "_toString_"), 825 ti_fi, fi_params, ite); 826 enumItems->addItem(fi); 827 828 /* 829 function string: _toString_ENUM(opt Foo: x, bool: b, bool: json) = 830 if occurs(x) then 831 if deopt(x)<=partCardinality[1] then _toString_1_ENUM(x,b,json) 832 elseif deopt(x)<=partCardinality[2] then _toString_2_ENUM(x,b,json) 833 ... 834 endif 835 else "<>" endif 836 */ 837 } 838 839 { 840 /* 841 842 function _toString_ENUM(array[$U] of opt Foo: x, bool: b, bool: json) = 843 let { 844 array[int] of opt ENUM: xx = array1d(x) 845 } in "[" ++ join(", ", [ _toString_ENUM(xx[i],b,json) | i in index_set(xx) ]) ++ "]"; 846 847 */ 848 849 TIId* tiid = new TIId(Location().introduce(), "U"); 850 auto* ti_range = new TypeInst(Location().introduce(), Type::parint(), tiid); 851 std::vector<TypeInst*> ranges(1); 852 ranges[0] = ti_range; 853 854 Type tx = Type::parint(-1); 855 tx.ot(Type::OT_OPTIONAL); 856 auto* x_ti = new TypeInst(Location().introduce(), tx, ranges, ident); 857 auto* vd_x = new VarDecl(Location().introduce(), x_ti, "x"); 858 vd_x->toplevel(false); 859 860 auto* b_ti = new TypeInst(Location().introduce(), Type::parbool()); 861 auto* vd_b = new VarDecl(Location().introduce(), b_ti, "b"); 862 vd_b->toplevel(false); 863 864 auto* j_ti = new TypeInst(Location().introduce(), Type::parbool()); 865 auto* vd_j = new VarDecl(Location().introduce(), j_ti, "json"); 866 vd_j->toplevel(false); 867 868 auto* xx_range = new TypeInst(Location().introduce(), Type::parint(), nullptr); 869 std::vector<TypeInst*> xx_ranges(1); 870 xx_ranges[0] = xx_range; 871 auto* xx_ti = new TypeInst(Location().introduce(), tx, xx_ranges, ident); 872 873 std::vector<Expression*> array1dArgs(1); 874 array1dArgs[0] = vd_x->id(); 875 Call* array1dCall = new Call(Location().introduce(), "array1d", array1dArgs); 876 877 auto* vd_xx = new VarDecl(Location().introduce(), xx_ti, "xx", array1dCall); 878 vd_xx->toplevel(false); 879 880 auto* idx_i_ti = new TypeInst(Location().introduce(), Type::parint()); 881 auto* idx_i = new VarDecl(Location().introduce(), idx_i_ti, "i"); 882 idx_i->toplevel(false); 883 884 std::vector<Expression*> aa_xxi_idx(1); 885 aa_xxi_idx[0] = idx_i->id(); 886 auto* aa_xxi = new ArrayAccess(Location().introduce(), vd_xx->id(), aa_xxi_idx); 887 888 std::vector<Expression*> _toString_ENUMArgs(3); 889 _toString_ENUMArgs[0] = aa_xxi; 890 _toString_ENUMArgs[1] = vd_b->id(); 891 _toString_ENUMArgs[2] = vd_j->id(); 892 Call* _toString_ENUM = 893 new Call(Location().introduce(), create_enum_to_string_name(ident, "_toString_"), 894 _toString_ENUMArgs); 895 896 std::vector<Expression*> index_set_xx_args(1); 897 index_set_xx_args[0] = vd_xx->id(); 898 Call* index_set_xx = new Call(Location().introduce(), "index_set", index_set_xx_args); 899 std::vector<VarDecl*> gen_exps(1); 900 gen_exps[0] = idx_i; 901 Generator gen(gen_exps, index_set_xx, nullptr); 902 903 Generators generators; 904 generators.g.push_back(gen); 905 auto* comp = new Comprehension(Location().introduce(), _toString_ENUM, generators, false); 906 907 std::vector<Expression*> join_args(2); 908 join_args[0] = new StringLit(Location().introduce(), ", "); 909 join_args[1] = comp; 910 Call* join = new Call(Location().introduce(), "join", join_args); 911 912 auto* sl_open = new StringLit(Location().introduce(), "["); 913 auto* bopp0 = new BinOp(Location().introduce(), sl_open, BOT_PLUSPLUS, join); 914 auto* sl_close = new StringLit(Location().introduce(), "]"); 915 auto* bopp1 = new BinOp(Location().introduce(), bopp0, BOT_PLUSPLUS, sl_close); 916 917 std::vector<Expression*> let_args(1); 918 let_args[0] = vd_xx; 919 Let* let = new Let(Location().introduce(), let_args, bopp1); 920 921 auto* ti_fi = new TypeInst(Location().introduce(), Type::parstring()); 922 std::vector<VarDecl*> fi_params(3); 923 fi_params[0] = vd_x; 924 fi_params[1] = vd_b; 925 fi_params[2] = vd_j; 926 auto* fi = 927 new FunctionI(Location().introduce(), create_enum_to_string_name(ident, "_toString_"), 928 ti_fi, fi_params, let); 929 enumItems->addItem(fi); 930 } 931 932 { 933 /* 934 935 function _toString_ENUM(opt set of ENUM: x, bool: b, bool: json) = 936 if absent(x) then "<>" else "{" ++ join(", ", [ _toString_ENUM(i,b,json) | i in x ]) ++ "}" 937 endif; 938 939 */ 940 941 Type argType = Type::parsetenum(ident->type().enumId()); 942 argType.ot(Type::OT_OPTIONAL); 943 auto* x_ti = new TypeInst(Location().introduce(), argType, ident); 944 auto* vd_x = new VarDecl(Location().introduce(), x_ti, "x"); 945 vd_x->toplevel(false); 946 947 auto* b_ti = new TypeInst(Location().introduce(), Type::parbool()); 948 auto* vd_b = new VarDecl(Location().introduce(), b_ti, "b"); 949 vd_b->toplevel(false); 950 951 auto* j_ti = new TypeInst(Location().introduce(), Type::parbool()); 952 auto* vd_j = new VarDecl(Location().introduce(), j_ti, "json"); 953 vd_j->toplevel(false); 954 955 auto* idx_i_ti = new TypeInst(Location().introduce(), Type::parint()); 956 auto* idx_i = new VarDecl(Location().introduce(), idx_i_ti, "i"); 957 idx_i->toplevel(false); 958 959 std::vector<Expression*> _toString_ENUMArgs(3); 960 _toString_ENUMArgs[0] = idx_i->id(); 961 _toString_ENUMArgs[1] = vd_b->id(); 962 _toString_ENUMArgs[2] = vd_j->id(); 963 Call* _toString_ENUM = 964 new Call(Location().introduce(), create_enum_to_string_name(ident, "_toString_"), 965 _toString_ENUMArgs); 966 967 std::vector<Expression*> deopt_args(1); 968 deopt_args[0] = vd_x->id(); 969 Call* deopt = new Call(Location().introduce(), "deopt", deopt_args); 970 Call* if_absent = new Call(Location().introduce(), "absent", deopt_args); 971 auto* sl_absent_dzn = new StringLit(Location().introduce(), "<>"); 972 ITE* sl_absent = new ITE(Location().introduce(), 973 {vd_j->id(), new StringLit(Location().introduce(), ASTString("null"))}, 974 sl_absent_dzn); 975 976 std::vector<VarDecl*> gen_exps(1); 977 gen_exps[0] = idx_i; 978 Generator gen(gen_exps, deopt, nullptr); 979 980 Generators generators; 981 generators.g.push_back(gen); 982 auto* comp = new Comprehension(Location().introduce(), _toString_ENUM, generators, false); 983 984 std::vector<Expression*> join_args(2); 985 join_args[0] = new StringLit(Location().introduce(), ", "); 986 join_args[1] = comp; 987 Call* join = new Call(Location().introduce(), "join", join_args); 988 989 ITE* json_set = 990 new ITE(Location().introduce(), 991 {vd_j->id(), new StringLit(Location().introduce(), ASTString("\"set\":["))}, 992 new StringLit(Location().introduce(), ASTString(""))); 993 ITE* json_set_close = new ITE( 994 Location().introduce(), {vd_j->id(), new StringLit(Location().introduce(), ASTString("]"))}, 995 new StringLit(Location().introduce(), ASTString(""))); 996 997 auto* sl_open = new StringLit(Location().introduce(), "{"); 998 auto* bopp0 = new BinOp(Location().introduce(), sl_open, BOT_PLUSPLUS, json_set); 999 auto* bopp1 = new BinOp(Location().introduce(), bopp0, BOT_PLUSPLUS, join); 1000 auto* bopp2 = new BinOp(Location().introduce(), bopp1, BOT_PLUSPLUS, json_set_close); 1001 auto* sl_close = new StringLit(Location().introduce(), "}"); 1002 auto* bopp3 = new BinOp(Location().introduce(), bopp2, BOT_PLUSPLUS, sl_close); 1003 1004 std::vector<Expression*> if_then(2); 1005 if_then[0] = if_absent; 1006 if_then[1] = sl_absent; 1007 ITE* ite = new ITE(Location().introduce(), if_then, bopp3); 1008 1009 auto* ti_fi = new TypeInst(Location().introduce(), Type::parstring()); 1010 std::vector<VarDecl*> fi_params(3); 1011 fi_params[0] = vd_x; 1012 fi_params[1] = vd_b; 1013 fi_params[2] = vd_j; 1014 auto* fi = 1015 new FunctionI(Location().introduce(), create_enum_to_string_name(ident, "_toString_"), 1016 ti_fi, fi_params, ite); 1017 enumItems->addItem(fi); 1018 } 1019 1020 { 1021 /* 1022 1023 function _toString_ENUM(array[$U] of opt set of ENUM: x, bool: b, bool: json) = 1024 let { 1025 array[int] of opt set of ENUM: xx = array1d(x) 1026 } in "[" ++ join(", ", [ _toString_ENUM(xx[i],b,json) | i in index_set(xx) ]) ++ "]"; 1027 1028 */ 1029 1030 TIId* tiid = new TIId(Location().introduce(), "U"); 1031 auto* ti_range = new TypeInst(Location().introduce(), Type::parint(), tiid); 1032 std::vector<TypeInst*> ranges(1); 1033 ranges[0] = ti_range; 1034 1035 Type tx = Type::parsetint(-1); 1036 tx.ot(Type::OT_OPTIONAL); 1037 auto* x_ti = new TypeInst(Location().introduce(), tx, ranges, ident); 1038 auto* vd_x = new VarDecl(Location().introduce(), x_ti, "x"); 1039 vd_x->toplevel(false); 1040 1041 auto* b_ti = new TypeInst(Location().introduce(), Type::parbool()); 1042 auto* vd_b = new VarDecl(Location().introduce(), b_ti, "b"); 1043 vd_b->toplevel(false); 1044 1045 auto* j_ti = new TypeInst(Location().introduce(), Type::parbool()); 1046 auto* vd_j = new VarDecl(Location().introduce(), j_ti, "json"); 1047 vd_j->toplevel(false); 1048 1049 auto* xx_range = new TypeInst(Location().introduce(), Type::parint(), nullptr); 1050 std::vector<TypeInst*> xx_ranges(1); 1051 xx_ranges[0] = xx_range; 1052 auto* xx_ti = new TypeInst(Location().introduce(), tx, xx_ranges, ident); 1053 1054 std::vector<Expression*> array1dArgs(1); 1055 array1dArgs[0] = vd_x->id(); 1056 Call* array1dCall = new Call(Location().introduce(), "array1d", array1dArgs); 1057 1058 auto* vd_xx = new VarDecl(Location().introduce(), xx_ti, "xx", array1dCall); 1059 vd_xx->toplevel(false); 1060 1061 auto* idx_i_ti = new TypeInst(Location().introduce(), Type::parint()); 1062 auto* idx_i = new VarDecl(Location().introduce(), idx_i_ti, "i"); 1063 idx_i->toplevel(false); 1064 1065 std::vector<Expression*> aa_xxi_idx(1); 1066 aa_xxi_idx[0] = idx_i->id(); 1067 auto* aa_xxi = new ArrayAccess(Location().introduce(), vd_xx->id(), aa_xxi_idx); 1068 1069 std::vector<Expression*> _toString_ENUMArgs(3); 1070 _toString_ENUMArgs[0] = aa_xxi; 1071 _toString_ENUMArgs[1] = vd_b->id(); 1072 _toString_ENUMArgs[2] = vd_j->id(); 1073 Call* _toString_ENUM = 1074 new Call(Location().introduce(), create_enum_to_string_name(ident, "_toString_"), 1075 _toString_ENUMArgs); 1076 1077 std::vector<Expression*> index_set_xx_args(1); 1078 index_set_xx_args[0] = vd_xx->id(); 1079 Call* index_set_xx = new Call(Location().introduce(), "index_set", index_set_xx_args); 1080 std::vector<VarDecl*> gen_exps(1); 1081 gen_exps[0] = idx_i; 1082 Generator gen(gen_exps, index_set_xx, nullptr); 1083 1084 Generators generators; 1085 generators.g.push_back(gen); 1086 auto* comp = new Comprehension(Location().introduce(), _toString_ENUM, generators, false); 1087 1088 std::vector<Expression*> join_args(2); 1089 join_args[0] = new StringLit(Location().introduce(), ", "); 1090 join_args[1] = comp; 1091 Call* join = new Call(Location().introduce(), "join", join_args); 1092 1093 auto* sl_open = new StringLit(Location().introduce(), "["); 1094 auto* bopp0 = new BinOp(Location().introduce(), sl_open, BOT_PLUSPLUS, join); 1095 auto* sl_close = new StringLit(Location().introduce(), "]"); 1096 auto* bopp1 = new BinOp(Location().introduce(), bopp0, BOT_PLUSPLUS, sl_close); 1097 1098 std::vector<Expression*> let_args(1); 1099 let_args[0] = vd_xx; 1100 Let* let = new Let(Location().introduce(), let_args, bopp1); 1101 1102 auto* ti_fi = new TypeInst(Location().introduce(), Type::parstring()); 1103 std::vector<VarDecl*> fi_params(3); 1104 fi_params[0] = vd_x; 1105 fi_params[1] = vd_b; 1106 fi_params[2] = vd_j; 1107 auto* fi = 1108 new FunctionI(Location().introduce(), create_enum_to_string_name(ident, "_toString_"), 1109 ti_fi, fi_params, let); 1110 enumItems->addItem(fi); 1111 } 1112} 1113 1114void TopoSorter::add(EnvI& env, VarDeclI* vdi, bool handleEnums, Model* enumItems) { 1115 VarDecl* vd = vdi->e(); 1116 if (handleEnums && vd->ti()->isEnum()) { 1117 unsigned int enumId = env.registerEnum(vdi); 1118 Type vdt = vd->type(); 1119 vdt.enumId(enumId); 1120 vd->ti()->type(vdt); 1121 vd->type(vdt); 1122 1123 if (vd->e() != nullptr) { 1124 create_enum_mapper(env, model, enumId, vd, enumItems); 1125 } 1126 } 1127 scopes.add(env, vd); 1128} 1129 1130VarDecl* TopoSorter::get(EnvI& env, const ASTString& id_v, const Location& loc) { 1131 GCLock lock; 1132 Id* ident = new Id(Location(), id_v, nullptr); 1133 VarDecl* decl = scopes.find(ident); 1134 if (decl == nullptr) { 1135 std::ostringstream ss; 1136 ss << "undefined identifier `" << ident->str() << "'"; 1137 VarDecl* similar = scopes.findSimilar(ident); 1138 if (similar != nullptr) { 1139 ss << ", did you mean `" << *similar->id() << "'?"; 1140 } 1141 throw TypeError(env, loc, ss.str()); 1142 } 1143 return decl; 1144} 1145 1146VarDecl* TopoSorter::checkId(EnvI& env, Id* ident, const Location& loc) { 1147 VarDecl* decl = scopes.find(ident); 1148 if (decl == nullptr) { 1149 std::ostringstream ss; 1150 ss << "undefined identifier `" << ident->str() << "'"; 1151 VarDecl* similar = scopes.findSimilar(ident); 1152 if (similar != nullptr) { 1153 ss << ", did you mean `" << *similar->id() << "'?"; 1154 } 1155 throw TypeError(env, loc, ss.str()); 1156 } 1157 auto pi = pos.find(decl); 1158 if (pi == pos.end()) { 1159 // new id 1160 scopes.pushToplevel(); 1161 run(env, decl); 1162 scopes.pop(); 1163 } else { 1164 // previously seen, check if circular 1165 if (pi->second == -1) { 1166 std::ostringstream ss; 1167 ss << "circular definition of `" << ident->str() << "'"; 1168 throw TypeError(env, loc, ss.str()); 1169 } 1170 } 1171 return decl; 1172} 1173 1174VarDecl* TopoSorter::checkId(EnvI& env, const ASTString& id_v, const Location& loc) { 1175 GCLock lock; 1176 Id* id = new Id(loc, id_v, nullptr); 1177 return checkId(env, id, loc); 1178} 1179 1180void TopoSorter::run(EnvI& env, Expression* e) { 1181 if (e == nullptr) { 1182 return; 1183 } 1184 switch (e->eid()) { 1185 case Expression::E_INTLIT: 1186 case Expression::E_FLOATLIT: 1187 case Expression::E_BOOLLIT: 1188 case Expression::E_STRINGLIT: 1189 case Expression::E_ANON: 1190 break; 1191 case Expression::E_SETLIT: { 1192 auto* sl = e->cast<SetLit>(); 1193 if (sl->isv() == nullptr && sl->fsv() == nullptr) { 1194 for (unsigned int i = 0; i < sl->v().size(); i++) { 1195 run(env, sl->v()[i]); 1196 } 1197 } 1198 } break; 1199 case Expression::E_ID: { 1200 if (e != constants().absent) { 1201 VarDecl* vd = checkId(env, e->cast<Id>(), e->loc()); 1202 e->cast<Id>()->decl(vd); 1203 } 1204 } break; 1205 case Expression::E_ARRAYLIT: { 1206 auto* al = e->cast<ArrayLit>(); 1207 for (unsigned int i = 0; i < al->size(); i++) { 1208 run(env, (*al)[i]); 1209 } 1210 } break; 1211 case Expression::E_ARRAYACCESS: { 1212 auto* ae = e->cast<ArrayAccess>(); 1213 run(env, ae->v()); 1214 for (unsigned int i = 0; i < ae->idx().size(); i++) { 1215 run(env, ae->idx()[i]); 1216 } 1217 } break; 1218 case Expression::E_COMP: { 1219 auto* ce = e->cast<Comprehension>(); 1220 scopes.push(); 1221 for (int i = 0; i < ce->numberOfGenerators(); i++) { 1222 run(env, ce->in(i)); 1223 for (int j = 0; j < ce->numberOfDecls(i); j++) { 1224 run(env, ce->decl(i, j)); 1225 scopes.add(env, ce->decl(i, j)); 1226 } 1227 if (ce->where(i) != nullptr) { 1228 run(env, ce->where(i)); 1229 } 1230 } 1231 run(env, ce->e()); 1232 scopes.pop(); 1233 } break; 1234 case Expression::E_ITE: { 1235 ITE* ite = e->cast<ITE>(); 1236 for (int i = 0; i < ite->size(); i++) { 1237 run(env, ite->ifExpr(i)); 1238 run(env, ite->thenExpr(i)); 1239 } 1240 run(env, ite->elseExpr()); 1241 } break; 1242 case Expression::E_BINOP: { 1243 auto* be = e->cast<BinOp>(); 1244 std::vector<Expression*> todo; 1245 todo.push_back(be->lhs()); 1246 todo.push_back(be->rhs()); 1247 while (!todo.empty()) { 1248 Expression* be = todo.back(); 1249 todo.pop_back(); 1250 if (auto* e_bo = be->dynamicCast<BinOp>()) { 1251 todo.push_back(e_bo->lhs()); 1252 todo.push_back(e_bo->rhs()); 1253 for (ExpressionSetIter it = e_bo->ann().begin(); it != e_bo->ann().end(); ++it) { 1254 run(env, *it); 1255 } 1256 } else { 1257 run(env, be); 1258 } 1259 } 1260 } break; 1261 case Expression::E_UNOP: { 1262 UnOp* ue = e->cast<UnOp>(); 1263 run(env, ue->e()); 1264 } break; 1265 case Expression::E_CALL: { 1266 Call* ce = e->cast<Call>(); 1267 for (unsigned int i = 0; i < ce->argCount(); i++) { 1268 run(env, ce->arg(i)); 1269 } 1270 } break; 1271 case Expression::E_VARDECL: { 1272 auto* ve = e->cast<VarDecl>(); 1273 auto pi = pos.find(ve); 1274 if (pi == pos.end()) { 1275 pos.insert(std::pair<VarDecl*, int>(ve, -1)); 1276 run(env, ve->ti()); 1277 run(env, ve->e()); 1278 ve->payload(static_cast<int>(decls.size())); 1279 decls.push_back(ve); 1280 pi = pos.find(ve); 1281 pi->second = static_cast<int>(decls.size()) - 1; 1282 } else { 1283 assert(pi->second != -1); 1284 } 1285 } break; 1286 case Expression::E_TI: { 1287 auto* ti = e->cast<TypeInst>(); 1288 for (unsigned int i = 0; i < ti->ranges().size(); i++) { 1289 run(env, ti->ranges()[i]); 1290 } 1291 run(env, ti->domain()); 1292 } break; 1293 case Expression::E_TIID: 1294 break; 1295 case Expression::E_LET: { 1296 Let* let = e->cast<Let>(); 1297 scopes.push(); 1298 for (unsigned int i = 0; i < let->let().size(); i++) { 1299 run(env, let->let()[i]); 1300 if (auto* vd = let->let()[i]->dynamicCast<VarDecl>()) { 1301 scopes.add(env, vd); 1302 } 1303 } 1304 run(env, let->in()); 1305 VarDeclCmp poscmp(pos); 1306 std::stable_sort(let->let().begin(), let->let().end(), poscmp); 1307 for (unsigned int i = 0, j = 0; i < let->let().size(); i++) { 1308 if (auto* vd = let->let()[i]->dynamicCast<VarDecl>()) { 1309 let->letOrig()[j++] = vd->e(); 1310 for (unsigned int k = 0; k < vd->ti()->ranges().size(); k++) { 1311 let->letOrig()[j++] = vd->ti()->ranges()[k]->domain(); 1312 } 1313 } 1314 } 1315 scopes.pop(); 1316 } break; 1317 } 1318 if (env.ignoreUnknownIds) { 1319 std::vector<Expression*> toDelete; 1320 for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) { 1321 try { 1322 run(env, *it); 1323 } catch (TypeError&) { 1324 toDelete.push_back(*it); 1325 } 1326 for (Expression* de : toDelete) { 1327 e->ann().remove(de); 1328 } 1329 } 1330 } else { 1331 for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) { 1332 run(env, *it); 1333 } 1334 } 1335} 1336 1337KeepAlive add_coercion(EnvI& env, Model* m, Expression* e, const Type& funarg_t) { 1338 if (e->isa<ArrayAccess>() && e->type().dim() > 0) { 1339 auto* aa = e->cast<ArrayAccess>(); 1340 // Turn ArrayAccess into a slicing operation 1341 std::vector<Expression*> args; 1342 args.push_back(aa->v()); 1343 args.push_back(nullptr); 1344 std::vector<Expression*> slice; 1345 GCLock lock; 1346 for (unsigned int i = 0; i < aa->idx().size(); i++) { 1347 if (aa->idx()[i]->type().isSet()) { 1348 bool needIdxSet = true; 1349 bool needInter = true; 1350 if (auto* sl = aa->idx()[i]->dynamicCast<SetLit>()) { 1351 if ((sl->isv() != nullptr) && sl->isv()->size() == 1) { 1352 if (sl->isv()->min().isFinite() && sl->isv()->max().isFinite()) { 1353 args.push_back(sl); 1354 needIdxSet = false; 1355 } else if (sl->isv()->min() == -IntVal::infinity() && 1356 sl->isv()->max() == IntVal::infinity()) { 1357 needInter = false; 1358 } 1359 } 1360 } 1361 if (needIdxSet) { 1362 std::ostringstream oss; 1363 oss << "index_set"; 1364 if (aa->idx().size() > 1) { 1365 oss << "_" << (i + 1) << "of" << aa->idx().size(); 1366 } 1367 std::vector<Expression*> origIdxsetArgs(1); 1368 origIdxsetArgs[0] = aa->v(); 1369 Call* origIdxset = new Call(aa->v()->loc(), ASTString(oss.str()), origIdxsetArgs); 1370 FunctionI* fi = m->matchFn(env, origIdxset, false); 1371 if (fi == nullptr) { 1372 throw TypeError(env, e->loc(), "missing builtin " + oss.str()); 1373 } 1374 origIdxset->type(fi->rtype(env, origIdxsetArgs, false)); 1375 origIdxset->decl(fi); 1376 if (needInter) { 1377 auto* inter = new BinOp(aa->idx()[i]->loc(), aa->idx()[i], BOT_INTERSECT, origIdxset); 1378 inter->type(Type::parsetint()); 1379 args.push_back(inter); 1380 } else { 1381 args.push_back(origIdxset); 1382 } 1383 } 1384 slice.push_back(aa->idx()[i]); 1385 } else { 1386 auto* bo = new BinOp(aa->idx()[i]->loc(), aa->idx()[i], BOT_DOTDOT, aa->idx()[i]); 1387 bo->type(Type::parsetint()); 1388 slice.push_back(bo); 1389 } 1390 } 1391 auto* a_slice = new ArrayLit(e->loc(), slice); 1392 a_slice->type(Type::parsetint(1)); 1393 args[1] = a_slice; 1394 std::ostringstream oss; 1395 oss << "slice_" << (args.size() - 2) << "d"; 1396 Call* c = new Call(e->loc(), ASTString(oss.str()), args); 1397 FunctionI* fi = m->matchFn(env, c, false); 1398 if (fi == nullptr) { 1399 throw TypeError(env, e->loc(), "missing builtin " + oss.str()); 1400 } 1401 c->type(fi->rtype(env, args, false)); 1402 c->decl(fi); 1403 e = c; 1404 } 1405 if (e->type().dim() == funarg_t.dim() && 1406 (funarg_t.bt() == Type::BT_BOT || funarg_t.bt() == Type::BT_TOP || 1407 e->type().bt() == funarg_t.bt() || e->type().bt() == Type::BT_BOT)) { 1408 return e; 1409 } 1410 GCLock lock; 1411 Call* c = nullptr; 1412 if (e->type().dim() == 0 && funarg_t.dim() != 0) { 1413 if (e->type().isvar()) { 1414 throw TypeError(env, e->loc(), "cannot coerce var set into array"); 1415 } 1416 if (e->type().isOpt()) { 1417 throw TypeError(env, e->loc(), "cannot coerce opt set into array"); 1418 } 1419 std::vector<Expression*> set2a_args(1); 1420 set2a_args[0] = e; 1421 Call* set2a = new Call(e->loc(), ASTString("set2array"), set2a_args); 1422 FunctionI* fi = m->matchFn(env, set2a, false); 1423 if (fi != nullptr) { 1424 set2a->type(fi->rtype(env, set2a_args, false)); 1425 set2a->decl(fi); 1426 e = set2a; 1427 } 1428 } 1429 if (funarg_t.bt() == Type::BT_TOP || e->type().bt() == funarg_t.bt() || 1430 e->type().bt() == Type::BT_BOT) { 1431 KeepAlive ka(e); 1432 return ka; 1433 } 1434 std::vector<Expression*> args(1); 1435 args[0] = e; 1436 if (e->type().bt() == Type::BT_BOOL) { 1437 if (funarg_t.bt() == Type::BT_INT) { 1438 c = new Call(e->loc(), constants().ids.bool2int, args); 1439 } else if (funarg_t.bt() == Type::BT_FLOAT) { 1440 c = new Call(e->loc(), constants().ids.bool2float, args); 1441 } 1442 } else if (e->type().bt() == Type::BT_INT) { 1443 if (funarg_t.bt() == Type::BT_FLOAT) { 1444 c = new Call(e->loc(), constants().ids.int2float, args); 1445 } 1446 } 1447 if (c != nullptr) { 1448 FunctionI* fi = m->matchFn(env, c, false); 1449 assert(fi); 1450 Type ct = fi->rtype(env, args, false); 1451 ct.cv(e->type().cv()); 1452 c->type(ct); 1453 c->decl(fi); 1454 KeepAlive ka(c); 1455 return ka; 1456 } 1457 throw TypeError(env, e->loc(), 1458 "cannot determine coercion from type " + e->type().toString(env) + " to type " + 1459 funarg_t.toString(env)); 1460} 1461KeepAlive add_coercion(EnvI& env, Model* m, Expression* e, Expression* funarg) { 1462 return add_coercion(env, m, e, funarg->type()); 1463} 1464 1465template <bool ignoreVarDecl> 1466class Typer { 1467private: 1468 EnvI& _env; 1469 Model* _model; 1470 std::vector<TypeError>& _typeErrors; 1471 bool _ignoreUndefined; 1472 1473public: 1474 Typer(EnvI& env, Model* model, std::vector<TypeError>& typeErrors, bool ignoreUndefined) 1475 : _env(env), _model(model), _typeErrors(typeErrors), _ignoreUndefined(ignoreUndefined) {} 1476 /// Check annotations when expression is finished 1477 void exit(Expression* e) { 1478 for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) { 1479 if (!(*it)->type().isAnn()) { 1480 throw TypeError(_env, (*it)->loc(), 1481 "expected annotation, got `" + (*it)->type().toString(_env) + "'"); 1482 } 1483 } 1484 } 1485 bool enter(Expression* /*e*/) { return true; } 1486 /// Visit integer literal 1487 void vIntLit(const IntLit& /*i*/) {} 1488 /// Visit floating point literal 1489 void vFloatLit(const FloatLit& /*f*/) {} 1490 /// Visit Boolean literal 1491 void vBoolLit(const BoolLit& /*b*/) {} 1492 /// Visit set literal 1493 void vSetLit(SetLit& sl) { 1494 Type ty; 1495 ty.st(Type::ST_SET); 1496 if (sl.isv() != nullptr) { 1497 ty.bt(Type::BT_INT); 1498 ty.enumId(sl.type().enumId()); 1499 sl.type(ty); 1500 return; 1501 } 1502 if (sl.fsv() != nullptr) { 1503 ty.bt(Type::BT_FLOAT); 1504 sl.type(ty); 1505 return; 1506 } 1507 unsigned int enumId = sl.v().size() > 0 ? sl.v()[0]->type().enumId() : 0; 1508 for (unsigned int i = 0; i < sl.v().size(); i++) { 1509 Type vi_t = sl.v()[i]->type(); 1510 vi_t.ot(Type::OT_PRESENT); 1511 if (sl.v()[i] == constants().absent) { 1512 continue; 1513 } 1514 if (vi_t.dim() > 0) { 1515 throw TypeError(_env, sl.v()[i]->loc(), "set literals cannot contain arrays"); 1516 } 1517 if (vi_t.st() == Type::ST_SET) { 1518 throw TypeError(_env, sl.v()[i]->loc(), "set literals cannot contain sets"); 1519 } 1520 if (vi_t.isvar()) { 1521 ty.ti(Type::TI_VAR); 1522 } 1523 if (vi_t.cv()) { 1524 ty.cv(true); 1525 } 1526 if (enumId != vi_t.enumId()) { 1527 enumId = 0; 1528 } 1529 if (!Type::btSubtype(vi_t, ty, true)) { 1530 if (ty.bt() == Type::BT_UNKNOWN || Type::btSubtype(ty, vi_t, true)) { 1531 ty.bt(vi_t.bt()); 1532 } else { 1533 throw TypeError(_env, sl.loc(), "non-uniform set literal"); 1534 } 1535 } 1536 } 1537 ty.enumId(enumId); 1538 if (ty.bt() == Type::BT_UNKNOWN) { 1539 ty.bt(Type::BT_BOT); 1540 } else { 1541 if (ty.isvar() && ty.bt() != Type::BT_INT) { 1542 if (ty.bt() == Type::BT_BOOL) { 1543 ty.bt(Type::BT_INT); 1544 } else { 1545 throw TypeError(_env, sl.loc(), "cannot coerce set literal element to var int"); 1546 } 1547 } 1548 for (unsigned int i = 0; i < sl.v().size(); i++) { 1549 sl.v()[i] = add_coercion(_env, _model, sl.v()[i], ty)(); 1550 } 1551 } 1552 sl.type(ty); 1553 } 1554 /// Visit string literal 1555 void vStringLit(const StringLit& /*sl*/) {} 1556 /// Visit identifier 1557 void vId(Id& id) { 1558 if (&id != constants().absent) { 1559 assert(!id.decl()->type().isunknown()); 1560 id.type(id.decl()->type()); 1561 } 1562 } 1563 /// Visit anonymous variable 1564 void vAnonVar(const AnonVar& /*v*/) {} 1565 /// Visit array literal 1566 void vArrayLit(ArrayLit& al) { 1567 Type ty; 1568 ty.dim(static_cast<int>(al.dims())); 1569 std::vector<AnonVar*> anons; 1570 bool haveAbsents = false; 1571 bool haveInferredType = false; 1572 for (unsigned int i = 0; i < al.size(); i++) { 1573 Expression* vi = al[i]; 1574 if (vi->type().dim() > 0) { 1575 throw TypeError(_env, vi->loc(), "arrays cannot be elements of arrays"); 1576 } 1577 if (vi == constants().absent) { 1578 haveAbsents = true; 1579 } 1580 auto* av = vi->dynamicCast<AnonVar>(); 1581 if (av != nullptr) { 1582 ty.ti(Type::TI_VAR); 1583 anons.push_back(av); 1584 } else if (vi->type().isvar()) { 1585 ty.ti(Type::TI_VAR); 1586 } 1587 if (vi->type().cv()) { 1588 ty.cv(true); 1589 } 1590 if (vi->type().isOpt()) { 1591 ty.ot(Type::OT_OPTIONAL); 1592 } 1593 1594 if (ty.bt() == Type::BT_UNKNOWN) { 1595 if (av == nullptr) { 1596 if (haveInferredType) { 1597 if (ty.st() != vi->type().st() && vi->type().ot() != Type::OT_OPTIONAL) { 1598 throw TypeError(_env, al.loc(), "non-uniform array literal"); 1599 } 1600 } else { 1601 haveInferredType = true; 1602 ty.st(vi->type().st()); 1603 } 1604 if (vi->type().bt() != Type::BT_BOT) { 1605 ty.bt(vi->type().bt()); 1606 ty.enumId(vi->type().enumId()); 1607 } 1608 } 1609 } else { 1610 if (av == nullptr) { 1611 if (vi->type().bt() == Type::BT_BOT) { 1612 if (vi->type().st() != ty.st() && vi->type().ot() != Type::OT_OPTIONAL) { 1613 throw TypeError(_env, al.loc(), "non-uniform array literal"); 1614 } 1615 if (vi->type().enumId() != 0 && ty.enumId() != vi->type().enumId()) { 1616 ty.enumId(0); 1617 } 1618 } else { 1619 unsigned int tyEnumId = ty.enumId(); 1620 ty.enumId(vi->type().enumId()); 1621 if (Type::btSubtype(ty, vi->type(), true)) { 1622 ty.bt(vi->type().bt()); 1623 } 1624 if (tyEnumId != vi->type().enumId()) { 1625 ty.enumId(0); 1626 } 1627 if (!Type::btSubtype(vi->type(), ty, true) || ty.st() != vi->type().st()) { 1628 throw TypeError(_env, al.loc(), "non-uniform array literal"); 1629 } 1630 } 1631 } 1632 } 1633 } 1634 if (ty.bt() == Type::BT_UNKNOWN) { 1635 ty.bt(Type::BT_BOT); 1636 if (!anons.empty()) { 1637 throw TypeError(_env, al.loc(), 1638 "array literal must contain at least one non-anonymous variable"); 1639 } 1640 if (haveAbsents) { 1641 throw TypeError(_env, al.loc(), "array literal must contain at least one non-absent value"); 1642 } 1643 } else { 1644 Type at = ty; 1645 at.dim(0); 1646 if (at.ti() == Type::TI_VAR && at.st() == Type::ST_SET && at.bt() != Type::BT_INT) { 1647 if (at.bt() == Type::BT_BOOL) { 1648 ty.bt(Type::BT_INT); 1649 at.bt(Type::BT_INT); 1650 } else { 1651 throw TypeError(_env, al.loc(), "cannot coerce array element to var set of int"); 1652 } 1653 } 1654 for (auto& anon : anons) { 1655 anon->type(at); 1656 } 1657 for (unsigned int i = 0; i < al.size(); i++) { 1658 al.set(i, add_coercion(_env, _model, al[i], at)()); 1659 } 1660 } 1661 if (ty.enumId() != 0) { 1662 std::vector<unsigned int> enumIds(ty.dim() + 1); 1663 for (int i = 0; i < ty.dim(); i++) { 1664 enumIds[i] = 0; 1665 } 1666 enumIds[ty.dim()] = ty.enumId(); 1667 ty.enumId(_env.registerArrayEnum(enumIds)); 1668 } 1669 al.type(ty); 1670 } 1671 /// Visit array access 1672 void vArrayAccess(ArrayAccess& aa) { 1673 if (aa.v()->type().dim() == 0) { 1674 if (aa.v()->type().st() == Type::ST_SET) { 1675 Type tv = aa.v()->type(); 1676 tv.st(Type::ST_PLAIN); 1677 tv.dim(1); 1678 aa.v(add_coercion(_env, _model, aa.v(), tv)()); 1679 } else { 1680 std::ostringstream oss; 1681 oss << "array access attempted on expression of type `" << aa.v()->type().toString(_env) 1682 << "'"; 1683 throw TypeError(_env, aa.v()->loc(), oss.str()); 1684 } 1685 } else if (aa.v()->isa<ArrayAccess>()) { 1686 aa.v(add_coercion(_env, _model, aa.v(), aa.v()->type())()); 1687 } 1688 if (aa.v()->type().dim() != aa.idx().size()) { 1689 std::ostringstream oss; 1690 oss << aa.v()->type().dim() << "-dimensional array accessed with " << aa.idx().size() 1691 << (aa.idx().size() == 1 ? " expression" : " expressions"); 1692 throw TypeError(_env, aa.v()->loc(), oss.str()); 1693 } 1694 Type tt = aa.v()->type(); 1695 if (tt.enumId() != 0) { 1696 const std::vector<unsigned int>& arrayEnumIds = _env.getArrayEnum(tt.enumId()); 1697 std::vector<unsigned int> newArrayEnumids; 1698 1699 for (unsigned int i = 0; i < arrayEnumIds.size() - 1; i++) { 1700 Expression* aai = aa.idx()[i]; 1701 // Check if index is slice operator, and convert to correct enum type 1702 if (auto* aai_sl = aai->dynamicCast<SetLit>()) { 1703 if (IntSetVal* aai_isv = aai_sl->isv()) { 1704 if (aai_isv->min() == -IntVal::infinity() && aai_isv->max() == IntVal::infinity()) { 1705 Type aai_sl_t = aai_sl->type(); 1706 aai_sl_t.enumId(arrayEnumIds[i]); 1707 aai_sl->type(aai_sl_t); 1708 } 1709 } 1710 } else if (auto* aai_bo = aai->dynamicCast<BinOp>()) { 1711 if (aai_bo->op() == BOT_DOTDOT) { 1712 Type aai_bo_t = aai_bo->type(); 1713 if (auto* il = aai_bo->lhs()->dynamicCast<IntLit>()) { 1714 if (il->v() == -IntVal::infinity()) { 1715 // Expression is ..X, so result gets enum type of X 1716 aai_bo_t.enumId(aai_bo->rhs()->type().enumId()); 1717 } 1718 } else if (auto* il = aai_bo->rhs()->dynamicCast<IntLit>()) { 1719 if (il->v() == IntVal::infinity()) { 1720 // Expression is X.., so result gets enum type of X 1721 aai_bo_t.enumId(aai_bo->lhs()->type().enumId()); 1722 } 1723 } 1724 aai_bo->type(aai_bo_t); 1725 } 1726 } 1727 if (aai->type().isSet()) { 1728 newArrayEnumids.push_back(arrayEnumIds[i]); 1729 } 1730 1731 if (arrayEnumIds[i] != 0) { 1732 if (aa.idx()[i]->type().enumId() != arrayEnumIds[i]) { 1733 std::ostringstream oss; 1734 oss << "array index "; 1735 if (aa.idx().size() > 1) { 1736 oss << (i + 1) << " "; 1737 } 1738 oss << "must be `" << _env.getEnum(arrayEnumIds[i])->e()->id()->str() << "', but is `" 1739 << aa.idx()[i]->type().toString(_env) << "'"; 1740 throw TypeError(_env, aa.loc(), oss.str()); 1741 } 1742 } 1743 } 1744 if (newArrayEnumids.empty()) { 1745 tt.enumId(arrayEnumIds[arrayEnumIds.size() - 1]); 1746 } else { 1747 newArrayEnumids.push_back(arrayEnumIds[arrayEnumIds.size() - 1]); 1748 int newEnumId = _env.registerArrayEnum(newArrayEnumids); 1749 tt.enumId(newEnumId); 1750 } 1751 } 1752 int n_dimensions = 0; 1753 bool isVarAccess = false; 1754 bool isSlice = false; 1755 for (unsigned int i = 0; i < aa.idx().size(); i++) { 1756 Expression* aai = aa.idx()[i]; 1757 if (aai->isa<AnonVar>()) { 1758 aai->type(Type::varint()); 1759 } 1760 if ((aai->type().bt() != Type::BT_INT && aai->type().bt() != Type::BT_BOOL) || 1761 aai->type().dim() != 0) { 1762 throw TypeError(_env, aa.loc(), 1763 "array index must be `int' or `set of int', but is `" + 1764 aai->type().toString(_env) + "'"); 1765 } 1766 if (aai->type().isSet()) { 1767 if (isVarAccess || aai->type().isvar()) { 1768 throw TypeError(_env, aa.loc(), 1769 "array slicing with variable range or index not supported"); 1770 } 1771 isSlice = true; 1772 aa.idx()[i] = add_coercion(_env, _model, aai, Type::varsetint())(); 1773 n_dimensions++; 1774 } else { 1775 aa.idx()[i] = add_coercion(_env, _model, aai, Type::varint())(); 1776 } 1777 1778 if (aai->type().isOpt()) { 1779 tt.ot(Type::OT_OPTIONAL); 1780 } 1781 if (aai->type().isvar()) { 1782 isVarAccess = true; 1783 if (isSlice) { 1784 throw TypeError(_env, aa.loc(), 1785 "array slicing with variable range or index not supported"); 1786 } 1787 tt.ti(Type::TI_VAR); 1788 if (tt.bt() == Type::BT_ANN || tt.bt() == Type::BT_STRING) { 1789 throw TypeError(_env, aai->loc(), 1790 std::string("array access using a variable not supported for array of ") + 1791 (tt.bt() == Type::BT_ANN ? "ann" : "string")); 1792 } 1793 } 1794 tt.dim(n_dimensions); 1795 if (aai->type().cv()) { 1796 tt.cv(true); 1797 } 1798 } 1799 aa.type(tt); 1800 } 1801 /// Visit array comprehension 1802 void vComprehension(Comprehension& c) { 1803 Type tt = c.e()->type(); 1804 typedef std::unordered_map<VarDecl*, std::pair<int, int>> genMap_t; 1805 typedef std::unordered_map<VarDecl*, std::vector<Expression*>> whereMap_t; 1806 genMap_t generatorMap; 1807 whereMap_t whereMap; 1808 int declCount = 0; 1809 1810 for (int i = 0; i < c.numberOfGenerators(); i++) { 1811 for (int j = 0; j < c.numberOfDecls(i); j++) { 1812 generatorMap[c.decl(i, j)] = std::pair<int, int>(i, declCount++); 1813 whereMap[c.decl(i, j)] = std::vector<Expression*>(); 1814 } 1815 Expression* g_in = c.in(i); 1816 if (g_in != nullptr) { 1817 const Type& ty_in = g_in->type(); 1818 if (ty_in == Type::varsetint()) { 1819 if (!c.set()) { 1820 tt.ot(Type::OT_OPTIONAL); 1821 } 1822 tt.ti(Type::TI_VAR); 1823 tt.cv(true); 1824 } 1825 if (ty_in.cv()) { 1826 tt.cv(true); 1827 } 1828 if (c.where(i) != nullptr) { 1829 if (c.where(i)->type() == Type::varbool()) { 1830 if (!c.set()) { 1831 tt.ot(Type::OT_OPTIONAL); 1832 } 1833 tt.ti(Type::TI_VAR); 1834 tt.cv(true); 1835 } else if (c.where(i)->type() != Type::parbool()) { 1836 throw TypeError( 1837 _env, c.where(i)->loc(), 1838 "where clause must be bool, but is `" + c.where(i)->type().toString(_env) + "'"); 1839 } 1840 if (c.where(i)->type().cv()) { 1841 tt.cv(true); 1842 } 1843 1844 // Try to move parts of the where clause to earlier generators 1845 std::vector<Expression*> wherePartsStack; 1846 std::vector<Expression*> whereParts; 1847 wherePartsStack.push_back(c.where(i)); 1848 while (!wherePartsStack.empty()) { 1849 Expression* e = wherePartsStack.back(); 1850 wherePartsStack.pop_back(); 1851 if (auto* bo = e->dynamicCast<BinOp>()) { 1852 if (bo->op() == BOT_AND) { 1853 wherePartsStack.push_back(bo->rhs()); 1854 wherePartsStack.push_back(bo->lhs()); 1855 } else { 1856 whereParts.push_back(e); 1857 } 1858 } else { 1859 whereParts.push_back(e); 1860 } 1861 } 1862 1863 for (auto* wp : whereParts) { 1864 class FindLatestGen : public EVisitor { 1865 public: 1866 int declIndex; 1867 VarDecl* decl; 1868 const genMap_t& generatorMap; 1869 Comprehension* comp; 1870 FindLatestGen(const genMap_t& generatorMap0, Comprehension* comp0) 1871 : declIndex(-1), 1872 decl(comp0->decl(0, 0)), 1873 generatorMap(generatorMap0), 1874 comp(comp0) {} 1875 void vId(const Id& ident) { 1876 auto it = generatorMap.find(ident.decl()); 1877 if (it != generatorMap.end() && it->second.second > declIndex) { 1878 declIndex = it->second.second; 1879 decl = ident.decl(); 1880 int gen = it->second.first; 1881 while (comp->in(gen) == nullptr && gen < comp->numberOfGenerators() - 1) { 1882 declIndex++; 1883 gen++; 1884 decl = comp->decl(gen, 0); 1885 } 1886 } 1887 } 1888 } flg(generatorMap, &c); 1889 top_down(flg, wp); 1890 whereMap[flg.decl].push_back(wp); 1891 } 1892 } 1893 } else { 1894 assert(c.where(i) != nullptr); 1895 whereMap[c.decl(i, 0)].push_back(c.where(i)); 1896 } 1897 } 1898 1899 { 1900 GCLock lock; 1901 Generators generators; 1902 for (int i = 0; i < c.numberOfGenerators(); i++) { 1903 std::vector<VarDecl*> decls; 1904 for (int j = 0; j < c.numberOfDecls(i); j++) { 1905 decls.push_back(c.decl(i, j)); 1906 KeepAlive c_in = 1907 c.in(i) != nullptr ? add_coercion(_env, _model, c.in(i), c.in(i)->type()) : nullptr; 1908 if (!whereMap[c.decl(i, j)].empty()) { 1909 // need a generator for all the decls up to this point 1910 Expression* whereExpr = whereMap[c.decl(i, j)][0]; 1911 for (unsigned int k = 1; k < whereMap[c.decl(i, j)].size(); k++) { 1912 GCLock lock; 1913 auto* bo = 1914 new BinOp(Location().introduce(), whereExpr, BOT_AND, whereMap[c.decl(i, j)][k]); 1915 Type bo_t = whereMap[c.decl(i, j)][k]->type().isPar() && whereExpr->type().isPar() 1916 ? Type::parbool() 1917 : Type::varbool(); 1918 if (whereMap[c.decl(i, j)][k]->type().cv() || whereExpr->type().cv()) { 1919 bo_t.cv(true); 1920 } 1921 bo->type(bo_t); 1922 whereExpr = bo; 1923 } 1924 generators.g.emplace_back(decls, c_in(), whereExpr); 1925 decls.clear(); 1926 } else if (j == c.numberOfDecls(i) - 1) { 1927 generators.g.emplace_back(decls, c_in(), nullptr); 1928 decls.clear(); 1929 } 1930 } 1931 } 1932 c.init(c.e(), generators); 1933 } 1934 1935 if (c.set()) { 1936 if (c.e()->type().dim() != 0 || c.e()->type().st() == Type::ST_SET) { 1937 throw TypeError(_env, c.e()->loc(), 1938 "set comprehension expression must be scalar, but is `" + 1939 c.e()->type().toString(_env) + "'"); 1940 } 1941 tt.st(Type::ST_SET); 1942 if (tt.isvar()) { 1943 c.e(add_coercion(_env, _model, c.e(), Type::varint())()); 1944 tt.bt(Type::BT_INT); 1945 } 1946 } else { 1947 if (c.e()->type().dim() != 0) { 1948 throw TypeError(_env, c.e()->loc(), "array comprehension expression cannot be an array"); 1949 } 1950 tt.dim(1); 1951 if (tt.enumId() != 0) { 1952 std::vector<unsigned int> enumIds(2); 1953 enumIds[0] = 0; 1954 enumIds[1] = tt.enumId(); 1955 tt.enumId(_env.registerArrayEnum(enumIds)); 1956 } 1957 } 1958 c.type(tt); 1959 } 1960 /// Visit array comprehension generator 1961 void vComprehensionGenerator(Comprehension& c, int gen_i) { 1962 Expression* g_in = c.in(gen_i); 1963 if (g_in == nullptr) { 1964 // This is an "assignment generator" (i = expr) 1965 assert(c.where(gen_i) != nullptr); 1966 assert(c.numberOfDecls(gen_i) == 1); 1967 const Type& ty_where = c.where(gen_i)->type(); 1968 c.decl(gen_i, 0)->type(ty_where); 1969 c.decl(gen_i, 0)->ti()->type(ty_where); 1970 } else { 1971 const Type& ty_in = g_in->type(); 1972 if (ty_in != Type::varsetint() && ty_in != Type::parsetint() && ty_in.dim() != 1) { 1973 throw TypeError(_env, g_in->loc(), 1974 "generator expression must be (par or var) set of int or one-dimensional " 1975 "array, but is `" + 1976 ty_in.toString(_env) + "'"); 1977 } 1978 Type ty_id; 1979 if (ty_in.dim() == 0) { 1980 ty_id = Type::parint(); 1981 ty_id.enumId(ty_in.enumId()); 1982 } else { 1983 ty_id = ty_in; 1984 if (ty_in.enumId() != 0) { 1985 const std::vector<unsigned int>& enumIds = _env.getArrayEnum(ty_in.enumId()); 1986 ty_id.enumId(enumIds.back()); 1987 } 1988 ty_id.dim(0); 1989 } 1990 for (int j = 0; j < c.numberOfDecls(gen_i); j++) { 1991 c.decl(gen_i, j)->type(ty_id); 1992 c.decl(gen_i, j)->ti()->type(ty_id); 1993 } 1994 } 1995 } 1996 /// Visit if-then-else 1997 void vITE(ITE& ite) { 1998 bool mustBeBool = false; 1999 if (ite.elseExpr() == nullptr) { 2000 // this is an "if <cond> then <expr> endif" so the <expr> must be bool 2001 ite.elseExpr(constants().boollit(true)); 2002 mustBeBool = true; 2003 } 2004 Type tret = ite.elseExpr()->type(); 2005 std::vector<AnonVar*> anons; 2006 bool allpar = !(tret.isvar()); 2007 if (tret.isunknown()) { 2008 if (auto* av = ite.elseExpr()->dynamicCast<AnonVar>()) { 2009 allpar = false; 2010 anons.push_back(av); 2011 } else { 2012 throw TypeError(_env, ite.elseExpr()->loc(), 2013 "cannot infer type of expression in `else' branch of conditional"); 2014 } 2015 } 2016 bool allpresent = !(tret.isOpt()); 2017 bool varcond = false; 2018 for (int i = 0; i < ite.size(); i++) { 2019 Expression* eif = ite.ifExpr(i); 2020 Expression* ethen = ite.thenExpr(i); 2021 varcond = varcond || (eif->type() == Type::varbool()); 2022 if (eif->type() != Type::parbool() && eif->type() != Type::varbool()) { 2023 throw TypeError( 2024 _env, eif->loc(), 2025 "expected bool conditional expression, got `" + eif->type().toString(_env) + "'"); 2026 } 2027 if (eif->type().cv()) { 2028 tret.cv(true); 2029 } 2030 if (ethen->type().isunknown()) { 2031 if (auto* av = ethen->dynamicCast<AnonVar>()) { 2032 allpar = false; 2033 anons.push_back(av); 2034 } else { 2035 throw TypeError(_env, ethen->loc(), 2036 "cannot infer type of expression in `then' branch of conditional"); 2037 } 2038 } else { 2039 if (tret.isbot() || tret.isunknown()) { 2040 tret.bt(ethen->type().bt()); 2041 } 2042 if (mustBeBool && 2043 (ethen->type().bt() != Type::BT_BOOL || ethen->type().dim() > 0 || 2044 ethen->type().st() != Type::ST_PLAIN || ethen->type().ot() != Type::OT_PRESENT)) { 2045 throw TypeError(_env, ite.loc(), 2046 std::string("conditional without `else' branch must have bool type, ") + 2047 "but `then' branch has type `" + ethen->type().toString(_env) + "'"); 2048 } 2049 if ((!ethen->type().isbot() && !Type::btSubtype(ethen->type(), tret, true) && 2050 !Type::btSubtype(tret, ethen->type(), true)) || 2051 ethen->type().st() != tret.st() || ethen->type().dim() != tret.dim()) { 2052 throw TypeError(_env, ethen->loc(), 2053 "type mismatch in branches of conditional. `then' branch has type `" + 2054 ethen->type().toString(_env) + "', but `else' branch has type `" + 2055 tret.toString(_env) + "'"); 2056 } 2057 if (Type::btSubtype(tret, ethen->type(), true)) { 2058 tret.bt(ethen->type().bt()); 2059 } 2060 if (tret.enumId() != 0 && ethen->type().enumId() == 0) { 2061 tret.enumId(0); 2062 } 2063 if (ethen->type().isvar()) { 2064 allpar = false; 2065 } 2066 if (ethen->type().isOpt()) { 2067 allpresent = false; 2068 } 2069 if (ethen->type().cv()) { 2070 tret.cv(true); 2071 } 2072 } 2073 } 2074 Type tret_var(tret); 2075 tret_var.ti(Type::TI_VAR); 2076 for (auto& anon : anons) { 2077 anon->type(tret_var); 2078 } 2079 for (int i = 0; i < ite.size(); i++) { 2080 ite.thenExpr(i, add_coercion(_env, _model, ite.thenExpr(i), tret)()); 2081 } 2082 ite.elseExpr(add_coercion(_env, _model, ite.elseExpr(), tret)()); 2083 /// TODO: perhaps extend flattener to array types, but for now throw an error 2084 if (varcond && tret.dim() > 0) { 2085 throw TypeError(_env, ite.loc(), "conditional with var condition cannot have array type"); 2086 } 2087 if (varcond || !allpar) { 2088 tret.ti(Type::TI_VAR); 2089 } 2090 if (!allpresent) { 2091 tret.ot(Type::OT_OPTIONAL); 2092 } 2093 ite.type(tret); 2094 } 2095 /// Visit binary operator 2096 void vBinOp(BinOp& bop) { 2097 std::vector<Expression*> args(2); 2098 args[0] = bop.lhs(); 2099 args[1] = bop.rhs(); 2100 if (FunctionI* fi = _model->matchFn(_env, bop.opToString(), args, true)) { 2101 bop.lhs(add_coercion(_env, _model, bop.lhs(), fi->argtype(_env, args, 0))()); 2102 bop.rhs(add_coercion(_env, _model, bop.rhs(), fi->argtype(_env, args, 1))()); 2103 args[0] = bop.lhs(); 2104 args[1] = bop.rhs(); 2105 Type ty = fi->rtype(_env, args, true); 2106 ty.cv(bop.lhs()->type().cv() || bop.rhs()->type().cv()); 2107 bop.type(ty); 2108 2109 if (fi->e() != nullptr) { 2110 bop.decl(fi); 2111 } else { 2112 bop.decl(nullptr); 2113 } 2114 2115 if (bop.lhs()->type().isint() && bop.rhs()->type().isint() && 2116 (bop.op() == BOT_EQ || bop.op() == BOT_GQ || bop.op() == BOT_GR || bop.op() == BOT_NQ || 2117 bop.op() == BOT_LE || bop.op() == BOT_LQ)) { 2118 Call* call = bop.lhs()->dynamicCast<Call>(); 2119 Expression* rhs = bop.rhs(); 2120 BinOpType bot = bop.op(); 2121 if (call == nullptr) { 2122 call = bop.rhs()->dynamicCast<Call>(); 2123 rhs = bop.lhs(); 2124 switch (bop.op()) { 2125 case BOT_LQ: 2126 bot = BOT_GQ; 2127 break; 2128 case BOT_LE: 2129 bot = BOT_GR; 2130 break; 2131 case BOT_GQ: 2132 bot = BOT_LQ; 2133 break; 2134 case BOT_GR: 2135 bot = BOT_LE; 2136 break; 2137 default: 2138 break; 2139 } 2140 } 2141 if ((call != nullptr) && (call->id() == "count" || call->id() == "sum") && 2142 call->type().isvar()) { 2143 if (call->argCount() == 1 && call->arg(0)->isa<Comprehension>()) { 2144 auto* comp = call->arg(0)->cast<Comprehension>(); 2145 auto* inner_bo = comp->e()->dynamicCast<BinOp>(); 2146 if (inner_bo != nullptr) { 2147 if (inner_bo->op() == BOT_EQ && inner_bo->lhs()->type().isint()) { 2148 Expression* generated = inner_bo->lhs(); 2149 Expression* comparedTo = inner_bo->rhs(); 2150 if (comp->containsBoundVariable(comparedTo)) { 2151 if (comp->containsBoundVariable(generated)) { 2152 comparedTo = nullptr; 2153 } else { 2154 std::swap(generated, comparedTo); 2155 } 2156 } 2157 if (comparedTo != nullptr) { 2158 GCLock lock; 2159 ASTString cid; 2160 switch (bot) { 2161 case BOT_EQ: 2162 cid = ASTString("count_eq"); 2163 break; 2164 case BOT_GQ: 2165 cid = ASTString("count_leq"); 2166 break; 2167 case BOT_GR: 2168 cid = ASTString("count_lt"); 2169 break; 2170 case BOT_LQ: 2171 cid = ASTString("count_geq"); 2172 break; 2173 case BOT_LE: 2174 cid = ASTString("count_gt"); 2175 break; 2176 case BOT_NQ: 2177 cid = ASTString("count_neq"); 2178 break; 2179 default: 2180 assert(false); 2181 } 2182 2183 comp->e(generated); 2184 Type ct = comp->type(); 2185 ct.bt(generated->type().bt()); 2186 comp->type(ct); 2187 2188 std::vector<Expression*> args({comp, comparedTo, rhs}); 2189 FunctionI* newCall_decl = _model->matchFn(_env, cid, args, true); 2190 if (newCall_decl == nullptr) { 2191 std::ostringstream ss; 2192 ss << "could not replace binary operator by call to " << cid; 2193 throw InternalError(ss.str()); 2194 } 2195 Call* newCall = bop.morph(cid, args); 2196 newCall->decl(newCall_decl); 2197 } 2198 } 2199 } 2200 } else if (call->argCount() == 2 && call->arg(0)->type().isIntArray() && 2201 call->arg(1)->type().isint()) { 2202 GCLock lock; 2203 ASTString cid; 2204 switch (bot) { 2205 case BOT_EQ: 2206 cid = ASTString("count_eq"); 2207 break; 2208 case BOT_GQ: 2209 cid = ASTString("count_leq"); 2210 break; 2211 case BOT_GR: 2212 cid = ASTString("count_lt"); 2213 break; 2214 case BOT_LQ: 2215 cid = ASTString("count_geq"); 2216 break; 2217 case BOT_LE: 2218 cid = ASTString("count_gt"); 2219 break; 2220 case BOT_NQ: 2221 cid = ASTString("count_neq"); 2222 break; 2223 default: 2224 assert(false); 2225 } 2226 std::vector<Expression*> args({call->arg(0), call->arg(1), rhs}); 2227 FunctionI* newCall_decl = _model->matchFn(_env, cid, args, true); 2228 if (newCall_decl == nullptr) { 2229 std::ostringstream ss; 2230 ss << "could not replace binary operator by call to " << cid; 2231 throw InternalError(ss.str()); 2232 } 2233 Call* newCall = bop.morph(cid, args); 2234 newCall->decl(newCall_decl); 2235 } 2236 } 2237 } 2238 } else { 2239 std::ostringstream ss; 2240 ss << "type error in operator application for `" << bop.opToString() 2241 << "'. No matching operator found with left-hand side type `" 2242 << bop.lhs()->type().toString(_env) << "' and right-hand side type `" 2243 << bop.rhs()->type().toString(_env) << "'"; 2244 throw TypeError(_env, bop.loc(), ss.str()); 2245 } 2246 } 2247 /// Visit unary operator 2248 void vUnOp(UnOp& uop) { 2249 std::vector<Expression*> args(1); 2250 args[0] = uop.e(); 2251 if (FunctionI* fi = _model->matchFn(_env, uop.opToString(), args, true)) { 2252 uop.e(add_coercion(_env, _model, uop.e(), fi->argtype(_env, args, 0))()); 2253 args[0] = uop.e(); 2254 Type ty = fi->rtype(_env, args, true); 2255 ty.cv(uop.e()->type().cv()); 2256 uop.type(ty); 2257 if (fi->e() != nullptr) { 2258 uop.decl(fi); 2259 } 2260 } else { 2261 std::ostringstream ss; 2262 ss << "type error in operator application for `" << uop.opToString() 2263 << "'. No matching operator found with type `" << uop.e()->type().toString(_env) << "'"; 2264 throw TypeError(_env, uop.loc(), ss.str()); 2265 } 2266 } 2267 2268 /// Visit call 2269 void vCall(Call& call) { 2270 std::vector<Expression*> args(call.argCount()); 2271 for (auto i = static_cast<unsigned int>(args.size()); (i--) != 0U;) { 2272 args[i] = call.arg(i); 2273 } 2274 FunctionI* fi = _model->matchFn(_env, &call, true, true); 2275 2276 if (fi != nullptr && fi->id() == "symmetry_breaking_constraint" && fi->params().size() == 1 && 2277 fi->params()[0]->type().isbool()) { 2278 GCLock lock; 2279 call.id(ASTString("mzn_symmetry_breaking_constraint")); 2280 fi = _model->matchFn(_env, &call, true, true); 2281 } else if (fi != nullptr && fi->id() == "redundant_constraint" && fi->params().size() == 1 && 2282 fi->params()[0]->type().isbool()) { 2283 GCLock lock; 2284 call.id(ASTString("mzn_redundant_constraint")); 2285 fi = _model->matchFn(_env, &call, true, true); 2286 } 2287 2288 if ((fi->e() != nullptr) && fi->e()->isa<Call>()) { 2289 Call* next_call = fi->e()->cast<Call>(); 2290 if ((next_call->decl() != nullptr) && next_call->argCount() == fi->params().size() && 2291 _model->sameOverloading(_env, args, fi, next_call->decl())) { 2292 bool macro = true; 2293 for (unsigned int i = 0; i < fi->params().size(); i++) { 2294 if (!Expression::equal(next_call->arg(i), fi->params()[i]->id())) { 2295 macro = false; 2296 break; 2297 } 2298 } 2299 if (macro) { 2300 // Call is not a macro if it has a reification implementation 2301 GCLock lock; 2302 ASTString reif_id = _env.reifyId(fi->id()); 2303 std::vector<Type> tt(fi->params().size() + 1); 2304 for (unsigned int i = 0; i < fi->params().size(); i++) { 2305 tt[i] = fi->params()[i]->type(); 2306 } 2307 tt[fi->params().size()] = Type::varbool(); 2308 2309 macro = _model->matchFn(_env, reif_id, tt, true) == nullptr; 2310 } 2311 if (macro) { 2312 call.decl(next_call->decl()); 2313 for (ExpressionSetIter esi = next_call->ann().begin(); esi != next_call->ann().end(); 2314 ++esi) { 2315 call.addAnnotation(*esi); 2316 } 2317 call.rehash(); 2318 fi = next_call->decl(); 2319 } 2320 } 2321 } 2322 2323 bool cv = false; 2324 for (unsigned int i = 0; i < args.size(); i++) { 2325 if (auto* c = call.arg(i)->dynamicCast<Comprehension>()) { 2326 Type t_before = c->e()->type(); 2327 Type t = fi->argtype(_env, args, i); 2328 t.dim(0); 2329 c->e(add_coercion(_env, _model, c->e(), t)()); 2330 Type t_after = c->e()->type(); 2331 if (t_before != t_after) { 2332 Type ct = c->type(); 2333 ct.bt(t_after.bt()); 2334 c->type(ct); 2335 } 2336 } else { 2337 args[i] = add_coercion(_env, _model, call.arg(i), fi->argtype(_env, args, i))(); 2338 call.arg(i, args[i]); 2339 } 2340 cv = cv || args[i]->type().cv(); 2341 } 2342 // Replace par enums with their string versions 2343 if (call.id() == "format" || call.id() == "show" || call.id() == "showDzn" || 2344 call.id() == "showJSON") { 2345 if (call.arg(call.argCount() - 1)->type().isPar()) { 2346 unsigned int enumId = call.arg(call.argCount() - 1)->type().enumId(); 2347 if (enumId != 0U && call.arg(call.argCount() - 1)->type().dim() != 0) { 2348 const std::vector<unsigned int>& enumIds = _env.getArrayEnum(enumId); 2349 enumId = enumIds[enumIds.size() - 1]; 2350 } 2351 if (enumId > 0) { 2352 VarDecl* enumDecl = _env.getEnum(enumId)->e(); 2353 if (enumDecl->e() != nullptr) { 2354 Id* ti_id = _env.getEnum(enumId)->e()->id(); 2355 GCLock lock; 2356 std::vector<Expression*> args(3); 2357 args[0] = call.arg(call.argCount() - 1); 2358 if (args[0]->type().dim() > 1) { 2359 std::vector<Expression*> a1dargs(1); 2360 a1dargs[0] = args[0]; 2361 Call* array1d = new Call(Location().introduce(), ASTString("array1d"), a1dargs); 2362 Type array1dt = args[0]->type(); 2363 array1dt.dim(1); 2364 array1d->type(array1dt); 2365 args[0] = array1d; 2366 } 2367 args[1] = constants().boollit(call.id() == "showDzn"); 2368 args[2] = constants().boollit(call.id() == "showJSON"); 2369 ASTString enumName(create_enum_to_string_name(ti_id, "_toString_")); 2370 call.id(enumName); 2371 call.args(args); 2372 if (call.id() == "showDzn") { 2373 call.id(constants().ids.show); 2374 } 2375 fi = _model->matchFn(_env, &call, false, true); 2376 } 2377 } 2378 } 2379 } 2380 2381 // Set type and decl 2382 Type ty = fi->rtype(_env, args, true); 2383 ty.cv(cv); 2384 call.type(ty); 2385 2386 if (Call* deprecated = fi->ann().getCall(constants().ann.mzn_deprecated)) { 2387 // rewrite this call into a call to mzn_deprecate(..., e) 2388 GCLock lock; 2389 std::vector<Expression*> params(call.argCount()); 2390 for (unsigned int i = 0; i < params.size(); i++) { 2391 params[i] = call.arg(i); 2392 } 2393 Call* origCall = new Call(call.loc(), call.id(), params); 2394 origCall->type(ty); 2395 origCall->decl(fi); 2396 call.id(constants().ids.mzn_deprecate); 2397 std::vector<Expression*> args( 2398 {new StringLit(Location(), fi->id()), deprecated->arg(0), deprecated->arg(1), origCall}); 2399 call.args(args); 2400 FunctionI* deprecated_fi = _model->matchFn(_env, &call, false, true); 2401 call.decl(deprecated_fi); 2402 } else { 2403 call.decl(fi); 2404 } 2405 } 2406 /// Visit let 2407 void vLet(Let& let) { 2408 bool cv = false; 2409 bool isVar = false; 2410 for (unsigned int i = 0, j = 0; i < let.let().size(); i++) { 2411 Expression* li = let.let()[i]; 2412 cv = cv || li->type().cv(); 2413 if (auto* vdi = li->dynamicCast<VarDecl>()) { 2414 if (vdi->e() == nullptr && vdi->type().isSet() && vdi->type().isvar() && 2415 vdi->ti()->domain() == nullptr) { 2416 std::ostringstream ss; 2417 ss << "set element type for `" << vdi->id()->str() << "' is not finite"; 2418 _typeErrors.emplace_back(_env, vdi->loc(), ss.str()); 2419 } 2420 if (vdi->type().isPar() && (vdi->e() == nullptr)) { 2421 std::ostringstream ss; 2422 ss << "let variable `" << vdi->id()->v() << "' must be initialised"; 2423 throw TypeError(_env, vdi->loc(), ss.str()); 2424 } 2425 if (vdi->ti()->hasTiVariable()) { 2426 std::ostringstream ss; 2427 ss << "type-inst variables not allowed in type-inst for let variable `" 2428 << vdi->id()->str() << "'"; 2429 _typeErrors.emplace_back(_env, vdi->loc(), ss.str()); 2430 } 2431 let.letOrig()[j++] = vdi->e(); 2432 for (unsigned int k = 0; k < vdi->ti()->ranges().size(); k++) { 2433 let.letOrig()[j++] = vdi->ti()->ranges()[k]->domain(); 2434 } 2435 } 2436 isVar |= li->type().isvar(); 2437 } 2438 Type ty = let.in()->type(); 2439 ty.cv(cv); 2440 if (isVar && ty.bt() == Type::BT_BOOL && ty.dim() == 0) { 2441 ty.ti(Type::TI_VAR); 2442 } 2443 let.type(ty); 2444 } 2445 /// Visit variable declaration 2446 void vVarDecl(VarDecl& vd) { 2447 if (ignoreVarDecl) { 2448 if (vd.e() != nullptr) { 2449 Type vdt = vd.ti()->type(); 2450 Type vet = vd.e()->type(); 2451 if (vdt.enumId() != 0 && vdt.dim() > 0 && 2452 (vd.e()->isa<ArrayLit>() || vd.e()->isa<Comprehension>() || 2453 (vd.e()->isa<BinOp>() && vd.e()->cast<BinOp>()->op() == BOT_PLUSPLUS))) { 2454 // Special case: index sets of array literals and comprehensions automatically 2455 // coerce to any enum index set 2456 const std::vector<unsigned int>& enumIds = _env.getArrayEnum(vdt.enumId()); 2457 if (enumIds[enumIds.size() - 1] == 0) { 2458 vdt.enumId(0); 2459 } else { 2460 std::vector<unsigned int> nEnumIds(enumIds.size()); 2461 for (unsigned int i = 0; i < nEnumIds.size() - 1; i++) { 2462 nEnumIds[i] = 0; 2463 } 2464 nEnumIds[nEnumIds.size() - 1] = enumIds[enumIds.size() - 1]; 2465 vdt.enumId(_env.registerArrayEnum(nEnumIds)); 2466 } 2467 } else if (vd.ti()->isEnum() && vd.e()->isa<Call>()) { 2468 if (vd.e()->cast<Call>()->id() == "anon_enum") { 2469 vet.enumId(vdt.enumId()); 2470 } 2471 } 2472 2473 if (vd.type().isunknown()) { 2474 vd.ti()->type(vet); 2475 vd.type(vet); 2476 } else if (!_env.isSubtype(vet, vdt, true)) { 2477 if (vet == Type::bot(1) && vd.e()->isa<ArrayLit>() && 2478 vd.e()->cast<ArrayLit>()->size() == 0 && 2479 vdt.dim() != 0) { // NOLINT(bugprone-branch-clone): see TODO in other branch 2480 // this is okay: assigning an empty array (one-dimensional) to an array variable 2481 } else if (vd.ti()->isEnum() && vet == Type::parsetint()) { 2482 // let's ignore this for now (TODO: add an annotation to make sure only 2483 // compiler-generated ones are accepted) 2484 } else { 2485 const Location& loc = vd.e()->loc().isNonAlloc() ? vd.loc() : vd.e()->loc(); 2486 std::ostringstream ss; 2487 ss << "initialisation value for `" << vd.id()->str() 2488 << "' has invalid type-inst: expected `" << vd.ti()->type().toString(_env) 2489 << "', actual `" << vd.e()->type().toString(_env) << "'"; 2490 _typeErrors.emplace_back(_env, loc, ss.str()); 2491 } 2492 } else { 2493 vd.e(add_coercion(_env, _model, vd.e(), vd.ti()->type())()); 2494 } 2495 } else { 2496 assert(!vd.type().isunknown()); 2497 } 2498 } else { 2499 vd.type(vd.ti()->type()); 2500 vd.id()->type(vd.type()); 2501 } 2502 } 2503 /// Visit type inst 2504 void vTypeInst(TypeInst& ti) { 2505 Type tt = ti.type(); 2506 bool foundEnum = 2507 ti.ranges().size() > 0 && (ti.domain() != nullptr) && ti.domain()->type().enumId() != 0; 2508 if (ti.ranges().size() > 0) { 2509 bool foundTIId = false; 2510 for (unsigned int i = 0; i < ti.ranges().size(); i++) { 2511 TypeInst* ri = ti.ranges()[i]; 2512 assert(ri != nullptr); 2513 if (ri->type().cv()) { 2514 tt.cv(true); 2515 } 2516 if (ri->type().enumId() != 0) { 2517 foundEnum = true; 2518 } 2519 if (ri->type() == Type::top()) { 2520 // if (foundTIId) { 2521 // throw TypeError(_env,ri->loc(), 2522 // "only one type-inst variable allowed in array index"); 2523 // } else { 2524 foundTIId = true; 2525 // } 2526 } else if (ri->type() != Type::parint()) { 2527 assert(ri->isa<TypeInst>()); 2528 auto* riti = ri->cast<TypeInst>(); 2529 if (riti->domain() != nullptr) { 2530 throw TypeError(_env, ri->loc(), 2531 "array index set expression has invalid type, expected `set of int', " 2532 "actual `set of " + 2533 ri->type().toString(_env) + "'"); 2534 } 2535 throw TypeError(_env, ri->loc(), 2536 "cannot use `" + ri->type().toString(_env) + 2537 "' as array index set (did you mean `int'?)"); 2538 } 2539 } 2540 tt.dim(foundTIId ? -1 : static_cast<int>(ti.ranges().size())); 2541 } 2542 if ((ti.domain() != nullptr) && ti.domain()->type().cv()) { 2543 tt.cv(true); 2544 } 2545 if (ti.domain() != nullptr) { 2546 if (TIId* tiid = ti.domain()->dynamicCast<TIId>()) { 2547 if (tiid->isEnum()) { 2548 tt.bt(Type::BT_INT); 2549 } 2550 } else { 2551 if (ti.domain()->type().ti() != Type::TI_PAR || ti.domain()->type().st() != Type::ST_SET) { 2552 throw TypeError( 2553 _env, ti.domain()->loc().isNonAlloc() ? ti.loc() : ti.domain()->loc(), 2554 "type-inst must be par set but is `" + ti.domain()->type().toString(_env) + "'"); 2555 } 2556 if (ti.domain()->type().dim() != 0) { 2557 throw TypeError(_env, ti.domain()->loc(), "type-inst cannot be an array"); 2558 } 2559 } 2560 } 2561 if (tt.isunknown() && (ti.domain() != nullptr)) { 2562 assert(ti.domain()); 2563 switch (ti.domain()->type().bt()) { 2564 case Type::BT_INT: 2565 case Type::BT_FLOAT: 2566 break; 2567 case Type::BT_BOT: { 2568 Type tidt = ti.domain()->type(); 2569 tidt.bt(Type::BT_INT); 2570 ti.domain()->type(tidt); 2571 } break; 2572 default: 2573 throw TypeError(_env, ti.domain()->loc(), "type-inst must be int or float"); 2574 } 2575 tt.bt(ti.domain()->type().bt()); 2576 tt.enumId(ti.domain()->type().enumId()); 2577 } else { 2578 // assert(ti.domain()==NULL || ti.domain()->isa<TIId>()); 2579 } 2580 if (foundEnum) { 2581 std::vector<unsigned int> enumIds(ti.ranges().size() + 1); 2582 for (unsigned int i = 0; i < ti.ranges().size(); i++) { 2583 enumIds[i] = ti.ranges()[i]->type().enumId(); 2584 } 2585 enumIds[ti.ranges().size()] = ti.domain() != nullptr ? ti.domain()->type().enumId() : 0; 2586 int arrayEnumId = _env.registerArrayEnum(enumIds); 2587 tt.enumId(arrayEnumId); 2588 } 2589 2590 if (tt.st() == Type::ST_SET && tt.ti() == Type::TI_VAR && tt.bt() != Type::BT_INT && 2591 tt.bt() != Type::BT_TOP) { 2592 throw TypeError(_env, ti.loc(), "var set element types other than `int' not allowed"); 2593 } 2594 ti.type(tt); 2595 } 2596 void vTIId(TIId& id) {} 2597}; 2598 2599void typecheck(Env& env, Model* origModel, std::vector<TypeError>& typeErrors, 2600 bool ignoreUndefinedParameters, bool allowMultiAssignment, bool isFlatZinc) { 2601 Model* m; 2602 if (!isFlatZinc && origModel == env.model()) { 2603 // Combine all items into single model 2604 auto* combinedModel = new Model; 2605 class Combiner : public ItemVisitor { 2606 public: 2607 Model* m; 2608 Combiner(Model* m0) : m(m0) {} 2609 bool enter(Item* i) const { 2610 if (!i->isa<IncludeI>()) { 2611 m->addItem(i); 2612 } 2613 return true; 2614 } 2615 } _combiner(combinedModel); 2616 iter_items(_combiner, origModel); 2617 env.envi().originalModel = origModel; 2618 env.envi().model = combinedModel; 2619 m = combinedModel; 2620 } else { 2621 m = origModel; 2622 } 2623 2624 // Topological sorting 2625 TopoSorter ts(m); 2626 2627 std::vector<FunctionI*> functionItems; 2628 std::vector<AssignI*> assignItems; 2629 auto* enumItems = new Model; 2630 2631 class TSVFuns : public ItemVisitor { 2632 public: 2633 EnvI& env; 2634 Model* model; 2635 std::vector<FunctionI*>& fis; 2636 TSVFuns(EnvI& env0, Model* model0, std::vector<FunctionI*>& fis0) 2637 : env(env0), model(model0), fis(fis0) {} 2638 void vFunctionI(FunctionI* i) { 2639 (void)model->registerFn(env, i); 2640 fis.push_back(i); 2641 } 2642 } _tsvf(env.envi(), m, functionItems); 2643 iter_items(_tsvf, m); 2644 2645 class TSV0 : public ItemVisitor { 2646 public: 2647 EnvI& env; 2648 TopoSorter& ts; 2649 Model* model; 2650 bool hadSolveItem; 2651 std::vector<AssignI*>& ais; 2652 VarDeclI* objective; 2653 Model* enumis; 2654 bool isFlatZinc; 2655 TSV0(EnvI& env0, TopoSorter& ts0, Model* model0, std::vector<AssignI*>& ais0, Model* enumis0, 2656 bool isFlatZinc0) 2657 : env(env0), 2658 ts(ts0), 2659 model(model0), 2660 hadSolveItem(false), 2661 ais(ais0), 2662 objective(nullptr), 2663 enumis(enumis0), 2664 isFlatZinc(isFlatZinc0) {} 2665 void vAssignI(AssignI* i) { ais.push_back(i); } 2666 void vVarDeclI(VarDeclI* i) { 2667 ts.add(env, i, true, enumis); 2668 // initialise new identifier counter to be larger than existing identifier 2669 if (i->e()->id()->idn() >= 0) { 2670 env.minId(i->e()->id()->idn()); 2671 } else if (i->e()->id()->v().beginsWith("X_INTRODUCED_") && i->e()->id()->v().endsWith("_")) { 2672 std::string numId = i->e()->id()->v().substr(std::string("X_INTRODUCED_").size()); 2673 if (!numId.empty()) { 2674 numId = numId.substr(0, numId.size() - 1); 2675 if (!numId.empty()) { 2676 int vId = -1; 2677 try { 2678 vId = std::stoi(numId); 2679 } catch (std::exception&) { 2680 } 2681 if (vId >= 0) { 2682 env.minId(vId); 2683 } 2684 } 2685 } 2686 } 2687 } 2688 void vSolveI(SolveI* si) { 2689 if (hadSolveItem) { 2690 throw TypeError(env, si->loc(), "Only one solve item allowed"); 2691 } 2692 hadSolveItem = true; 2693 if (!isFlatZinc && (si->e() != nullptr)) { 2694 GCLock lock; 2695 auto* ti = new TypeInst(Location().introduce(), Type()); 2696 auto* obj = new VarDecl(Location().introduce(), ti, "_objective", si->e()); 2697 si->e(obj->id()); 2698 objective = new VarDeclI(Location().introduce(), obj); 2699 } 2700 } 2701 } _tsv0(env.envi(), ts, m, assignItems, enumItems, isFlatZinc); 2702 iter_items(_tsv0, m); 2703 if (_tsv0.objective != nullptr) { 2704 m->addItem(_tsv0.objective); 2705 ts.add(env.envi(), _tsv0.objective, true, enumItems); 2706 } 2707 2708 for (unsigned int i = 0; i < enumItems->size(); i++) { 2709 if (auto* ai = (*enumItems)[i]->dynamicCast<AssignI>()) { 2710 assignItems.push_back(ai); 2711 } else if (auto* vdi = (*enumItems)[i]->dynamicCast<VarDeclI>()) { 2712 m->addItem(vdi); 2713 ts.add(env.envi(), vdi, false, enumItems); 2714 } else { 2715 auto* fi = (*enumItems)[i]->dynamicCast<FunctionI>(); 2716 m->addItem(fi); 2717 (void)m->registerFn(env.envi(), fi); 2718 functionItems.push_back(fi); 2719 } 2720 } 2721 2722 auto* enumItems2 = new Model; 2723 2724 for (auto* ai : assignItems) { 2725 VarDecl* vd = nullptr; 2726 if (env.envi().ignoreUnknownIds) { 2727 try { 2728 vd = ts.get(env.envi(), ai->id(), ai->loc()); 2729 } catch (TypeError&) { 2730 } 2731 } else { 2732 vd = ts.get(env.envi(), ai->id(), ai->loc()); 2733 } 2734 if (vd != nullptr) { 2735 if (vd->e() != nullptr) { 2736 if (allowMultiAssignment) { 2737 GCLock lock; 2738 m->addItem(new ConstraintI( 2739 ai->loc(), 2740 new BinOp(ai->loc(), new Id(Location().introduce(), ai->id(), vd), BOT_EQ, ai->e()))); 2741 } else { 2742 throw TypeError(env.envi(), ai->loc(), "multiple assignment to the same variable"); 2743 } 2744 } else { 2745 vd->e(ai->e()); 2746 vd->ann().add(constants().ann.rhs_from_assignment); 2747 if (vd->ti()->isEnum()) { 2748 create_enum_mapper(env.envi(), m, vd->ti()->type().enumId(), vd, enumItems2); 2749 } 2750 } 2751 } 2752 ai->remove(); 2753 } 2754 2755 for (auto& i : *enumItems2) { 2756 if (auto* vdi = i->dynamicCast<VarDeclI>()) { 2757 m->addItem(vdi); 2758 ts.add(env.envi(), vdi, false, enumItems); 2759 } else { 2760 auto* fi = i->cast<FunctionI>(); 2761 m->addItem(fi); 2762 (void)m->registerFn(env.envi(), fi); 2763 functionItems.push_back(fi); 2764 } 2765 } 2766 2767 delete enumItems; 2768 delete enumItems2; 2769 2770 class TSV1 : public ItemVisitor { 2771 public: 2772 EnvI& env; 2773 TopoSorter& ts; 2774 TSV1(EnvI& env0, TopoSorter& ts0) : env(env0), ts(ts0) {} 2775 void vVarDeclI(VarDeclI* i) { ts.run(env, i->e()); } 2776 void vAssignI(AssignI* i) {} 2777 void vConstraintI(ConstraintI* i) { ts.run(env, i->e()); } 2778 void vSolveI(SolveI* i) { 2779 for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) { 2780 ts.run(env, *it); 2781 } 2782 ts.run(env, i->e()); 2783 } 2784 void vOutputI(OutputI* i) { ts.run(env, i->e()); } 2785 void vFunctionI(FunctionI* fi) { 2786 ts.run(env, fi->ti()); 2787 for (unsigned int i = 0; i < fi->params().size(); i++) { 2788 ts.run(env, fi->params()[i]); 2789 } 2790 for (ExpressionSetIter it = fi->ann().begin(); it != fi->ann().end(); ++it) { 2791 ts.run(env, *it); 2792 } 2793 ts.scopes.pushFun(); 2794 for (unsigned int i = 0; i < fi->params().size(); i++) { 2795 ts.scopes.add(env, fi->params()[i]); 2796 } 2797 ts.run(env, fi->e()); 2798 ts.scopes.pop(); 2799 } 2800 } _tsv1(env.envi(), ts); 2801 iter_items(_tsv1, m); 2802 2803 m->sortFn(); 2804 2805 { 2806 struct SortByPayload { 2807 bool operator()(Item* i0, Item* i1) { 2808 if (i0->isa<IncludeI>()) { 2809 return !i1->isa<IncludeI>(); 2810 } 2811 if (auto* vdi0 = i0->dynamicCast<VarDeclI>()) { 2812 if (auto* vdi1 = i1->dynamicCast<VarDeclI>()) { 2813 return vdi0->e()->payload() < vdi1->e()->payload(); 2814 } 2815 return !i1->isa<IncludeI>(); 2816 } 2817 return false; 2818 } 2819 } _sbp; 2820 2821 std::stable_sort(m->begin(), m->end(), _sbp); 2822 } 2823 2824 { 2825 Typer<false> ty(env.envi(), m, typeErrors, ignoreUndefinedParameters); 2826 BottomUpIterator<Typer<false>> bottomUpTyper(ty); 2827 for (auto& decl : ts.decls) { 2828 decl->payload(0); 2829 bottomUpTyper.run(decl->ti()); 2830 ty.vVarDecl(*decl); 2831 } 2832 for (auto& functionItem : functionItems) { 2833 bottomUpTyper.run(functionItem->ti()); 2834 for (unsigned int j = 0; j < functionItem->params().size(); j++) { 2835 bottomUpTyper.run(functionItem->params()[j]); 2836 } 2837 } 2838 } 2839 2840 m->fixFnMap(); 2841 2842 { 2843 Typer<true> ty(env.envi(), m, typeErrors, ignoreUndefinedParameters); 2844 BottomUpIterator<Typer<true>> bottomUpTyper(ty); 2845 2846 class TSV2 : public ItemVisitor { 2847 private: 2848 EnvI& _env; 2849 Model* _m; 2850 BottomUpIterator<Typer<true>>& _bottomUpTyper; 2851 std::vector<TypeError>& _typeErrors; 2852 2853 public: 2854 TSV2(EnvI& env0, Model* m0, BottomUpIterator<Typer<true>>& b, 2855 std::vector<TypeError>& typeErrors) 2856 : _env(env0), _m(m0), _bottomUpTyper(b), _typeErrors(typeErrors) {} 2857 void vVarDeclI(VarDeclI* i) { 2858 _bottomUpTyper.run(i->e()); 2859 if (i->e()->ti()->hasTiVariable()) { 2860 std::ostringstream ss; 2861 ss << "type-inst variables not allowed in type-inst for `" << i->e()->id()->str() << "'"; 2862 _typeErrors.emplace_back(_env, i->e()->loc(), ss.str()); 2863 } 2864 VarDecl* vdi = i->e(); 2865 if (vdi->e() == nullptr && vdi->type().isSet() && vdi->type().isvar() && 2866 vdi->ti()->domain() == nullptr) { 2867 std::ostringstream ss; 2868 ss << "set element type for `" << vdi->id()->str() << "' is not finite"; 2869 _typeErrors.emplace_back(_env, vdi->loc(), ss.str()); 2870 } 2871 if (i->e()->ann().contains(constants().ann.output_only)) { 2872 if (vdi->e() == nullptr) { 2873 _typeErrors.emplace_back( 2874 _env, vdi->loc(), 2875 "variables annotated with ::output_only must have a right hand side"); 2876 } else if (vdi->e()->type().isvar()) { 2877 _typeErrors.emplace_back(_env, vdi->loc(), 2878 "variables annotated with ::output_only must be par"); 2879 } 2880 } 2881 } 2882 void vAssignI(AssignI* i) { 2883 _bottomUpTyper.run(i->e()); 2884 if (!_env.isSubtype(i->e()->type(), i->decl()->ti()->type(), true)) { 2885 std::ostringstream ss; 2886 ss << "assignment value for `" << i->decl()->id()->str() 2887 << "' has invalid type-inst: expected `" << i->decl()->ti()->type().toString(_env) 2888 << "', actual `" << i->e()->type().toString(_env) << "'"; 2889 _typeErrors.emplace_back(_env, i->loc(), ss.str()); 2890 // Assign to "true" constant to avoid generating further errors that the parameter 2891 // is undefined 2892 i->decl()->e(constants().literalTrue); 2893 } 2894 } 2895 void vConstraintI(ConstraintI* i) { 2896 _bottomUpTyper.run(i->e()); 2897 if (!_env.isSubtype(i->e()->type(), Type::varbool(), true)) { 2898 throw TypeError(_env, i->loc(), 2899 "invalid type of constraint, expected `" + 2900 Type::varbool().toString(_env) + "', actual `" + 2901 i->e()->type().toString(_env) + "'"); 2902 } 2903 } 2904 void vSolveI(SolveI* i) { 2905 for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) { 2906 _bottomUpTyper.run(*it); 2907 if (!(*it)->type().isAnn()) { 2908 throw TypeError(_env, (*it)->loc(), 2909 "expected annotation, got `" + (*it)->type().toString(_env) + "'"); 2910 } 2911 } 2912 _bottomUpTyper.run(i->e()); 2913 if (i->e() != nullptr) { 2914 Type et = i->e()->type(); 2915 2916 bool needOptCoercion = et.isOpt() && et.isint(); 2917 if (needOptCoercion) { 2918 et.ot(Type::OT_PRESENT); 2919 } 2920 2921 if (!(_env.isSubtype(et, Type::varint(), true) || 2922 _env.isSubtype(et, Type::varfloat(), true))) { 2923 throw TypeError(_env, i->e()->loc(), 2924 "objective has invalid type, expected int or float, actual `" + 2925 et.toString(_env) + "'"); 2926 } 2927 2928 if (needOptCoercion) { 2929 GCLock lock; 2930 std::vector<Expression*> args(2); 2931 args[0] = i->e(); 2932 args[1] = constants().boollit(i->st() == SolveI::ST_MAX); 2933 Call* c = new Call(Location().introduce(), ASTString("objective_deopt_"), args); 2934 c->decl(_env.model->matchFn(_env, c, false)); 2935 assert(c->decl()); 2936 c->type(et); 2937 i->e(c); 2938 } 2939 } 2940 } 2941 void vOutputI(OutputI* i) { 2942 _bottomUpTyper.run(i->e()); 2943 if (i->e()->type() != Type::parstring(1) && i->e()->type() != Type::bot(1)) { 2944 throw TypeError(_env, i->e()->loc(), 2945 "invalid type in output item, expected `" + 2946 Type::parstring(1).toString(_env) + "', actual `" + 2947 i->e()->type().toString(_env) + "'"); 2948 } 2949 } 2950 void vFunctionI(FunctionI* i) { 2951 for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) { 2952 _bottomUpTyper.run(*it); 2953 if (!(*it)->type().isAnn()) { 2954 throw TypeError(_env, (*it)->loc(), 2955 "expected annotation, got `" + (*it)->type().toString(_env) + "'"); 2956 } 2957 } 2958 _bottomUpTyper.run(i->ti()); 2959 _bottomUpTyper.run(i->e()); 2960 if ((i->e() != nullptr) && !_env.isSubtype(i->e()->type(), i->ti()->type(), true)) { 2961 throw TypeError(_env, i->e()->loc(), 2962 "return type of function does not match body, declared type is `" + 2963 i->ti()->type().toString(_env) + "', body type is `" + 2964 i->e()->type().toString(_env) + "'"); 2965 } 2966 if ((i->e() != nullptr) && i->e()->type().isPar() && i->ti()->type().isvar()) { 2967 // this is a par function declared as var, so change declared return type 2968 Type i_t = i->ti()->type(); 2969 i_t.ti(Type::TI_PAR); 2970 i->ti()->type(i_t); 2971 } 2972 if (i->e() != nullptr) { 2973 i->e(add_coercion(_env, _m, i->e(), i->ti()->type())()); 2974 } 2975 } 2976 } _tsv2(env.envi(), m, bottomUpTyper, typeErrors); 2977 iter_items(_tsv2, m); 2978 } 2979 2980 class TSV3 : public ItemVisitor { 2981 public: 2982 EnvI& env; 2983 Model* m; 2984 OutputI* outputItem; 2985 TSV3(EnvI& env0, Model* m0) : env(env0), m(m0), outputItem(nullptr) {} 2986 void vAssignI(AssignI* i) { i->decl()->e(add_coercion(env, m, i->e(), i->decl()->type())()); } 2987 void vOutputI(OutputI* oi) { 2988 if (outputItem == nullptr) { 2989 outputItem = oi; 2990 } else { 2991 GCLock lock; 2992 auto* bo = new BinOp(Location().introduce(), outputItem->e(), BOT_PLUSPLUS, oi->e()); 2993 bo->type(Type::parstring(1)); 2994 outputItem->e(bo); 2995 oi->remove(); 2996 m->setOutputItem(outputItem); 2997 } 2998 } 2999 } _tsv3(env.envi(), m); 3000 if (typeErrors.empty()) { 3001 iter_items(_tsv3, m); 3002 } 3003 3004 // Create a par version of each function that returns par and 3005 // that has a body that can be made par 3006 std::unordered_map<FunctionI*, std::pair<bool, std::vector<FunctionI*>>> fnsToMakePar; 3007 for (auto& f : m->functions()) { 3008 if (f.id() == "mzn_reverse_map_var") { 3009 continue; 3010 } 3011 if (f.e() != nullptr && f.ti()->type().bt() != Type::BT_ANN) { 3012 bool foundVar = false; 3013 for (auto* p : f.params()) { 3014 if (p->type().isvar()) { 3015 foundVar = true; 3016 break; 3017 } 3018 } 3019 if (foundVar) { 3020 // create par version of parameter types 3021 std::vector<Type> tv; 3022 for (auto* p : f.params()) { 3023 Type t = p->type(); 3024 t.cv(false); 3025 t.ti(Type::TI_PAR); 3026 tv.push_back(t); 3027 } 3028 // check if specialised par version of function already exists 3029 FunctionI* fi_par = m->matchFn(env.envi(), f.id(), tv, false); 3030 bool parIsUsable = false; 3031 if (fi_par != nullptr) { 3032 bool foundVar = false; 3033 for (auto* p : fi_par->params()) { 3034 if (p->type().isvar()) { 3035 foundVar = true; 3036 break; 3037 } 3038 } 3039 parIsUsable = !foundVar; 3040 } 3041 if (!parIsUsable) { 3042 // check if body of f doesn't contain any free variables in lets, 3043 // all calls in the body have par versions available, 3044 // and all toplevel identifiers used in the body of f are par 3045 class CheckParBody : public EVisitor { 3046 public: 3047 EnvI& env; 3048 Model* m; 3049 CheckParBody(EnvI& env0, Model* m0) : env(env0), m(m0) {} 3050 bool isPar = true; 3051 std::vector<FunctionI*> deps; 3052 bool enter(Expression* e) const { 3053 // if we have already found a var, don't continue 3054 return isPar; 3055 } 3056 void vId(const Id& ident) { 3057 if (ident.decl() != nullptr && ident.type().isvar() && ident.decl()->toplevel()) { 3058 isPar = false; 3059 } 3060 } 3061 void vLet(const Let& let) { 3062 // check if any of the declared variables does not have a RHS 3063 for (auto* e : let.let()) { 3064 if (auto* vd = e->dynamicCast<VarDecl>()) { 3065 if (vd->e() == nullptr) { 3066 isPar = false; 3067 break; 3068 } 3069 } 3070 } 3071 } 3072 void vCall(const Call& c) { 3073 if (!c.type().isAnn()) { 3074 FunctionI* decl = c.decl(); 3075 // create par version of parameter types 3076 std::vector<Type> tv; 3077 for (auto* p : decl->params()) { 3078 Type t = p->type(); 3079 t.cv(false); 3080 t.ti(Type::TI_PAR); 3081 tv.push_back(t); 3082 } 3083 // check if specialised par version of function already exists 3084 FunctionI* decl_par = m->matchFn(env, decl->id(), tv, false); 3085 bool parIsUsable = decl_par->ti()->type().isPar(); 3086 if (parIsUsable && decl_par->e() == nullptr && decl_par->fromStdLib()) { 3087 parIsUsable = true; 3088 } else if (parIsUsable) { 3089 bool foundVar = false; 3090 for (auto* p : decl_par->params()) { 3091 if (p->type().isvar()) { 3092 foundVar = true; 3093 break; 3094 } 3095 } 3096 parIsUsable = !foundVar; 3097 } 3098 if (!parIsUsable) { 3099 deps.push_back(decl_par); 3100 } 3101 } 3102 } 3103 } cpb(env.envi(), m); 3104 top_down(cpb, f.e()); 3105 if (cpb.isPar) { 3106 fnsToMakePar.insert({&f, {false, cpb.deps}}); 3107 } 3108 } else { 3109 fnsToMakePar.insert({fi_par, {true, std::vector<FunctionI*>()}}); 3110 } 3111 } 3112 } 3113 } 3114 3115 // Repeatedly remove functions whose dependencies cannot be made par 3116 bool didRemove; 3117 do { 3118 didRemove = false; 3119 std::vector<FunctionI*> toRemove; 3120 for (auto& p : fnsToMakePar) { 3121 for (auto* dep : p.second.second) { 3122 if (fnsToMakePar.find(dep) == fnsToMakePar.end()) { 3123 toRemove.push_back(p.first); 3124 } 3125 } 3126 } 3127 if (!toRemove.empty()) { 3128 didRemove = true; 3129 for (auto* p : toRemove) { 3130 fnsToMakePar.erase(p); 3131 } 3132 } 3133 } while (didRemove); 3134 3135 // Create par versions of remaining functions 3136 { 3137 // First step: copy and register functions 3138 std::vector<FunctionI*> parFunctions; 3139 CopyMap parCopyMap; 3140 for (auto& p : fnsToMakePar) { 3141 if (!p.second.first) { 3142 GCLock lock; 3143 auto* cp = copy(env.envi(), parCopyMap, p.first)->cast<FunctionI>(); 3144 for (auto* v : cp->params()) { 3145 Type vt = v->ti()->type(); 3146 vt.ti(Type::TI_PAR); 3147 v->ti()->type(vt); 3148 v->type(vt); 3149 } 3150 Type cpt(cp->ti()->type()); 3151 cpt.ti(Type::TI_PAR); 3152 cp->ti()->type(cpt); 3153 bool didRegister = m->registerFn(env.envi(), cp, true, false); 3154 if (didRegister) { 3155 m->addItem(cp); 3156 parFunctions.push_back(cp); 3157 } 3158 } 3159 } 3160 3161 // Second step: make function bodies par 3162 // (needs to happen in a separate second step so that 3163 // matchFn will find the correct par function from first step) 3164 class MakeFnPar : public EVisitor { 3165 public: 3166 EnvI& env; 3167 Model* m; 3168 MakeFnPar(EnvI& env0, Model* m0) : env(env0), m(m0) {} 3169 static bool enter(Expression* e) { 3170 Type t(e->type()); 3171 t.ti(Type::TI_PAR); 3172 t.cv(false); 3173 e->type(t); 3174 return true; 3175 } 3176 void vCall(Call& c) { 3177 FunctionI* decl = m->matchFn(env, &c, false); 3178 c.decl(decl); 3179 } 3180 void vBinOp(BinOp& bo) { 3181 if (bo.decl() != nullptr) { 3182 std::vector<Type> ta(2); 3183 ta[0] = bo.lhs()->type(); 3184 ta[1] = bo.rhs()->type(); 3185 FunctionI* decl = m->matchFn(env, bo.opToString(), ta, false); 3186 bo.decl(decl); 3187 } 3188 } 3189 void vUnOp(UnOp& uo) { 3190 if (uo.decl() != nullptr) { 3191 std::vector<Type> ta(1); 3192 ta[0] = uo.e()->type(); 3193 FunctionI* decl = m->matchFn(env, uo.opToString(), ta, false); 3194 uo.decl(decl); 3195 } 3196 } 3197 } _mfp(env.envi(), m); 3198 3199 for (auto* p : parFunctions) { 3200 bottom_up(_mfp, p->e()); 3201 } 3202 } 3203 3204 try { 3205 m->checkFnOverloading(env.envi()); 3206 } catch (TypeError& e) { 3207 typeErrors.push_back(e); 3208 } 3209 3210 for (auto& decl : ts.decls) { 3211 if (decl->toplevel() && decl->type().isPar() && !decl->type().isAnn() && decl->e() == nullptr) { 3212 if (decl->type().isOpt() && decl->type().dim() == 0) { 3213 decl->e(constants().absent); 3214 decl->addAnnotation(constants().ann.mzn_was_undefined); 3215 } else if (!ignoreUndefinedParameters) { 3216 std::ostringstream ss; 3217 ss << " symbol error: variable `" << decl->id()->str() 3218 << "' must be defined (did you forget to specify a data file?)"; 3219 typeErrors.emplace_back(env.envi(), decl->loc(), ss.str()); 3220 } 3221 } 3222 if (decl->ti()->isEnum()) { 3223 decl->ti()->setIsEnum(false); 3224 Type vdt = decl->ti()->type(); 3225 vdt.enumId(0); 3226 decl->ti()->type(vdt); 3227 } 3228 } 3229 3230 for (auto vd_k : env.envi().checkVars) { 3231 try { 3232 VarDecl* vd; 3233 try { 3234 vd = ts.get(env.envi(), vd_k()->cast<VarDecl>()->id()->str(), 3235 vd_k()->cast<VarDecl>()->loc()); 3236 } catch (TypeError&) { 3237 if (vd_k()->cast<VarDecl>()->type().isvar()) { 3238 continue; // var can be undefined 3239 } 3240 throw; 3241 } 3242 vd->ann().add(constants().ann.mzn_check_var); 3243 if (vd->type().enumId() != 0) { 3244 GCLock lock; 3245 std::vector<unsigned int> enumIds({vd->type().enumId()}); 3246 if (vd->type().dim() > 0) { 3247 enumIds = env.envi().getArrayEnum(vd->type().enumId()); 3248 } 3249 std::vector<Expression*> enumIds_a(enumIds.size()); 3250 for (unsigned int i = 0; i < enumIds.size(); i++) { 3251 if (enumIds[i] != 0) { 3252 enumIds_a[i] = env.envi().getEnum(enumIds[i])->e()->id(); 3253 } else { 3254 enumIds_a[i] = new SetLit(Location().introduce(), std::vector<Expression*>()); 3255 } 3256 } 3257 auto* enumIds_al = new ArrayLit(Location().introduce(), enumIds_a); 3258 enumIds_al->type(Type::parsetint(1)); 3259 std::vector<Expression*> args({enumIds_al}); 3260 Call* checkEnum = 3261 new Call(Location().introduce(), constants().ann.mzn_check_enum_var, args); 3262 checkEnum->type(Type::ann()); 3263 checkEnum->decl(env.envi().model->matchFn(env.envi(), checkEnum, false)); 3264 vd->ann().add(checkEnum); 3265 } 3266 Type vdktype = vd_k()->type(); 3267 vdktype.ti(Type::TI_VAR); 3268 if (!vd_k()->type().isSubtypeOf(vd->type(), false)) { 3269 std::ostringstream ss; 3270 ss << "Solution checker requires `" << vd->id()->str() << "' to be of type `" 3271 << vdktype.toString(env.envi()) << "'"; 3272 typeErrors.emplace_back(env.envi(), vd->loc(), ss.str()); 3273 } 3274 } catch (TypeError& e) { 3275 typeErrors.emplace_back(env.envi(), e.loc(), 3276 e.msg() + " (required by solution checker model)"); 3277 } 3278 } 3279} 3280 3281void typecheck(Env& env, Model* m, AssignI* ai) { 3282 std::vector<TypeError> typeErrors; 3283 Typer<true> ty(env.envi(), m, typeErrors, false); 3284 BottomUpIterator<Typer<true>> bottomUpTyper(ty); 3285 bottomUpTyper.run(ai->e()); 3286 if (!typeErrors.empty()) { 3287 throw typeErrors[0]; 3288 } 3289 if (!env.envi().isSubtype(ai->e()->type(), ai->decl()->ti()->type(), true)) { 3290 std::ostringstream ss; 3291 ss << "assignment value for `" << ai->decl()->id()->str() 3292 << "' has invalid type-inst: expected `" << ai->decl()->ti()->type().toString(env.envi()) 3293 << "', actual `" << ai->e()->type().toString(env.envi()) << "'"; 3294 throw TypeError(env.envi(), ai->e()->loc(), ss.str()); 3295 } 3296} 3297 3298void output_var_desc_json(Env& env, VarDecl* vd, std::ostream& os, bool extra = false) { 3299 os << " \"" << *vd->id() << "\" : {"; 3300 os << "\"type\" : "; 3301 switch (vd->type().bt()) { 3302 case Type::BT_INT: 3303 os << "\"int\""; 3304 break; 3305 case Type::BT_BOOL: 3306 os << "\"bool\""; 3307 break; 3308 case Type::BT_FLOAT: 3309 os << "\"float\""; 3310 break; 3311 case Type::BT_STRING: 3312 os << "\"string\""; 3313 break; 3314 case Type::BT_ANN: 3315 os << "\"ann\""; 3316 break; 3317 default: 3318 os << "\"?\""; 3319 break; 3320 } 3321 if (vd->type().ot() == Type::OT_OPTIONAL) { 3322 os << ", \"optional\" : true"; 3323 } 3324 if (vd->type().st() == Type::ST_SET) { 3325 os << ", \"set\" : true"; 3326 } 3327 if (vd->type().dim() > 0) { 3328 os << ", \"dim\" : " << vd->type().dim(); 3329 3330 if (extra) { 3331 os << ", \"dims\" : ["; 3332 bool had_dim = false; 3333 ASTExprVec<TypeInst> ranges = vd->ti()->ranges(); 3334 for (auto& range : ranges) { 3335 if (range->type().enumId() > 0) { 3336 os << (had_dim ? "," : "") << "\"" 3337 << *env.envi().getEnum(range->type().enumId())->e()->id() << "\""; 3338 } else { 3339 os << (had_dim ? "," : "") << "\"int\""; 3340 } 3341 had_dim = true; 3342 } 3343 os << "]"; 3344 3345 if (vd->type().enumId() > 0) { 3346 const std::vector<unsigned int>& enumIds = env.envi().getArrayEnum(vd->type().enumId()); 3347 if (enumIds.back() > 0) { 3348 os << ", \"enum_type\" : \"" << *env.envi().getEnum(enumIds.back())->e()->id() << "\""; 3349 } 3350 } 3351 } 3352 3353 } else { 3354 if (extra) { 3355 if (vd->type().enumId() > 0) { 3356 os << ", \"enum_type\" : \"" << *env.envi().getEnum(vd->type().enumId())->e()->id() << "\""; 3357 } 3358 } 3359 } 3360 os << "}"; 3361} 3362 3363void output_model_variable_types(Env& env, Model* m, std::ostream& os, 3364 const std::vector<std::string>& skipDirs) { 3365 class VInfVisitor : public ItemVisitor { 3366 public: 3367 Env& env; 3368 const std::vector<std::string>& skipDirs; 3369 bool hadVar; 3370 bool hadEnum; 3371 std::ostringstream ossVars; 3372 std::ostringstream ossEnums; 3373 VInfVisitor(Env& env0, const std::vector<std::string>& skipDirs0) 3374 : env(env0), skipDirs(skipDirs0), hadVar(false), hadEnum(false) {} 3375 bool enter(Item* i) { 3376 if (auto* ii = i->dynamicCast<IncludeI>()) { 3377 std::string prefix = 3378 ii->m()->filepath().substr(0, ii->m()->filepath().size() - ii->f().size()); 3379 for (const auto& skip_dir : skipDirs) { 3380 if (prefix.substr(0, skip_dir.size()) == skip_dir) { 3381 return false; 3382 } 3383 } 3384 } 3385 return true; 3386 } 3387 void vVarDeclI(VarDeclI* vdi) { 3388 if (!vdi->e()->type().isAnn() && !vdi->e()->ti()->isEnum()) { 3389 if (hadVar) { 3390 ossVars << ",\n"; 3391 } 3392 output_var_desc_json(env, vdi->e(), ossVars, true); 3393 hadVar = true; 3394 } else if (vdi->e()->type().st() == Type::ST_SET && vdi->e()->type().enumId() != 0 && 3395 !vdi->e()->type().isAnn()) { 3396 if (hadEnum) { 3397 ossEnums << ", "; 3398 } 3399 ossEnums << "\"" << *env.envi().getEnum(vdi->e()->type().enumId())->e()->id() << "\""; 3400 hadEnum = true; 3401 } 3402 } 3403 } _vinf(env, skipDirs); 3404 iter_items(_vinf, m); 3405 os << "{\"var_types\": {"; 3406 os << "\n \"vars\": {\n" << _vinf.ossVars.str() << "\n },"; 3407 os << "\n \"enums\": [" << _vinf.ossEnums.str() << "]\n"; 3408 os << "}}\n"; 3409} 3410 3411void output_model_interface(Env& env, Model* m, std::ostream& os, 3412 const std::vector<std::string>& skipDirs) { 3413 class IfcVisitor : public ItemVisitor { 3414 public: 3415 Env& env; 3416 const std::vector<std::string>& skipDirs; 3417 bool hadInput; 3418 bool hadOutput; 3419 bool hadIncludedFiles; 3420 bool hadAddToOutput = false; 3421 std::ostringstream ossInput; 3422 std::ostringstream ossOutput; 3423 std::ostringstream ossIncludedFiles; 3424 std::string method; 3425 bool outputItem; 3426 IfcVisitor(Env& env0, const std::vector<std::string>& skipDirs0) 3427 : env(env0), 3428 skipDirs(skipDirs0), 3429 hadInput(false), 3430 hadOutput(false), 3431 hadIncludedFiles(false), 3432 method("sat"), 3433 outputItem(false) {} 3434 bool enter(Item* i) { 3435 if (auto* ii = i->dynamicCast<IncludeI>()) { 3436 std::string prefix = 3437 ii->m()->filepath().substr(0, ii->m()->filepath().size() - ii->f().size()); 3438 for (const auto& skip_dir : skipDirs) { 3439 if (prefix.substr(0, skip_dir.size()) == skip_dir) { 3440 return false; 3441 } 3442 } 3443 if (hadIncludedFiles) { 3444 ossIncludedFiles << ",\n"; 3445 } 3446 ossIncludedFiles << " \"" << Printer::escapeStringLit(ii->m()->filepath()) << "\""; 3447 hadIncludedFiles = true; 3448 } 3449 return true; 3450 } 3451 void vVarDeclI(VarDeclI* vdi) { 3452 VarDecl* vd = vdi->e(); 3453 if (vd->type().isPar() && !vd->type().isAnn() && 3454 (vd->e() == nullptr || (vd->e() == constants().absent && 3455 vd->ann().contains(constants().ann.mzn_was_undefined)))) { 3456 if (hadInput) { 3457 ossInput << ",\n"; 3458 } 3459 output_var_desc_json(env, vd, ossInput); 3460 hadInput = true; 3461 } else { 3462 bool process_var = false; 3463 if (vd->ann().contains(constants().ann.add_to_output)) { 3464 if (!hadAddToOutput) { 3465 ossOutput.str(""); 3466 hadOutput = false; 3467 } 3468 hadAddToOutput = true; 3469 process_var = true; 3470 } else if (!hadAddToOutput) { 3471 process_var = 3472 vd->type().isvar() && 3473 (vd->e() == nullptr || vd->ann().contains(constants().ann.rhs_from_assignment)); 3474 } 3475 if (process_var) { 3476 if (hadOutput) { 3477 ossOutput << ",\n"; 3478 } 3479 output_var_desc_json(env, vd, ossOutput); 3480 hadOutput = true; 3481 } 3482 } 3483 } 3484 void vSolveI(SolveI* si) { 3485 switch (si->st()) { 3486 case SolveI::ST_MIN: 3487 method = "min"; 3488 break; 3489 case SolveI::ST_MAX: 3490 method = "max"; 3491 break; 3492 case SolveI::ST_SAT: 3493 method = "sat"; 3494 break; 3495 } 3496 } 3497 void vOutputI(OutputI* oi) { outputItem = true; } 3498 } _ifc(env, skipDirs); 3499 iter_items(_ifc, m); 3500 os << "{\n \"input\" : {\n" 3501 << _ifc.ossInput.str() << "\n },\n \"output\" : {\n" 3502 << _ifc.ossOutput.str() << "\n }"; 3503 os << ",\n \"method\": \""; 3504 os << _ifc.method; 3505 os << "\""; 3506 os << ",\n \"has_outputItem\": " << (_ifc.outputItem ? "true" : "false"); 3507 os << ",\n \"included_files\": [\n" << _ifc.ossIncludedFiles.str() << "\n ]"; 3508 os << "\n}\n"; 3509} 3510 3511std::string create_enum_to_string_name(Id* ident, const std::string& prefix) { 3512 std::ostringstream ss; 3513 if (ident->str().c_str()[0] == '\'') { 3514 ss << "'" << prefix << ident->str().substr(1); 3515 } else { 3516 ss << prefix << *ident; 3517 } 3518 return ss.str(); 3519} 3520 3521} // namespace MiniZinc