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