1*627f7eb2Smrg
2*627f7eb2Smrg /* Compiler implementation of the D programming language
3*627f7eb2Smrg * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4*627f7eb2Smrg * written by Walter Bright
5*627f7eb2Smrg * http://www.digitalmars.com
6*627f7eb2Smrg * Distributed under the Boost Software License, Version 1.0.
7*627f7eb2Smrg * http://www.boost.org/LICENSE_1_0.txt
8*627f7eb2Smrg * https://github.com/D-Programming-Language/dmd/blob/master/src/arrayop.c
9*627f7eb2Smrg */
10*627f7eb2Smrg
11*627f7eb2Smrg #include "root/dsystem.h"
12*627f7eb2Smrg #include "root/rmem.h"
13*627f7eb2Smrg #include "root/aav.h"
14*627f7eb2Smrg
15*627f7eb2Smrg #include "mars.h"
16*627f7eb2Smrg #include "expression.h"
17*627f7eb2Smrg #include "statement.h"
18*627f7eb2Smrg #include "mtype.h"
19*627f7eb2Smrg #include "declaration.h"
20*627f7eb2Smrg #include "scope.h"
21*627f7eb2Smrg #include "id.h"
22*627f7eb2Smrg #include "module.h"
23*627f7eb2Smrg #include "init.h"
24*627f7eb2Smrg #include "tokens.h"
25*627f7eb2Smrg
26*627f7eb2Smrg void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments);
27*627f7eb2Smrg Expression *buildArrayLoop(Expression *e, Parameters *fparams);
28*627f7eb2Smrg Expression *semantic(Expression *e, Scope *sc);
29*627f7eb2Smrg
30*627f7eb2Smrg /**************************************
31*627f7eb2Smrg * Hash table of array op functions already generated or known about.
32*627f7eb2Smrg */
33*627f7eb2Smrg
34*627f7eb2Smrg AA *arrayfuncs;
35*627f7eb2Smrg
36*627f7eb2Smrg /**************************************
37*627f7eb2Smrg * Structure to contain information needed to insert an array op call
38*627f7eb2Smrg */
39*627f7eb2Smrg
buildArrayOp(Identifier * ident,BinExp * exp,Scope * sc)40*627f7eb2Smrg FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc)
41*627f7eb2Smrg {
42*627f7eb2Smrg Parameters *fparams = new Parameters();
43*627f7eb2Smrg Expression *loopbody = buildArrayLoop(exp, fparams);
44*627f7eb2Smrg
45*627f7eb2Smrg /* Construct the function body:
46*627f7eb2Smrg * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++)
47*627f7eb2Smrg * loopbody;
48*627f7eb2Smrg * return p;
49*627f7eb2Smrg */
50*627f7eb2Smrg
51*627f7eb2Smrg Parameter *p = (*fparams)[0];
52*627f7eb2Smrg // foreach (i; 0 .. p.length)
53*627f7eb2Smrg Statement *s1 = new ForeachRangeStatement(Loc(), TOKforeach,
54*627f7eb2Smrg new Parameter(0, NULL, Id::p, NULL),
55*627f7eb2Smrg new IntegerExp(Loc(), 0, Type::tsize_t),
56*627f7eb2Smrg new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p->ident)),
57*627f7eb2Smrg new ExpStatement(Loc(), loopbody),
58*627f7eb2Smrg Loc());
59*627f7eb2Smrg //printf("%s\n", s1->toChars());
60*627f7eb2Smrg Statement *s2 = new ReturnStatement(Loc(), new IdentifierExp(Loc(), p->ident));
61*627f7eb2Smrg //printf("s2: %s\n", s2->toChars());
62*627f7eb2Smrg Statement *fbody = new CompoundStatement(Loc(), s1, s2);
63*627f7eb2Smrg
64*627f7eb2Smrg // Built-in array ops should be @trusted, pure, nothrow and nogc
65*627f7eb2Smrg StorageClass stc = STCtrusted | STCpure | STCnothrow | STCnogc;
66*627f7eb2Smrg
67*627f7eb2Smrg /* Construct the function
68*627f7eb2Smrg */
69*627f7eb2Smrg TypeFunction *ftype = new TypeFunction(fparams, exp->e1->type, 0, LINKc, stc);
70*627f7eb2Smrg //printf("fd: %s %s\n", ident->toChars(), ftype->toChars());
71*627f7eb2Smrg FuncDeclaration *fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype);
72*627f7eb2Smrg fd->fbody = fbody;
73*627f7eb2Smrg fd->protection = Prot(PROTpublic);
74*627f7eb2Smrg fd->linkage = LINKc;
75*627f7eb2Smrg fd->isArrayOp = 1;
76*627f7eb2Smrg
77*627f7eb2Smrg sc->_module->importedFrom->members->push(fd);
78*627f7eb2Smrg
79*627f7eb2Smrg sc = sc->push();
80*627f7eb2Smrg sc->parent = sc->_module->importedFrom;
81*627f7eb2Smrg sc->stc = 0;
82*627f7eb2Smrg sc->linkage = LINKc;
83*627f7eb2Smrg fd->semantic(sc);
84*627f7eb2Smrg fd->semantic2(sc);
85*627f7eb2Smrg unsigned errors = global.startGagging();
86*627f7eb2Smrg fd->semantic3(sc);
87*627f7eb2Smrg if (global.endGagging(errors))
88*627f7eb2Smrg {
89*627f7eb2Smrg fd->type = Type::terror;
90*627f7eb2Smrg fd->errors = true;
91*627f7eb2Smrg fd->fbody = NULL;
92*627f7eb2Smrg }
93*627f7eb2Smrg sc->pop();
94*627f7eb2Smrg
95*627f7eb2Smrg return fd;
96*627f7eb2Smrg }
97*627f7eb2Smrg
98*627f7eb2Smrg /**********************************************
99*627f7eb2Smrg * Check that there are no uses of arrays without [].
100*627f7eb2Smrg */
isArrayOpValid(Expression * e)101*627f7eb2Smrg bool isArrayOpValid(Expression *e)
102*627f7eb2Smrg {
103*627f7eb2Smrg if (e->op == TOKslice)
104*627f7eb2Smrg return true;
105*627f7eb2Smrg if (e->op == TOKarrayliteral)
106*627f7eb2Smrg {
107*627f7eb2Smrg Type *t = e->type->toBasetype();
108*627f7eb2Smrg while (t->ty == Tarray || t->ty == Tsarray)
109*627f7eb2Smrg t = t->nextOf()->toBasetype();
110*627f7eb2Smrg return (t->ty != Tvoid);
111*627f7eb2Smrg }
112*627f7eb2Smrg Type *tb = e->type->toBasetype();
113*627f7eb2Smrg if (tb->ty == Tarray || tb->ty == Tsarray)
114*627f7eb2Smrg {
115*627f7eb2Smrg if (isUnaArrayOp(e->op))
116*627f7eb2Smrg {
117*627f7eb2Smrg return isArrayOpValid(((UnaExp *)e)->e1);
118*627f7eb2Smrg }
119*627f7eb2Smrg if (isBinArrayOp(e->op) ||
120*627f7eb2Smrg isBinAssignArrayOp(e->op) ||
121*627f7eb2Smrg e->op == TOKassign)
122*627f7eb2Smrg {
123*627f7eb2Smrg BinExp *be = (BinExp *)e;
124*627f7eb2Smrg return isArrayOpValid(be->e1) && isArrayOpValid(be->e2);
125*627f7eb2Smrg }
126*627f7eb2Smrg if (e->op == TOKconstruct)
127*627f7eb2Smrg {
128*627f7eb2Smrg BinExp *be = (BinExp *)e;
129*627f7eb2Smrg return be->e1->op == TOKslice && isArrayOpValid(be->e2);
130*627f7eb2Smrg }
131*627f7eb2Smrg if (e->op == TOKcall)
132*627f7eb2Smrg {
133*627f7eb2Smrg return false; // TODO: Decide if [] is required after arrayop calls.
134*627f7eb2Smrg }
135*627f7eb2Smrg else
136*627f7eb2Smrg {
137*627f7eb2Smrg return false;
138*627f7eb2Smrg }
139*627f7eb2Smrg }
140*627f7eb2Smrg return true;
141*627f7eb2Smrg }
142*627f7eb2Smrg
isNonAssignmentArrayOp(Expression * e)143*627f7eb2Smrg bool isNonAssignmentArrayOp(Expression *e)
144*627f7eb2Smrg {
145*627f7eb2Smrg if (e->op == TOKslice)
146*627f7eb2Smrg return isNonAssignmentArrayOp(((SliceExp *)e)->e1);
147*627f7eb2Smrg
148*627f7eb2Smrg Type *tb = e->type->toBasetype();
149*627f7eb2Smrg if (tb->ty == Tarray || tb->ty == Tsarray)
150*627f7eb2Smrg {
151*627f7eb2Smrg return (isUnaArrayOp(e->op) || isBinArrayOp(e->op));
152*627f7eb2Smrg }
153*627f7eb2Smrg return false;
154*627f7eb2Smrg }
155*627f7eb2Smrg
checkNonAssignmentArrayOp(Expression * e,bool suggestion)156*627f7eb2Smrg bool checkNonAssignmentArrayOp(Expression *e, bool suggestion)
157*627f7eb2Smrg {
158*627f7eb2Smrg if (isNonAssignmentArrayOp(e))
159*627f7eb2Smrg {
160*627f7eb2Smrg const char *s = "";
161*627f7eb2Smrg if (suggestion)
162*627f7eb2Smrg s = " (possible missing [])";
163*627f7eb2Smrg e->error("array operation %s without destination memory not allowed%s", e->toChars(), s);
164*627f7eb2Smrg return true;
165*627f7eb2Smrg }
166*627f7eb2Smrg return false;
167*627f7eb2Smrg }
168*627f7eb2Smrg
169*627f7eb2Smrg /***********************************
170*627f7eb2Smrg * Construct the array operation expression.
171*627f7eb2Smrg */
172*627f7eb2Smrg
arrayOp(BinExp * e,Scope * sc)173*627f7eb2Smrg Expression *arrayOp(BinExp *e, Scope *sc)
174*627f7eb2Smrg {
175*627f7eb2Smrg //printf("BinExp::arrayOp() %s\n", toChars());
176*627f7eb2Smrg
177*627f7eb2Smrg Type *tb = e->type->toBasetype();
178*627f7eb2Smrg assert(tb->ty == Tarray || tb->ty == Tsarray);
179*627f7eb2Smrg Type *tbn = tb->nextOf()->toBasetype();
180*627f7eb2Smrg if (tbn->ty == Tvoid)
181*627f7eb2Smrg {
182*627f7eb2Smrg e->error("cannot perform array operations on void[] arrays");
183*627f7eb2Smrg return new ErrorExp();
184*627f7eb2Smrg }
185*627f7eb2Smrg if (!isArrayOpValid(e))
186*627f7eb2Smrg {
187*627f7eb2Smrg e->error("invalid array operation %s (possible missing [])", e->toChars());
188*627f7eb2Smrg return new ErrorExp();
189*627f7eb2Smrg }
190*627f7eb2Smrg
191*627f7eb2Smrg Expressions *arguments = new Expressions();
192*627f7eb2Smrg
193*627f7eb2Smrg /* The expression to generate an array operation for is mangled
194*627f7eb2Smrg * into a name to use as the array operation function name.
195*627f7eb2Smrg * Mangle in the operands and operators in RPN order, and type.
196*627f7eb2Smrg */
197*627f7eb2Smrg OutBuffer buf;
198*627f7eb2Smrg buf.writestring("_array");
199*627f7eb2Smrg buildArrayIdent(e, &buf, arguments);
200*627f7eb2Smrg buf.writeByte('_');
201*627f7eb2Smrg
202*627f7eb2Smrg /* Append deco of array element type
203*627f7eb2Smrg */
204*627f7eb2Smrg buf.writestring(e->type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
205*627f7eb2Smrg
206*627f7eb2Smrg char *name = buf.peekString();
207*627f7eb2Smrg Identifier *ident = Identifier::idPool(name);
208*627f7eb2Smrg
209*627f7eb2Smrg FuncDeclaration **pFd = (FuncDeclaration **)dmd_aaGet(&arrayfuncs, (void *)ident);
210*627f7eb2Smrg FuncDeclaration *fd = *pFd;
211*627f7eb2Smrg
212*627f7eb2Smrg if (!fd)
213*627f7eb2Smrg fd = buildArrayOp(ident, e, sc);
214*627f7eb2Smrg
215*627f7eb2Smrg if (fd && fd->errors)
216*627f7eb2Smrg {
217*627f7eb2Smrg const char *fmt;
218*627f7eb2Smrg if (tbn->ty == Tstruct || tbn->ty == Tclass)
219*627f7eb2Smrg fmt = "invalid array operation '%s' because %s doesn't support necessary arithmetic operations";
220*627f7eb2Smrg else if (!tbn->isscalar())
221*627f7eb2Smrg fmt = "invalid array operation '%s' because %s is not a scalar type";
222*627f7eb2Smrg else
223*627f7eb2Smrg fmt = "invalid array operation '%s' for element type %s";
224*627f7eb2Smrg
225*627f7eb2Smrg e->error(fmt, e->toChars(), tbn->toChars());
226*627f7eb2Smrg return new ErrorExp();
227*627f7eb2Smrg }
228*627f7eb2Smrg
229*627f7eb2Smrg *pFd = fd;
230*627f7eb2Smrg
231*627f7eb2Smrg Expression *ev = new VarExp(e->loc, fd);
232*627f7eb2Smrg Expression *ec = new CallExp(e->loc, ev, arguments);
233*627f7eb2Smrg
234*627f7eb2Smrg return semantic(ec, sc);
235*627f7eb2Smrg }
236*627f7eb2Smrg
arrayOp(BinAssignExp * e,Scope * sc)237*627f7eb2Smrg Expression *arrayOp(BinAssignExp *e, Scope *sc)
238*627f7eb2Smrg {
239*627f7eb2Smrg //printf("BinAssignExp::arrayOp() %s\n", toChars());
240*627f7eb2Smrg
241*627f7eb2Smrg /* Check that the elements of e1 can be assigned to
242*627f7eb2Smrg */
243*627f7eb2Smrg Type *tn = e->e1->type->toBasetype()->nextOf();
244*627f7eb2Smrg
245*627f7eb2Smrg if (tn && (!tn->isMutable() || !tn->isAssignable()))
246*627f7eb2Smrg {
247*627f7eb2Smrg e->error("slice %s is not mutable", e->e1->toChars());
248*627f7eb2Smrg return new ErrorExp();
249*627f7eb2Smrg }
250*627f7eb2Smrg if (e->e1->op == TOKarrayliteral)
251*627f7eb2Smrg {
252*627f7eb2Smrg return e->e1->modifiableLvalue(sc, e->e1);
253*627f7eb2Smrg }
254*627f7eb2Smrg
255*627f7eb2Smrg return arrayOp((BinExp *)e, sc);
256*627f7eb2Smrg }
257*627f7eb2Smrg
258*627f7eb2Smrg /******************************************
259*627f7eb2Smrg * Construct the identifier for the array operation function,
260*627f7eb2Smrg * and build the argument list to pass to it.
261*627f7eb2Smrg */
262*627f7eb2Smrg
buildArrayIdent(Expression * e,OutBuffer * buf,Expressions * arguments)263*627f7eb2Smrg void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments)
264*627f7eb2Smrg {
265*627f7eb2Smrg class BuildArrayIdentVisitor : public Visitor
266*627f7eb2Smrg {
267*627f7eb2Smrg OutBuffer *buf;
268*627f7eb2Smrg Expressions *arguments;
269*627f7eb2Smrg public:
270*627f7eb2Smrg BuildArrayIdentVisitor(OutBuffer *buf, Expressions *arguments)
271*627f7eb2Smrg : buf(buf), arguments(arguments)
272*627f7eb2Smrg {
273*627f7eb2Smrg }
274*627f7eb2Smrg
275*627f7eb2Smrg void visit(Expression *e)
276*627f7eb2Smrg {
277*627f7eb2Smrg buf->writestring("Exp");
278*627f7eb2Smrg arguments->shift(e);
279*627f7eb2Smrg }
280*627f7eb2Smrg
281*627f7eb2Smrg void visit(CastExp *e)
282*627f7eb2Smrg {
283*627f7eb2Smrg Type *tb = e->type->toBasetype();
284*627f7eb2Smrg if (tb->ty == Tarray || tb->ty == Tsarray)
285*627f7eb2Smrg {
286*627f7eb2Smrg e->e1->accept(this);
287*627f7eb2Smrg }
288*627f7eb2Smrg else
289*627f7eb2Smrg visit((Expression *)e);
290*627f7eb2Smrg }
291*627f7eb2Smrg
292*627f7eb2Smrg void visit(ArrayLiteralExp *e)
293*627f7eb2Smrg {
294*627f7eb2Smrg buf->writestring("Slice");
295*627f7eb2Smrg arguments->shift(e);
296*627f7eb2Smrg }
297*627f7eb2Smrg
298*627f7eb2Smrg void visit(SliceExp *e)
299*627f7eb2Smrg {
300*627f7eb2Smrg buf->writestring("Slice");
301*627f7eb2Smrg arguments->shift(e);
302*627f7eb2Smrg }
303*627f7eb2Smrg
304*627f7eb2Smrg void visit(AssignExp *e)
305*627f7eb2Smrg {
306*627f7eb2Smrg /* Evaluate assign expressions right to left
307*627f7eb2Smrg */
308*627f7eb2Smrg e->e2->accept(this);
309*627f7eb2Smrg e->e1->accept(this);
310*627f7eb2Smrg buf->writestring("Assign");
311*627f7eb2Smrg }
312*627f7eb2Smrg
313*627f7eb2Smrg void visit(BinAssignExp *e)
314*627f7eb2Smrg {
315*627f7eb2Smrg /* Evaluate assign expressions right to left
316*627f7eb2Smrg */
317*627f7eb2Smrg e->e2->accept(this);
318*627f7eb2Smrg e->e1->accept(this);
319*627f7eb2Smrg const char *s;
320*627f7eb2Smrg switch(e->op)
321*627f7eb2Smrg {
322*627f7eb2Smrg case TOKaddass: s = "Addass"; break;
323*627f7eb2Smrg case TOKminass: s = "Minass"; break;
324*627f7eb2Smrg case TOKmulass: s = "Mulass"; break;
325*627f7eb2Smrg case TOKdivass: s = "Divass"; break;
326*627f7eb2Smrg case TOKmodass: s = "Modass"; break;
327*627f7eb2Smrg case TOKxorass: s = "Xorass"; break;
328*627f7eb2Smrg case TOKandass: s = "Andass"; break;
329*627f7eb2Smrg case TOKorass: s = "Orass"; break;
330*627f7eb2Smrg case TOKpowass: s = "Powass"; break;
331*627f7eb2Smrg default: assert(0);
332*627f7eb2Smrg }
333*627f7eb2Smrg buf->writestring(s);
334*627f7eb2Smrg }
335*627f7eb2Smrg
336*627f7eb2Smrg void visit(NegExp *e)
337*627f7eb2Smrg {
338*627f7eb2Smrg e->e1->accept(this);
339*627f7eb2Smrg buf->writestring("Neg");
340*627f7eb2Smrg }
341*627f7eb2Smrg
342*627f7eb2Smrg void visit(ComExp *e)
343*627f7eb2Smrg {
344*627f7eb2Smrg e->e1->accept(this);
345*627f7eb2Smrg buf->writestring("Com");
346*627f7eb2Smrg }
347*627f7eb2Smrg
348*627f7eb2Smrg void visit(BinExp *e)
349*627f7eb2Smrg {
350*627f7eb2Smrg /* Evaluate assign expressions left to right
351*627f7eb2Smrg */
352*627f7eb2Smrg const char *s = NULL;
353*627f7eb2Smrg switch(e->op)
354*627f7eb2Smrg {
355*627f7eb2Smrg case TOKadd: s = "Add"; break;
356*627f7eb2Smrg case TOKmin: s = "Min"; break;
357*627f7eb2Smrg case TOKmul: s = "Mul"; break;
358*627f7eb2Smrg case TOKdiv: s = "Div"; break;
359*627f7eb2Smrg case TOKmod: s = "Mod"; break;
360*627f7eb2Smrg case TOKxor: s = "Xor"; break;
361*627f7eb2Smrg case TOKand: s = "And"; break;
362*627f7eb2Smrg case TOKor: s = "Or"; break;
363*627f7eb2Smrg case TOKpow: s = "Pow"; break;
364*627f7eb2Smrg default: break;
365*627f7eb2Smrg }
366*627f7eb2Smrg if (s)
367*627f7eb2Smrg {
368*627f7eb2Smrg Type *tb = e->type->toBasetype();
369*627f7eb2Smrg Type *t1 = e->e1->type->toBasetype();
370*627f7eb2Smrg Type *t2 = e->e2->type->toBasetype();
371*627f7eb2Smrg e->e1->accept(this);
372*627f7eb2Smrg if (t1->ty == Tarray &&
373*627f7eb2Smrg ((t2->ty == Tarray && !t1->equivalent(tb)) ||
374*627f7eb2Smrg (t2->ty != Tarray && !t1->nextOf()->equivalent(e->e2->type))))
375*627f7eb2Smrg {
376*627f7eb2Smrg // Bugzilla 12780: if A is narrower than B
377*627f7eb2Smrg // A[] op B[]
378*627f7eb2Smrg // A[] op B
379*627f7eb2Smrg buf->writestring("Of");
380*627f7eb2Smrg buf->writestring(t1->nextOf()->mutableOf()->deco);
381*627f7eb2Smrg }
382*627f7eb2Smrg e->e2->accept(this);
383*627f7eb2Smrg if (t2->ty == Tarray &&
384*627f7eb2Smrg ((t1->ty == Tarray && !t2->equivalent(tb)) ||
385*627f7eb2Smrg (t1->ty != Tarray && !t2->nextOf()->equivalent(e->e1->type))))
386*627f7eb2Smrg {
387*627f7eb2Smrg // Bugzilla 12780: if B is narrower than A:
388*627f7eb2Smrg // A[] op B[]
389*627f7eb2Smrg // A op B[]
390*627f7eb2Smrg buf->writestring("Of");
391*627f7eb2Smrg buf->writestring(t2->nextOf()->mutableOf()->deco);
392*627f7eb2Smrg }
393*627f7eb2Smrg buf->writestring(s);
394*627f7eb2Smrg }
395*627f7eb2Smrg else
396*627f7eb2Smrg visit((Expression *)e);
397*627f7eb2Smrg }
398*627f7eb2Smrg };
399*627f7eb2Smrg
400*627f7eb2Smrg BuildArrayIdentVisitor v(buf, arguments);
401*627f7eb2Smrg e->accept(&v);
402*627f7eb2Smrg }
403*627f7eb2Smrg
404*627f7eb2Smrg /******************************************
405*627f7eb2Smrg * Construct the inner loop for the array operation function,
406*627f7eb2Smrg * and build the parameter list.
407*627f7eb2Smrg */
408*627f7eb2Smrg
buildArrayLoop(Expression * e,Parameters * fparams)409*627f7eb2Smrg Expression *buildArrayLoop(Expression *e, Parameters *fparams)
410*627f7eb2Smrg {
411*627f7eb2Smrg class BuildArrayLoopVisitor : public Visitor
412*627f7eb2Smrg {
413*627f7eb2Smrg Parameters *fparams;
414*627f7eb2Smrg Expression *result;
415*627f7eb2Smrg
416*627f7eb2Smrg public:
417*627f7eb2Smrg BuildArrayLoopVisitor(Parameters *fparams)
418*627f7eb2Smrg : fparams(fparams), result(NULL)
419*627f7eb2Smrg {
420*627f7eb2Smrg }
421*627f7eb2Smrg
422*627f7eb2Smrg void visit(Expression *e)
423*627f7eb2Smrg {
424*627f7eb2Smrg Identifier *id = Identifier::generateId("c", fparams->dim);
425*627f7eb2Smrg Parameter *param = new Parameter(0, e->type, id, NULL);
426*627f7eb2Smrg fparams->shift(param);
427*627f7eb2Smrg result = new IdentifierExp(Loc(), id);
428*627f7eb2Smrg }
429*627f7eb2Smrg
430*627f7eb2Smrg void visit(CastExp *e)
431*627f7eb2Smrg {
432*627f7eb2Smrg Type *tb = e->type->toBasetype();
433*627f7eb2Smrg if (tb->ty == Tarray || tb->ty == Tsarray)
434*627f7eb2Smrg {
435*627f7eb2Smrg e->e1->accept(this);
436*627f7eb2Smrg }
437*627f7eb2Smrg else
438*627f7eb2Smrg visit((Expression *)e);
439*627f7eb2Smrg }
440*627f7eb2Smrg
441*627f7eb2Smrg void visit(ArrayLiteralExp *e)
442*627f7eb2Smrg {
443*627f7eb2Smrg Identifier *id = Identifier::generateId("p", fparams->dim);
444*627f7eb2Smrg Parameter *param = new Parameter(STCconst, e->type, id, NULL);
445*627f7eb2Smrg fparams->shift(param);
446*627f7eb2Smrg Expression *ie = new IdentifierExp(Loc(), id);
447*627f7eb2Smrg Expression *index = new IdentifierExp(Loc(), Id::p);
448*627f7eb2Smrg result = new ArrayExp(Loc(), ie, index);
449*627f7eb2Smrg }
450*627f7eb2Smrg
451*627f7eb2Smrg void visit(SliceExp *e)
452*627f7eb2Smrg {
453*627f7eb2Smrg Identifier *id = Identifier::generateId("p", fparams->dim);
454*627f7eb2Smrg Parameter *param = new Parameter(STCconst, e->type, id, NULL);
455*627f7eb2Smrg fparams->shift(param);
456*627f7eb2Smrg Expression *ie = new IdentifierExp(Loc(), id);
457*627f7eb2Smrg Expression *index = new IdentifierExp(Loc(), Id::p);
458*627f7eb2Smrg result = new ArrayExp(Loc(), ie, index);
459*627f7eb2Smrg }
460*627f7eb2Smrg
461*627f7eb2Smrg void visit(AssignExp *e)
462*627f7eb2Smrg {
463*627f7eb2Smrg /* Evaluate assign expressions right to left
464*627f7eb2Smrg */
465*627f7eb2Smrg Expression *ex2 = buildArrayLoop(e->e2);
466*627f7eb2Smrg /* Need the cast because:
467*627f7eb2Smrg * b = c + p[i];
468*627f7eb2Smrg * where b is a byte fails because (c + p[i]) is an int
469*627f7eb2Smrg * which cannot be implicitly cast to byte.
470*627f7eb2Smrg */
471*627f7eb2Smrg ex2 = new CastExp(Loc(), ex2, e->e1->type->nextOf());
472*627f7eb2Smrg Expression *ex1 = buildArrayLoop(e->e1);
473*627f7eb2Smrg Parameter *param = (*fparams)[0];
474*627f7eb2Smrg param->storageClass = 0;
475*627f7eb2Smrg result = new AssignExp(Loc(), ex1, ex2);
476*627f7eb2Smrg }
477*627f7eb2Smrg
478*627f7eb2Smrg void visit(BinAssignExp *e)
479*627f7eb2Smrg {
480*627f7eb2Smrg /* Evaluate assign expressions right to left
481*627f7eb2Smrg */
482*627f7eb2Smrg Expression *ex2 = buildArrayLoop(e->e2);
483*627f7eb2Smrg Expression *ex1 = buildArrayLoop(e->e1);
484*627f7eb2Smrg Parameter *param = (*fparams)[0];
485*627f7eb2Smrg param->storageClass = 0;
486*627f7eb2Smrg switch(e->op)
487*627f7eb2Smrg {
488*627f7eb2Smrg case TOKaddass: result = new AddAssignExp(e->loc, ex1, ex2); return;
489*627f7eb2Smrg case TOKminass: result = new MinAssignExp(e->loc, ex1, ex2); return;
490*627f7eb2Smrg case TOKmulass: result = new MulAssignExp(e->loc, ex1, ex2); return;
491*627f7eb2Smrg case TOKdivass: result = new DivAssignExp(e->loc, ex1, ex2); return;
492*627f7eb2Smrg case TOKmodass: result = new ModAssignExp(e->loc, ex1, ex2); return;
493*627f7eb2Smrg case TOKxorass: result = new XorAssignExp(e->loc, ex1, ex2); return;
494*627f7eb2Smrg case TOKandass: result = new AndAssignExp(e->loc, ex1, ex2); return;
495*627f7eb2Smrg case TOKorass: result = new OrAssignExp(e->loc, ex1, ex2); return;
496*627f7eb2Smrg case TOKpowass: result = new PowAssignExp(e->loc, ex1, ex2); return;
497*627f7eb2Smrg default:
498*627f7eb2Smrg assert(0);
499*627f7eb2Smrg }
500*627f7eb2Smrg }
501*627f7eb2Smrg
502*627f7eb2Smrg void visit(NegExp *e)
503*627f7eb2Smrg {
504*627f7eb2Smrg Expression *ex1 = buildArrayLoop(e->e1);
505*627f7eb2Smrg result = new NegExp(Loc(), ex1);
506*627f7eb2Smrg }
507*627f7eb2Smrg
508*627f7eb2Smrg void visit(ComExp *e)
509*627f7eb2Smrg {
510*627f7eb2Smrg Expression *ex1 = buildArrayLoop(e->e1);
511*627f7eb2Smrg result = new ComExp(Loc(), ex1);
512*627f7eb2Smrg }
513*627f7eb2Smrg
514*627f7eb2Smrg void visit(BinExp *e)
515*627f7eb2Smrg {
516*627f7eb2Smrg if (isBinArrayOp(e->op))
517*627f7eb2Smrg {
518*627f7eb2Smrg /* Evaluate assign expressions left to right
519*627f7eb2Smrg */
520*627f7eb2Smrg BinExp *be = (BinExp *)e->copy();
521*627f7eb2Smrg be->e1 = buildArrayLoop(be->e1);
522*627f7eb2Smrg be->e2 = buildArrayLoop(be->e2);
523*627f7eb2Smrg be->type = NULL;
524*627f7eb2Smrg result = be;
525*627f7eb2Smrg return;
526*627f7eb2Smrg }
527*627f7eb2Smrg else
528*627f7eb2Smrg {
529*627f7eb2Smrg visit((Expression *)e);
530*627f7eb2Smrg return;
531*627f7eb2Smrg }
532*627f7eb2Smrg }
533*627f7eb2Smrg
534*627f7eb2Smrg Expression *buildArrayLoop(Expression *e)
535*627f7eb2Smrg {
536*627f7eb2Smrg e->accept(this);
537*627f7eb2Smrg return result;
538*627f7eb2Smrg }
539*627f7eb2Smrg };
540*627f7eb2Smrg
541*627f7eb2Smrg BuildArrayLoopVisitor v(fparams);
542*627f7eb2Smrg return v.buildArrayLoop(e);
543*627f7eb2Smrg }
544*627f7eb2Smrg
545*627f7eb2Smrg /***********************************************
546*627f7eb2Smrg * Test if expression is a unary array op.
547*627f7eb2Smrg */
548*627f7eb2Smrg
isUnaArrayOp(TOK op)549*627f7eb2Smrg bool isUnaArrayOp(TOK op)
550*627f7eb2Smrg {
551*627f7eb2Smrg switch (op)
552*627f7eb2Smrg {
553*627f7eb2Smrg case TOKneg:
554*627f7eb2Smrg case TOKtilde:
555*627f7eb2Smrg return true;
556*627f7eb2Smrg default:
557*627f7eb2Smrg break;
558*627f7eb2Smrg }
559*627f7eb2Smrg return false;
560*627f7eb2Smrg }
561*627f7eb2Smrg
562*627f7eb2Smrg /***********************************************
563*627f7eb2Smrg * Test if expression is a binary array op.
564*627f7eb2Smrg */
565*627f7eb2Smrg
isBinArrayOp(TOK op)566*627f7eb2Smrg bool isBinArrayOp(TOK op)
567*627f7eb2Smrg {
568*627f7eb2Smrg switch (op)
569*627f7eb2Smrg {
570*627f7eb2Smrg case TOKadd:
571*627f7eb2Smrg case TOKmin:
572*627f7eb2Smrg case TOKmul:
573*627f7eb2Smrg case TOKdiv:
574*627f7eb2Smrg case TOKmod:
575*627f7eb2Smrg case TOKxor:
576*627f7eb2Smrg case TOKand:
577*627f7eb2Smrg case TOKor:
578*627f7eb2Smrg case TOKpow:
579*627f7eb2Smrg return true;
580*627f7eb2Smrg default:
581*627f7eb2Smrg break;
582*627f7eb2Smrg }
583*627f7eb2Smrg return false;
584*627f7eb2Smrg }
585*627f7eb2Smrg
586*627f7eb2Smrg /***********************************************
587*627f7eb2Smrg * Test if expression is a binary assignment array op.
588*627f7eb2Smrg */
589*627f7eb2Smrg
isBinAssignArrayOp(TOK op)590*627f7eb2Smrg bool isBinAssignArrayOp(TOK op)
591*627f7eb2Smrg {
592*627f7eb2Smrg switch (op)
593*627f7eb2Smrg {
594*627f7eb2Smrg case TOKaddass:
595*627f7eb2Smrg case TOKminass:
596*627f7eb2Smrg case TOKmulass:
597*627f7eb2Smrg case TOKdivass:
598*627f7eb2Smrg case TOKmodass:
599*627f7eb2Smrg case TOKxorass:
600*627f7eb2Smrg case TOKandass:
601*627f7eb2Smrg case TOKorass:
602*627f7eb2Smrg case TOKpowass:
603*627f7eb2Smrg return true;
604*627f7eb2Smrg default:
605*627f7eb2Smrg break;
606*627f7eb2Smrg }
607*627f7eb2Smrg return false;
608*627f7eb2Smrg }
609*627f7eb2Smrg
610*627f7eb2Smrg /***********************************************
611*627f7eb2Smrg * Test if operand is a valid array op operand.
612*627f7eb2Smrg */
613*627f7eb2Smrg
isArrayOpOperand(Expression * e)614*627f7eb2Smrg bool isArrayOpOperand(Expression *e)
615*627f7eb2Smrg {
616*627f7eb2Smrg //printf("Expression::isArrayOpOperand() %s\n", e->toChars());
617*627f7eb2Smrg if (e->op == TOKslice)
618*627f7eb2Smrg return true;
619*627f7eb2Smrg if (e->op == TOKarrayliteral)
620*627f7eb2Smrg {
621*627f7eb2Smrg Type *t = e->type->toBasetype();
622*627f7eb2Smrg while (t->ty == Tarray || t->ty == Tsarray)
623*627f7eb2Smrg t = t->nextOf()->toBasetype();
624*627f7eb2Smrg return (t->ty != Tvoid);
625*627f7eb2Smrg }
626*627f7eb2Smrg Type *tb = e->type->toBasetype();
627*627f7eb2Smrg if (tb->ty == Tarray)
628*627f7eb2Smrg {
629*627f7eb2Smrg return (isUnaArrayOp(e->op) ||
630*627f7eb2Smrg isBinArrayOp(e->op) ||
631*627f7eb2Smrg isBinAssignArrayOp(e->op) ||
632*627f7eb2Smrg e->op == TOKassign);
633*627f7eb2Smrg }
634*627f7eb2Smrg return false;
635*627f7eb2Smrg }
636