this repo has no description
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