this repo has no description
at develop 9.7 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/flat_exp.hh> 13 14namespace MiniZinc { 15 16EE flatten_arrayaccess(EnvI& env, const Ctx& ctx, Expression* e, VarDecl* r, VarDecl* b) { 17 CallStackItem _csi(env, e); 18 EE ret; 19 auto* aa = e->cast<ArrayAccess>(); 20 KeepAlive aa_ka = aa; 21 22 Ctx nctx = ctx; 23 nctx.b = +nctx.b; 24 nctx.neg = false; 25 EE eev = flat_exp(env, nctx, aa->v(), nullptr, nullptr); 26 std::vector<EE> ees; 27 28start_flatten_arrayaccess: 29 for (unsigned int i = 0; i < aa->idx().size(); i++) { 30 Expression* tmp = follow_id_to_decl(aa->idx()[i]); 31 if (auto* vd = tmp->dynamicCast<VarDecl>()) { 32 tmp = vd->id(); 33 } 34 if (tmp->type().isPar()) { 35 ArrayLit* al; 36 if (eev.r()->isa<ArrayLit>()) { 37 al = eev.r()->cast<ArrayLit>(); 38 } else { 39 Id* id = eev.r()->cast<Id>(); 40 if (id->decl() == nullptr) { 41 throw InternalError("undefined identifier"); 42 } 43 if (id->decl()->e() == nullptr) { 44 throw InternalError("array without initialiser not supported"); 45 } 46 Expression* id_e = follow_id(id); 47 if (id_e->isa<ArrayLit>()) { 48 al = id_e->cast<ArrayLit>(); 49 } else { 50 throw InternalError("builtin function returning array not supported"); 51 } 52 } 53 54 std::vector<KeepAlive> elems; 55 std::vector<IntVal> idx(aa->idx().size()); 56 std::vector<std::pair<int, int> > dims; 57 std::vector<Expression*> newaccess; 58 std::vector<int> nonpar; 59 std::vector<int> stack; 60 for (unsigned int j = 0; j < aa->idx().size(); j++) { 61 Expression* tmp = follow_id_to_decl(aa->idx()[j]); 62 if (auto* vd = tmp->dynamicCast<VarDecl>()) { 63 tmp = vd->id(); 64 } 65 if (tmp->type().isPar()) { 66 GCLock lock; 67 idx[j] = eval_int(env, tmp).toInt(); 68 } else { 69 idx[j] = al->min(j); 70 stack.push_back(static_cast<int>(nonpar.size())); 71 nonpar.push_back(j); 72 dims.emplace_back(al->min(j), al->max(j)); 73 newaccess.push_back(aa->idx()[j]); 74 } 75 } 76 if (stack.empty()) { 77 bool success; 78 KeepAlive ka; 79 { 80 GCLock lock; 81 ka = eval_arrayaccess(env, al, idx, success); 82 if (!success && env.inMaybePartial == 0) { 83 ResultUndefinedError warning(env, al->loc(), "array access out of bounds"); 84 } 85 } 86 ees.emplace_back(nullptr, constants().boollit(success)); 87 ees.emplace_back(nullptr, eev.b()); 88 if (aa->type().isbool() && !aa->type().isOpt()) { 89 ret.b = bind(env, Ctx(), b, constants().literalTrue); 90 ees.emplace_back(nullptr, ka()); 91 ret.r = conj(env, r, ctx, ees); 92 } else { 93 ret.b = conj(env, b, ctx, ees); 94 ret.r = bind(env, ctx, r, ka()); 95 } 96 return ret; 97 } 98 while (!stack.empty()) { 99 int cur = stack.back(); 100 if (cur == nonpar.size() - 1) { 101 stack.pop_back(); 102 for (int i = al->min(nonpar[cur]); i <= al->max(nonpar[cur]); i++) { 103 idx[nonpar[cur]] = i; 104 bool success; 105 GCLock lock; 106 Expression* al_idx = eval_arrayaccess(env, al, idx, success); 107 if (!success) { 108 if (env.inMaybePartial == 0) { 109 ResultUndefinedError warning(env, al->loc(), "array access out of bounds"); 110 } 111 ees.emplace_back(nullptr, constants().literalFalse); 112 ees.emplace_back(nullptr, eev.b()); 113 if (aa->type().isbool() && !aa->type().isOpt()) { 114 ret.b = bind(env, Ctx(), b, constants().literalTrue); 115 ret.r = conj(env, r, ctx, ees); 116 } else { 117 ret.b = conj(env, b, ctx, ees); 118 ret.r = bind(env, ctx, r, al_idx); 119 } 120 return ret; 121 } 122 elems.emplace_back(al_idx); 123 } 124 } else { 125 if (idx[nonpar[cur]].toInt() == al->max(nonpar[cur])) { 126 idx[nonpar[cur]] = al->min(nonpar[cur]); 127 stack.pop_back(); 128 } else { 129 idx[nonpar[cur]]++; 130 for (unsigned int j = cur + 1; j < nonpar.size(); j++) { 131 stack.push_back(j); 132 } 133 } 134 } 135 } 136 std::vector<Expression*> elems_e(elems.size()); 137 for (unsigned int i = 0; i < elems.size(); i++) { 138 elems_e[i] = elems[i](); 139 } 140 { 141 GCLock lock; 142 Expression* newal = new ArrayLit(al->loc(), elems_e, dims); 143 Type t = al->type(); 144 t.dim(static_cast<int>(dims.size())); 145 newal->type(t); 146 eev.r = newal; 147 auto* n_aa = new ArrayAccess(aa->loc(), newal, newaccess); 148 n_aa->type(aa->type()); 149 aa = n_aa; 150 aa_ka = aa; 151 } 152 } 153 } 154 155 if (aa->idx().size() == 1 && aa->idx()[0]->isa<ArrayAccess>()) { 156 auto* aa_inner = aa->idx()[0]->cast<ArrayAccess>(); 157 ArrayLit* al; 158 if (eev.r()->isa<ArrayLit>()) { 159 al = eev.r()->cast<ArrayLit>(); 160 } else { 161 Id* id = eev.r()->cast<Id>(); 162 if (id->decl() == nullptr) { 163 throw InternalError("undefined identifier"); 164 } 165 if (id->decl()->e() == nullptr) { 166 throw InternalError("array without initialiser not supported"); 167 } 168 al = follow_id(id)->cast<ArrayLit>(); 169 } 170 if (aa_inner->v()->type().isPar()) { 171 KeepAlive ka_al_inner = flat_cv_exp(env, ctx, aa_inner->v()); 172 auto* al_inner = ka_al_inner()->cast<ArrayLit>(); 173 std::vector<Expression*> composed_e(al_inner->size()); 174 for (unsigned int i = 0; i < al_inner->size(); i++) { 175 GCLock lock; 176 IntVal inner_idx = eval_int(env, (*al_inner)[i]); 177 if (inner_idx < al->min(0) || inner_idx > al->max(0)) { 178 goto flatten_arrayaccess; 179 } 180 composed_e[i] = (*al)[static_cast<int>(inner_idx.toInt()) - al->min(0)]; 181 } 182 std::vector<std::pair<int, int> > dims(al_inner->dims()); 183 for (int i = 0; i < al_inner->dims(); i++) { 184 dims[i] = std::make_pair(al_inner->min(i), al_inner->max(i)); 185 } 186 { 187 GCLock lock; 188 Expression* newal = new ArrayLit(al->loc(), composed_e, dims); 189 Type t = al->type(); 190 t.dim(static_cast<int>(dims.size())); 191 newal->type(t); 192 eev.r = newal; 193 auto* n_aa = new ArrayAccess(aa->loc(), newal, aa_inner->idx()); 194 n_aa->type(aa->type()); 195 aa = n_aa; 196 aa_ka = aa; 197 goto start_flatten_arrayaccess; 198 } 199 } 200 } 201flatten_arrayaccess: 202 Ctx dimctx = ctx; 203 dimctx.neg = false; 204 for (unsigned int i = 0; i < aa->idx().size(); i++) { 205 Expression* tmp = follow_id_to_decl(aa->idx()[i]); 206 if (auto* vd = tmp->dynamicCast<VarDecl>()) { 207 tmp = vd->id(); 208 } 209 ees.push_back(flat_exp(env, dimctx, tmp, nullptr, nullptr)); 210 } 211 ees.emplace_back(nullptr, eev.b()); 212 213 bool parAccess = true; 214 for (unsigned int i = 0; i < aa->idx().size(); i++) { 215 if (!ees[i].r()->type().isPar()) { 216 parAccess = false; 217 break; 218 } 219 } 220 221 if (parAccess) { 222 ArrayLit* al; 223 if (eev.r()->isa<ArrayLit>()) { 224 al = eev.r()->cast<ArrayLit>(); 225 } else { 226 Id* id = eev.r()->cast<Id>(); 227 if (id->decl() == nullptr) { 228 throw InternalError("undefined identifier"); 229 } 230 if (id->decl()->e() == nullptr) { 231 throw InternalError("array without initialiser not supported"); 232 } 233 al = follow_id(id)->cast<ArrayLit>(); 234 } 235 KeepAlive ka; 236 bool success; 237 { 238 GCLock lock; 239 std::vector<IntVal> dims(aa->idx().size()); 240 for (unsigned int i = aa->idx().size(); (i--) != 0U;) { 241 dims[i] = eval_int(env, ees[i].r()); 242 } 243 ka = eval_arrayaccess(env, al, dims, success); 244 } 245 if (!success && env.inMaybePartial == 0) { 246 ResultUndefinedError warning(env, al->loc(), "array access out of bounds"); 247 } 248 ees.emplace_back(nullptr, constants().boollit(success)); 249 if (aa->type().isbool() && !aa->type().isOpt()) { 250 ret.b = bind(env, Ctx(), b, constants().literalTrue); 251 ees.emplace_back(nullptr, ka()); 252 ret.r = conj(env, r, ctx, ees); 253 } else { 254 ret.b = conj(env, b, ctx, ees); 255 ret.r = bind(env, ctx, r, ka()); 256 } 257 } else { 258 std::vector<Expression*> args(aa->idx().size() + 1); 259 for (unsigned int i = aa->idx().size(); (i--) != 0U;) { 260 args[i] = ees[i].r(); 261 } 262 args[aa->idx().size()] = eev.r(); 263 KeepAlive ka; 264 { 265 GCLock lock; 266 Call* cc = new Call(e->loc().introduce(), constants().ids.element, args); 267 cc->type(aa->type()); 268 FunctionI* fi = env.model->matchFn(env, cc->id(), args, false); 269 if (fi == nullptr) { 270 throw FlatteningError(env, cc->loc(), "cannot find matching declaration"); 271 } 272 assert(fi); 273 assert(env.isSubtype(fi->rtype(env, args, false), cc->type(), false)); 274 cc->decl(fi); 275 ka = cc; 276 } 277 Ctx elemctx = ctx; 278 elemctx.neg = false; 279 EE ee = flat_exp(env, elemctx, ka(), nullptr, nullptr); 280 ees.push_back(ee); 281 if (aa->type().isbool() && !aa->type().isOpt()) { 282 ee.b = ee.r; 283 ees.push_back(ee); 284 ret.r = conj(env, r, ctx, ees); 285 ret.b = bind(env, ctx, b, constants().boollit(!ctx.neg)); 286 } else { 287 ret.r = bind(env, ctx, r, ee.r()); 288 ret.b = conj(env, b, ctx, ees); 289 } 290 } 291 return ret; 292} 293 294} // namespace MiniZinc