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